Package org.zanata

Source Code of org.zanata.ZanataDbunitJpaTest$DataSetOperation

package org.zanata;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;

import lombok.extern.slf4j.Slf4j;

import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.DatabaseConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ReplacementDataSet;
import org.dbunit.dataset.datatype.DataType;
import org.dbunit.dataset.datatype.DataTypeException;
import org.dbunit.dataset.datatype.DefaultDataTypeFactory;
import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
import org.dbunit.operation.DatabaseOperation;
import org.hibernate.internal.SessionImpl;
import org.junit.After;
import org.junit.Before;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Optional;
import org.testng.annotations.Parameters;

/**
* Adapted from org.jboss.seam.mock.DBUnitSeamTest
*
* @see org.jboss.seam.mock.DBUnitSeamTest
* @see org.jboss.seam.mock.DBJUnitSeamTest
*/
@Slf4j
public abstract class ZanataDbunitJpaTest extends ZanataJpaTest {

    protected String binaryDir;
    protected boolean replaceNull = true;
    protected List<DataSetOperation> beforeTestOperations =
            new ArrayList<DataSetOperation>();
    protected List<DataSetOperation> afterTestOperations =
            new ArrayList<DataSetOperation>();

    private boolean prepared = false;

    @BeforeClass
    @Parameters("binaryDir")
    public void setBinaryDir(@Optional String binaryDir) {
        if (binaryDir == null)
            return;
        this.binaryDir = binaryDir;
    }

    protected String getBinaryDir() {
        return binaryDir;
    }

    @BeforeClass
    @Parameters("replaceNull")
    public void setReplaceNull(@Optional Boolean replaceNull) {
        if (replaceNull == null)
            return;
        this.replaceNull = replaceNull;
    }

    protected Boolean isReplaceNull() {
        return replaceNull;
    }

    @BeforeMethod
    @Before
    protected void prepareDataBeforeTest() {
        // This is not pretty but we unfortunately can not have dependencies
        // between @BeforeClass methods.
        // This was a basic design mistake and we can't change it now because we
        // need to be backwards
        // compatible. We can only "prepare" the datasets once all @BeforeClass
        // have been executed.
        if (!prepared) {
            prepareDBUnitOperations();
            for (DataSetOperation beforeTestOperation : beforeTestOperations) {
                beforeTestOperation.prepare(this);
            }
            for (DataSetOperation afterTestOperation : afterTestOperations) {
                afterTestOperation.prepare(this);
            }
            prepared = true;
        }

        executeOperations(beforeTestOperations);
        clearCache();
    }

    @AfterMethod
    @After
    public void cleanDataAfterTest() {
        executeOperations(afterTestOperations);
        clearCache();
    }

    private void clearCache() {
        /*
         * Session session = getSession();
         * session.getSessionFactory().getCache().evictEntityRegions();
         * session.getSessionFactory().getCache().evictCollectionRegions();
         */
    }

    protected void executeOperations(List<DataSetOperation> list) {
        IDatabaseConnection con = null;
        con = getConnection();
        disableReferentialIntegrity(con);
        for (DataSetOperation op : list) {
            prepareExecution(con, op);
            op.execute(con);
            afterExecution(con, op);
        }
        enableReferentialIntegrity(con);
    }

    protected static class DataSetOperation {

        String dataSetLocation;
        ReplacementDataSet dataSet;
        DatabaseOperation operation;

        protected DataSetOperation() {
            // Support subclassing
        }

        /**
         * Defaults to <tt>DatabaseOperation.CLEAN_INSERT</tt>
         *
         * @param dataSetLocation
         *            location of DBUnit dataset
         */
        public DataSetOperation(String dataSetLocation) {
            this(dataSetLocation, DatabaseOperation.CLEAN_INSERT);
        }

