views:

69

answers:

2

My DAO integration tests are failing because entities created during the tests are still in the database at the start of the next test. The exact same behavior is seen from both MySQL 5 and H2.

The test classes are annotated with:

@Transactional
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration( { "/testPersist-applicationContext.xml" })

The transaction bean configuration in the test application context is as follows:

<tx:annotation-driven />

<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
    <property name="transactionManager" ref="atomikosTransactionManager" />
    <property name="userTransaction" ref="atomikosUserTransaction" />
</bean>

<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
    <property name="forceShutdown" value="false" />
</bean>

<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
    <property name="transactionTimeout" value="300" />
</bean>

The entity manager is configured as follows:

<bean id="myappTestLocalEmf"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceUnitName" value="myapp" />
    <property name="persistenceUnitPostProcessors">
        <bean                class="com.myapp.core.persist.util.JtaPersistenceUnitPostProcessor">
        <property name="jtaDataSource" ref="myappPersistTestJdbcDataSource" />
        </bean>
    </property>
    <property name="jpaVendorAdapter">
        <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <property name="showSql" value="false" />
            <property name="database" value="$DS{hibernate.database}" />
            <property name="databasePlatform" value="$DS{hibernate.dialect}" />
        </bean>
    </property>
    <property name="jpaProperties">
        <props>
            <prop key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup
            </prop>
            <prop key="hibernate.format_sql">true"</prop>
            <prop key="hibernate.use_sql_comments">true</prop>
            </props>
    </property>
</bean>

<context:annotation-config />

Everything in the log files seem to be fine...I can see messages from Spring about rollback and from Atomikos about rollback as well. But frankly, the logs are so huge and so complex, I could easily be missing something...

Yet the inserted test data remains! Any clues?

+1  A: 

I think you will need to go through the logs in details. It could be that the rollbacks you are seeing are working, except that something else has executed a commit first. I also cannot see anything in your code which indicates automated rollback. And that it should occur at the end of each test. If you are depending on a timeout based rollback it could be that the second test is running before the timeout occurs, therefore it sees the data before it is rolled back.

Many options here there is :-)

Derek Clarkson
The Spring Test runner does the rollback. I can see Spring Test and Atomikos create the transaction and also execute the rollback. However, it seems like the Hibernate/JDBC data connection must not be getting synchronized properly. Just to make sure it wasn't a Spring Test, C3P0, JDBC, or Hibernate problem I switched to a RESOURCE_LOCAL persistence unit with the datasource injected directly into my entity manager and everything worked as expected. So the problem is with Atomikos and/or my post processor work-around for the lack of JNDI outside an app server.
HDave
+1  A: 

It turned out that my C3P0 JDBC data source was not XA aware and was therefore not participating in the transaction. Why I did not get an error, nor a warning in the log file, I do not know. Nonetheless, the reason you cannot use an XA aware data source is explained very nicely here. Note that the data source does not need to be XA capable...just XA aware.

Replacing the C3P0 data source with the following one solved the problem.

<bean id="myappJTANonXADataSource" class="com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean">
        <property name="uniqueResourceName" value="myappDatabase" />
        <property name="driverClassName" value="$DS{hibernate.connection.driver_class}" />
        <property name="url" value="$DS{hibernate.connection.url}" />
        <property name="user" value="$DS{hibernate.connection.username}" />
        <property name="password" value="$DS{hibernate.connection.password}" />
        <property name="maxPoolSize" value="20" />
        <property name="reapTimeout" value="300" />
</bean>
HDave