mardi 7 mars 2017

Grails, loading tests data for functional tests. org.hibernate.ObjectNotFoundException

I'm creating functional tests for a Grails (V3.2.3) application. During the tests, it runs on an h2 database. The tests make calls to the rest API. Because the application needs to support several mutually exclusive data sets I'm trying to load the data before every test and clean it up after every test. However, this is giving very inconsistent results. Sometimes it works fine other times it throws

org.hibernate.ObjectNotFoundException: No row with the given identifier exists.

But if I check the database using localhost:{port}/dbconsole the data is there. Any ideas what is going wrong and how to fix it?

configurations:

The data is loaded by creating domain objects and then calling .save(flush: true) on them. This is done in Spock's setup method.

The data is cleared by calling this in Spock's cleanup method:

static void clearAllData() {
    Session session = Holders.applicationContext.getBean(SessionFactory).currentSession
    session.createSQLQuery("SET REFERENTIAL_INTEGRITY FALSE").executeUpdate()

    getH2TruncateScript().each {
        try {
            session.createSQLQuery(it).executeUpdate()
        } catch(GenericJDBCException e) {
            //ignore CANNOT TRUNCATE xxx, as several domain classes are backed by views
        }
    }
    session.createSQLQuery("SET REFERENTIAL_INTEGRITY TRUE").executeUpdate()
    session.clear()
}

The test class is annotated with: @Integration @Rollback @Slf4j

The h2 database settings from the application.groovy are as follows:

environments {
    test {
        dataSource {
            driverClassName = 'org.h2.Driver'
            url = "jdbc:h2:mem:testDb;MVCC=TRUE;LOCK_TIMEOUT=10000;INIT=RUNSCRIPT FROM '../db/h2_init.sql'"
            username = 'sa'
            password = ''
            dbCreate = 'create-drop' //also tried 'create' and 'update'
            logSql = true
            formatSql = true
        }
    }
}

What I have tried so far:

  • Switching dbCreate setting to 'create-drop', 'create' and 'update'. create has a 50/50 success rate. create-drop and update almost always fail.
  • session.flush() after loading/cleaning the data
  • sleep after loading/cleanup
  • call session.flush() inside the application controller and/or services before retrieving data

when loading once during startup it works fine.

class BootStrap {
    def init = { servletContext ->
        if (Environment.current == Environment.TEST) {
            ..load data here           
        }
    }
}

However, this is not an option because the tests are to verify support for both new and legacy data formats. These formats are mutually exclusive.

Aucun commentaire:

Enregistrer un commentaire