        /**
         * Defaults to <tt>DatabaseOperation.CLEAN_INSERT</tt>
         *
         * @param dataSetLocation
         *            location of DBUnit dataset
         * @param dtdLocation
         *            optional (can be null) location of XML file DTD on
         *            classpath
         */
        public DataSetOperation(String dataSetLocation, String dtdLocation) {
            this(dataSetLocation, dtdLocation, DatabaseOperation.CLEAN_INSERT);
        }

        /**
         * @param dataSetLocation
         *            location of DBUnit dataset
         * @param operation
         *            operation to execute
         */
        public DataSetOperation(String dataSetLocation,
                DatabaseOperation operation) {
            this(dataSetLocation, null, operation);
        }

        public DataSetOperation(String dataSetLocation, String dtdLocation,
                DatabaseOperation operation) {
            if (dataSetLocation == null) {
                this.operation = operation;
                return;
            }

            // Load the base dataset file
            InputStream input =
                    Thread.currentThread().getContextClassLoader()
                            .getResourceAsStream(dataSetLocation);
            try {
                FlatXmlDataSetBuilder dataSetBuilder =
                        new FlatXmlDataSetBuilder();
                dataSetBuilder.setColumnSensing(true);

                InputStream dtdInput = null;
                if (dtdLocation != null) {
                    dtdInput =
                            Thread.currentThread().getContextClassLoader()
                                    .getResourceAsStream(dtdLocation);
                }
                if (dtdInput == null) {
                    this.dataSet =
                            new ReplacementDataSet(dataSetBuilder.build(input));
                } else {
                    dataSetBuilder.setMetaDataSetFromDtd(dtdInput);
                    this.dataSet =
                            new ReplacementDataSet(dataSetBuilder.build(input));
                }
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
            this.operation = operation;
            this.dataSetLocation = dataSetLocation;
        }

        public IDataSet getDataSet() {
            return dataSet;
        }

        public DatabaseOperation getOperation() {
            return operation;
        }

        public void prepare(ZanataDbunitJpaTest test) {
            if (dataSet == null)
                return;

            if (test.isReplaceNull()) {
                dataSet.addReplacementObject("[NULL]", null);
            }
            if (test.getBinaryDir() != null) {
                dataSet.addReplacementSubstring("[BINARY_DIR]", test
                        .getBinaryDirFullpath().toString());
            }
        }

        public void execute(IDatabaseConnection connection) {
            if (dataSet == null || operation == null)
                return;
            try {
                this.operation.execute(connection, dataSet);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }

        @Override
        public String toString() {
            return getClass().getName() + " with dataset location: "
                    + dataSetLocation;
        }
    }

    /**
     * Override this method if you want to provide your own DBUnit
     * <tt>IDatabaseConnection</tt> instance.
     * <p/>
     * If you do not override this, default behavior is to use the * configured
     * datasource name and to obtain a connection with a JNDI lookup.
     *
     * @return a DBUnit database connection (wrapped)
     */
    // TODO This is hibernate specific
    protected IDatabaseConnection getConnection() {
        try {
            return new DatabaseConnection(
                    ((SessionImpl) getSession()).connection());
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * Execute whatever statement is necessary to either defer or disable
     * foreign key constraint checking on the given database connection, which
     * is used by DBUnit to import datasets.
     *
     * @param con
     *            A DBUnit connection wrapper, which is used afterwards for
     *            dataset operations
     */
    protected void disableReferentialIntegrity(IDatabaseConnection con) {
        try {
            con.getConnection()
                    .prepareStatement("set referential_integrity FALSE")
                    .execute(); // HSQL
                                // DB
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * Execute whatever statement is necessary to enable integrity constraint
     * checks after dataset operations.
     *
     * @param con
     *            A DBUnit connection wrapper, before it is used by the
     *            application again
     */
    protected void enableReferentialIntegrity(IDatabaseConnection con) {
        try {
            con.getConnection()
                    .prepareStatement("set referential_integrity TRUE")
                    .execute(); // HSQL
                                // DB
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /**
     * Override this method if you require DBUnit configuration features or
     * additional properties.
     * <p/>
     * Called after a connection has been obtaind and before the connection is
     * used. Can be a NOOP method if no additional settings are necessary for
     * your DBUnit/DBMS setup.
     *
     * @param config
     *            A DBUnit <tt>DatabaseConfig</tt> object for setting properties
     *            and features
     */
    protected void editConfig(DatabaseConfig config) {
        // DBUnit/HSQL bugfix
        // http://www.carbonfive.com/community/archives/2005/07/dbunit_hsql_and.html
        config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY,
                new DefaultDataTypeFactory() {
                    @Override
                    public DataType createDataType(int sqlType,
                            String sqlTypeName) throws DataTypeException {
                        if (sqlType == Types.BOOLEAN) {
                            return DataType.BOOLEAN;
                        }
                        return super.createDataType(sqlType, sqlTypeName);
                    }
                });
    }

    /**
     * Callback for each operation before DBUnit executes the operation, useful
     * if extra preparation of data/tables is necessary, e.g. additional SQL
     * commands on a per-operation (per table?) granularity on the given
     * database connection.
     *
     * @param con
     *            A DBUnit connection wrapper
     * @param operation
     *            The operation to be executed, call <tt>getDataSet()</tt> to
     *            access the data.
     */
    protected void prepareExecution(IDatabaseConnection con,
            DataSetOperation operation) {
    }

    /**
     * Callback for each operation, useful if extra preparation of data/tables
     * is necessary.
     *
     * @param con
     *            A DBUnit connection wrapper
     * @param operation
     *            The operation that was executed, call <tt>getDataSet()</tt> to
     *            access the data.
     */
    protected void afterExecution(IDatabaseConnection con,
            DataSetOperation operation) {
    }

    /**
     * Resolves the binary dir location with the help of the classloader, we
     * need the absolute full path of that directory.
     *
     * @return URL full absolute path of the binary directory
     */
    protected URL getBinaryDirFullpath() {
        if (getBinaryDir() == null) {
            throw new RuntimeException(
                    "Please set binaryDir TestNG property to location of binary test files");
        }
        return getResourceURL(getBinaryDir());
    }

    protected URL getResourceURL(String resource) {
        URL url =
                Thread.currentThread().getContextClassLoader()
                        .getResource(resource);
        if (url == null) {
            throw new RuntimeException(
                    "Could not find resource with classloader: " + resource);
        }
        return url;
    }

    /**
     * Load a file and return it as a <tt>byte[]</tt>. Useful for comparison
     * operations in an actual unit test, e.g. to compare an imported database
     * record against a known file state.
     *
     * @param filename
     *            the path of the file on the classpath, relative to configured
     *            <tt>binaryDir</tt> base path
     * @return the file content as bytes
     * @throws Exception
     *             when the file could not be found or read
     */
    protected byte[] getBinaryFile(String filename) throws Exception {
        if (getBinaryDir() == null) {
            throw new RuntimeException(
                    "Please set binaryDir TestNG property to location of binary test files");
        }
        File file =
                new File(getResourceURL(getBinaryDir() + "/" + filename)
                        .toURI());
        InputStream is = new FileInputStream(file);
        try {

            // Get the size of the file
            long length = file.length();

            if (length > Integer.MAX_VALUE) {
                // File is too large
            }

            // Create the byte array to hold the data
            byte[] bytes = new byte[(int) length];

            // Read in the bytes
            int offset = 0;
            int numRead;
            while (offset < bytes.length
                    && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
                offset += numRead;
            }
            // Ensure all the bytes have been read in
            if (offset < bytes.length) {
                throw new IOException("Could not completely read file "
                        + file.getName());
            }
            return bytes;
        } finally {
            is.close();
        }
    }

    /**
     * Implement this in a subclass.
     * <p/>
     * Use it to stack DBUnit <tt>DataSetOperation</tt>'s with the
     * <tt>beforeTestOperations</tt> and <tt>afterTestOperations</tt> lists.
     */
    protected abstract void prepareDBUnitOperations();

}
TOP

Related Classes of org.zanata.ZanataDbunitJpaTest$DataSetOperation

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.