rollbacks not working if Spring starts them even if runInTransaction=false

I’m trying to load data for integration tests using Liquibase, but have the transaction rollback so I can use different data in other tests.

So, I have a lot of INSERTs that I wanna do inside a Spring-driven JUnit test.  My changesets look like:
  1.     

    changeSet

    runInTransaction = “false” author = “me (generated)”

    =

    “1413580824558-29” >

  2.         

    insert

    tableName = “some_table” >

  3.             

    column

    name

    “id”

    valueNumeric

    “10”

    />

  4.          

       

    < column name = “created” valueDate = “2014-10-17 10:25:55.0”

    />

  5.             

    column

    name = “modified” valueDate = “2014-10-17 10:25:55.0”

    />

  6.         

    insert

    >

My Spring-driven JUnit test looks like:

  1. @RunWith (SpringJUnit4ClassRunner. class )

  2. @ContextConfiguration (classes= {PersistenceJPAConfig.

    class

    })

  3. @Transactional

    ()

  4. @TestExecutionListeners ({

  5.      DependencyInjectionTestExecutionListener. class ,

  6.      TransactionalTestExecutionListener. class

  7.      })

  8. @TransactionConfiguration (defaultRollback= true )

  9. public

    class DatabaseBasedIT {

I have a

method that loads a changelog via the Spring-bean:

  1.     

    protected

    void loadLiquibaseChangelog(String

    changelogFilename )

    throws LiquibaseException {

  2.         

    SpringLiquibase springLiquibase =

    new SpringLiquibase();

  3.         

    springLiquibase .setDataSource( ds );

  4.         

    springLiquibase .setChangeLog(

    changelogFilename );

  5.         

    springLiquibase .setResourceLoader( resourceLoader

    );

  6.         

    springLiquibase .afterPropertiesSet();

  7.     }

Spring says it rolled back the tx:

  1. INFO 10/22/14 10:16 PM: liquibase: Successfully released change log lock

  2. Oct 22, 2014 10:16:54 PM org.springframework.test.context.transaction.TransactionContext endTransaction

  3. INFO: Rolled back transaction for test context [DefaultTestContext@14af2ab6 testClass = DatabaseBasedIT, testInstance =DatabaseBasedIT@2e5e130a, testMethod = onlyLoadsChangeLogFromLiquibase@DatabaseBasedIT, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@3f70f50e testClass = DatabaseBasedIT, locations = ‘{}’, classes = ‘{class PersistenceJPAConfig}’, contextInitializerClasses = ‘[]’, activeProfiles = ‘{}’, propertySourceLocations = ‘{}’, propertySourceProperties = ‘{}’, contextLoader = ‘org.springframework.test.context.support.DelegatingSmartContextLoader’, parent = [null]]].

But the data doesn't actually get rolled back because the data is still left over after the tests are done.  (If I manually INSERT the data using the DataSource that Spring gives me, that gets rolled back properly.

Looking at the code for liquibase.changelog.

ChangeSet and setting some breakpoints, I can see that autocommit is set to true.  Could this be the reason that the liquibase data isn’t rolled back?

P.S. I can create a small sample

project if need be, but I’m hoping it’s easy enough to

figure out with that. ;) 

P.S.S. I forgot to mention that I’m trying setting runInTransaction to false because it doesn’t work with the default either.

@nvoxland: Sorry, that doesn’t seem to fix it. :frowning:  (Although there’s a chance my environment is messed up.)

Also, I’m not sure if runInTransaction is supposed to be “true” or “false” in the case of transactions managed outside of Liquibase (i.e., my case).

Either way, I tried with both and neither seems to work.  By “work,” I mean rollback the data.

If you point me to the place where you like to keep your unit / integration tests, I can probably make one to expose this behavior.

I think the autocommit setting is the problem. I just put in a fix for 3.3 that correctly handles the autocommit. That may be affecting the runInTransaction as well. 

Would you be able to test with the build from https://liquibase.jira.com/builds/browse/CORE-LB-29 when it finishes and let me know if it resolves your problem?

Nathan

Sorry, I didn’t read your original question well enough to really understand what you are doing. 

The problem you are running into is that after each changeSet, liquibase does a connection.commit(), and so when you call rollback after it is done, there is nothing to roll back.

Before each changeSet, liqiubase will run connection.setAutoCommit(!runInTransaction) so by having it set to false it will also automatically commit after each insert and therefore not roll back.

There is nothing built into liquibase to control the fact that it commits after each changeSet, but you should be able to easily override the behavior in your tests. 

SpringLiquibase has a createDatabase(Connection c) method which creates a liquibase.database.Database instance based on the connection. It is that Database object’s commit() method that is called after the changeSet is ran so if create a subclass of SpringLiquibase that overrides createDatabase() to return a delegate pattern object that delegates all Database methods except commit() to the normal Database object and just replace commit() with a no-op.  That should keep the changeSets from committing when in your test cases and the outer connection rollback() will roll back the changes.

Just remember that some database operations like CREATE TABLE auto-commit and there is no way to avoid that besides using a different database.

Nathan

Thanks, Nathan!

Would you entertain a “do not commit” patch?  If not, that’s OK, I just won’t bother submitting one. :slight_smile:

I wouldn’t pull one into the main Liquibase repo since it I think it would be an edge case for people, but it would make a good extension. I currently have liquibase.org/extensions as a place to reference available extensions and am planning on continuing to improve that.

Nathan