Version 9

    This article describes how to configure the jBPM project so that unit tests connect to a database or your choice instead of using the default H2 (in-memory) database.

     

     

     

     

    Overview of modifications

     

    The jbpm project root pom.xml  contains:

      • Properties to be used to connect to the database of choice
      • A database profile that can be used in order to inject a dependency for the jdbc driver jar for the database
      • An example profile, which has been commented out, which shows how do test without using a settings file
    1. A org.jbpm.persistence.util.PersistenceUtil class has been added to the jbpm-persistence-jpa module.
    2. The jbpm-persistence-jpa module now also has a test-jar goal: the test-jar produced contains the PersistenceUtil class mentioned above.
    3. In the modules in which persistence is used during testing, the following modifications have been made:
      • A datasource.properties file has been added to the src/test/resources directory.
      • The pom.xml of the module has been modified so that filtering has been turned on for the src/test/resources directory.
      • The persistence.xml file in src/test/resources/META-INF has been modified so that the hibernate.connection.* properties use variables.

     

    How all of these modifications fit together is explained in the following section.

    Explanation

     

    We essentially use maven to inject the values we want into the persistence configuration.

     

    Unfortunately, because XA datasource configuration is not uniform across different database vendors, there is also a utility class (org.jbpm.persistence.util.PersistenceUtil) which contains database specific XA datasource configuration and which we use to initiate and configure the XA datasource when testing.

     

    An explanation follows the diagram below:

    Untitl33ed.jpg
    A. The pom.xml and maven settings:

     

    Properties


    The jbpm project root pom (jbpm artifact) contains a number of maven.* properties: a number of these settings are empty, and those that aren't are set to the h2 defaults.

     

    However, we can create a local settings.xml file and run the following:

    mvn clean test -ssettings-db.xml -Pdatabase

     

    (The -Pdatabase is explained below)

     

    By filling a local settings.xml file with the jdbc values that we want for, for example, our local PostgreSQL database, we can then use those values later on when running our tests.

     

    Otherwise, we can also directly modify the pom.xml itself and fill the values in there.

     

    Using a profile to inject a dependency


    The -Pdatabase option in the mvn command above tells maven to use the profile that has an id of "database".

     

    In the project root pom, we have also defined a "database" profile  that uses a dependency. By setting the maven.jdbc.driver.jar property (in either the pom.xml or the settings.xml file that you use) to the path of the appropriate jdbc driver class jar, we can then ensure that the database specific driver classes are available to our tests.

     

    [Depending on demand, we could also add properties to the pom.xml so that the groupId, artifactId, and version of the driver class jar (instead of a system path) are defined and used]

    B. Filtering and the datasource.properties and persistence.xml files:

     

    In the pom.xml of the module in which the testing is done (for example, jbpm-persistence-jpa or jbpm-bam), the following has also been added to the <build> section of the module pom:

     

    <build>

    ...

      <testResources>

        <testResource>

          <directory>src/test/resources</directory>

          <filtering>true</filtering>

        </testResource>

      </testResources>

    ...

    </build>

     

    When maven runs the process-test-resources goal, it filters all files in and under the src/main/resources directory. Any properties that have been defined in the (effective) pom.xml being processed by maven, will be replaced with the values that have been assigned to them.

     

    In this case, the following two files in src/main/resources that are filtered for us:

    • datasource.properties
    • META-INF/persistence.xml

     

    In the PersistenceUtil class, we read in the datasource.properties file. The test-compile and process-test-resources goals ensure that the filtered version of this file -- where all maven variables have been replaced with their assigned values -- is placed in the same class path as the rest of the test classes and jars (target/, namely).

     

    hibernate.xml is used by Hibernate/JPA when we instantiate an EntityManager.

     

    C. Using the PersistenceUtil in unit tests:

     

    Lastly, when we write any unit tests that use persistence, instead of configuring the datasource and entityManager ourselves, we use the static methods made available to us from the PersistenceUtil class.

     

    In our test class, we can use something like the following code:

     

    import static org.jbpm.persistence.util.PersistenceUtil.*;

    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Persistence;
    ...
    import org.junit.After;
    import org.junit.Before;

    import bitronix.tm.TransactionManagerServices;
    import bitronix.tm.resource.jdbc.PoolingDataSource;

    public class MyPersistenceTest {

        private PoolingDataSource ds1;
        private EntityManagerFactory emf;
       
        @Before
        public void setUp() throws Exception {
            ds1 = setupPoolingDataSource();
            ds1.init();
           
            emf = Persistence.createEntityManagerFactory( PERSISTENCE_UNIT_NAME );
        }
       
        @After
        public void tearDown() throws Exception {
            emf.close();
            ds1.close();
        }

     

    setupPoolingDataSource() is a static method from the PersistenceUtil Class.

     

    This method does the following:

    1. It retrieves the properties stored in datasource.properties
    2. It initializes a PoolingDataSource object.
    3. Depending on the driver class that's been specified, other properties are injected into the PoolingDataSource instance.
      • Depending on the database specific PoolingDataSource implementations, different properties are necessary to initiate the XA datasoruce.

     

    Summary

     

    In order to run the unit tests on a different database, you can do one of two things:

     

    If you want to run all of the tests with a specific database, the easiest way to do this is the following:

     

    1. Download the appropriate jdbc driver class jar for your database.
    2. Fill a settings file with the appropriate values (including the path to your jdbc driver class jar)
    3. Run mvn -Pdatabase -ssettings.xml clean test !

     

    Otherwise, if you are developing or debugging unit tests and running them with a specific database, do the following:

     

    1. Ensue that the appropriate jdbc driver classes are available by doing one of the following:
      • Download the appropriate jdbc driver class jar for your database and use the path to that jar.
      • Modify the dependency in the database profile that it points to the correct jdbc driver jar.
    2. Modify the properties in the jBPM project root pom so that they contain the correct values for your database.
    3. Run mvn -Pdatabase clean test-compile
    4. Debug/run your unit tests.

     

    Appendix

     

    The following is an example of a maven settings.xml file that you could use to test on a local PostgreSQL database that contained a "jbpm5" schema (with user "jbpm5" and password "jbpm5")

     

    <?xml version="1.0" encoding="UTF-8"?>

    <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
      <profiles>
        <profile>
          <id>database</id>

          <properties>
            <maven.hibernate.dialect>org.hibernate.dialect.PostgreSQLDialect</maven.hibernate.dialect>
            <maven.datasource.classname>org.postgresql.xa.PGXADataSource</maven.datasource.classname>

            <maven.jdbc.driver.class>org.postgresql.Driver</maven.jdbc.driver.class>

            <maven.jdbc.db.name>jbpm5</maven.jdbc.db.name>
            <maven.jdbc.db.port>5432</maven.jdbc.db.port>
            <maven.jdbc.db.server>localhost</maven.jdbc.db.server>

            <maven.jdbc.driver.jar>/home/awesomeUser/workspace/jbpm5/lib/postgresql-8.4-702.jdbc3.jar</maven.jdbc.driver.jar>

            <maven.jdbc.username>jbpm5</maven.jdbc.username>
            <maven.jdbc.password>jbpm5</maven.jdbc.password>
            <maven.jdbc.url>jdbc:postgresql://localhost:5432/jbpm5</maven.jdbc.url>
          </properties>

        </profile>
      </profiles>

      <activeProfiles>
        <activeProfile>database</activeProfile>
      </activeProfiles>
    </settings>