Atomikos Forum

Spring integration test not transactional, but it is in WebLogic

I wrote a similar question about this in the Spring forum, but perhaps my problem is something related to Atomikos, so I'm posting this here.

I have a small app that reads a few databases, and writes a small table in one database. I have a @Service-annotated class with a @Transactional method. That method calls a method in a DAO class (which is not @Repository-annotated) which first deletes some rows from a table and then inserts rows to the same table.

This gets deployed to WebLogic. Under normal operation this app is working perfectly fine.

I tried an experiment of deliberately mucking the SQL for the "insert", and deployed this to my local box, and then executed the JMX operation that executes this service operation. After it failed I checked the database, and I confirmed that the table was intact, so it correctly rolled back the "delete" when the "insert" failed.

My problem is that my integration test (using Atomikos) that tries to simulate a similar scenario is NOT behaving transactionally. I mocked the JdbcTemplate so it performed the delete, but forced it to throw a DataAccessException on the insert. Afterwards, I checked the database, and the rows were gone, so it didn't rollback the delete as I hoped.

The following is an excerpt from the context I'm using in test to define the "catalogTransactionManager", which is what is referenced in the rest of the context.
-----------
    <!-- Construct Atomikos UserTransactionManager, needed to configure Spring -->
    <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
          init-method="init" destroy-method="close">
        <!-- when close is called, should we force transactions to terminate or not? -->
        <property name="forceShutdown">
            <value>true</value>
        </property>
    </bean>

    <!-- Also use Atomikos UserTransactionImp, needed to configure Spring -->
    <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
        <property name="transactionTimeout">
            <value>300</value>
        </property>
    </bean>

    <!-- Configure the Spring framework to use JTA transactions from Atomikos -->
    <bean id="catalogTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManager">
            <ref bean="atomikosTransactionManager" />
        </property>
        <property name="userTransaction">
            <ref bean="atomikosUserTransaction" />
        </property>
    </bean>
-----------

It probably doesn't matter, but here's my test method (with some things obfuscated):
-----------
@Test
public void testInsertFailsAfterDelete() {
    List<ErrorMessageInfo>  commonErrorMessagesBefore  =
        myService.
        getMyDAO().getCommonErrorMessages(MyService.CHANNEL_NAME);

    JdbcTemplate  template    = mock(JdbcTemplate.class);
    myService.getMyDAO().setJdbcTemplate(template);

    when(template.update(eq(MyDAO.SQL_DELETE_CHANNEL), any())).
    thenReturn(getOrigTemplate().update(MyDAO.SQL_DELETE_CHANNEL, MyService.CHANNEL_NAME));

    DataAccessException    exception  = new DataAccessException("insert failed") {};

    when(template.update(eq(MyDAO.SQL_INSERT_ERROR_TO_CHANNEL), anyString(), anyString(), anyInt(), any(), anyInt())).
    thenThrow(exception);

    try {
    myService.updateCommonErrorMessages();
    fail();
    }
    catch (Exception ex) {
    assertThat(ex).isEqualTo(exception);
    }
    finally {
    restoreTemplate();
    }

    List<ErrorMessageInfo>  commonErrorMessagesAfter    =
        myService.
        getMyDAO().getCommonErrorMessages(MyService.CHANNEL_NAME);

    assertThat(commonErrorMessagesBefore).isEqualTo(commonErrorMessagesAfter);
}
--------------

What might I be missing?
David M. Karr Send private email
Friday, December 09, 2011
 
 
You mocked the template - but the template is using DataAccessUtils in the back, which participates in handling connection and transaction for the DAO.
If not, no transaction boundaries get applied (or are you using weaved classed via aspectj instead of cglib/java proxies)?

Either way - i guess your template does not participate in the spring managed transaction and thats the cause why it does fail; you can confirm this by looking at the database connection used to do your queries - should be different.

Solution would be to create a custom impl of your DAO for your test, annotate it with @Primary if using it as @Autowire dep, and implement your scenario in this custom impl, e.g. throwing an exception. Created proxy should take care of rolling back the TX. Should work fine.
Torsten Krah Send private email
Monday, January 09, 2012
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics