What I want is to run my tests with the same databse engine, same evolutions and config as in production. My db is PostgreSQL 9.4 and I use Slick 3.0.0 to access it.
And here the problems:
- In case of parallel tests execution I have several evolutions run at once on the same db. That leads to errors.
- In case of sequential tests execution I have another error with thread pool.
Here the details.
I use evolutions to init the db for each test. For that purpose I prepared a base spec class:
class DatabaseSpecification extends PlaySpecification {
protected val defaultAppBuilder =
new GuiceApplicationBuilder()
.configure(ConfigurationLoader.loadFirst("application.test.override.conf", "application.test.conf"))
protected def afterEach(app: Application) = {
recreateDbSchema(app)
}
private def recreateDbSchema(app: Application) = {
val dbConfig = DatabaseConfigProvider.get[JdbcProfile](app)
import dbConfig.driver.api._
val recreateSchema: DBIO[Unit] = DBIO.seq(
sqlu"drop schema public cascade",
sqlu"create schema public"
)
Await.ready(dbConfig.db.run(recreateSchema), 5 seconds)
}
abstract class DatabaseContext() extends WithApplication(defaultAppBuilder.build()) {
protected val injector = implicitApp.injector
override def around[T](t: => T)(implicit evidence$2: AsResult[T]): Result = super.around {
try {
t
} finally {
afterEach(implicitApp)
}
}
}
}
where application.test.override.conf
is config file for the tests.
Also there are couple tests in an ancestor spec:
"save1 and query" in new DatabaseContext {
// create new user
val accountRepo = injector.instanceOf[SystemUserRepo]
val user = new SystemUser(id = 0, login = "admin", passwordHash = "", role = Role.Administrator)
val futureUserId = accountRepo.create(user)
// check if user id is greater then zero
val userId = await(futureUserId)(5 second)
userId must be_>(0)
}
"second one1" in new DatabaseContext {
1 mustEqual 1
}
If I run the whole spec's tests in parallel (default) then get exception Database 'default' is in an inconsistent state![An evolution has not been applied properly. Please check the problem and resolve it manually before marking it as resolved.]
@6mk338l87: Database 'default' is in an inconsistent state!
in one of the tests.
If I run it sequential class AccountRepositoryTest extends DatabaseSpecification { sequential ... }
another exeception appears
Task slick.backend.DatabaseComponent$DatabaseDef$$anon$2@2744dcae rejected from java.util.concurrent.ThreadPoolExecutor@16d0e521[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 3]
java.util.concurrent.RejectedExecutionException: Task slick.backend.DatabaseComponent$DatabaseDef$$anon$2@2744dcae rejected from java.util.concurrent.ThreadPoolExecutor@16d0e521[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 3]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
at scala.concurrent.impl.ExecutionContextImpl$$anon$1.execute(ExecutionContextImpl.scala:136)
at slick.backend.DatabaseComponent$DatabaseDef$class.runSynchronousDatabaseAction(DatabaseComponent.scala:224)
at slick.jdbc.JdbcBackend$DatabaseDef.runSynchronousDatabaseAction(JdbcBackend.scala:38)
at slick.backend.DatabaseComponent$DatabaseDef$class.runInContext(DatabaseComponent.scala:201)
at slick.jdbc.JdbcBackend$DatabaseDef.runInContext(JdbcBackend.scala:38)
at slick.backend.DatabaseComponent$DatabaseDef$class.runInternal(DatabaseComponent.scala:75)
at slick.jdbc.JdbcBackend$DatabaseDef.runInternal(JdbcBackend.scala:38)
at slick.backend.DatabaseComponent$DatabaseDef$class.run(DatabaseComponent.scala:72)
at slick.jdbc.JdbcBackend$DatabaseDef.run(JdbcBackend.scala:38)
at repository.GenericCRUD$class.create(GenericCRUD.scala:50)
at repository.GenericCRUDImpl.create(GenericCRUD.scala:70)
at unit.repositories.AccountRepositoryTest$$anonfun$3$$anon$1.delayedEndpoint$unit$repositories$AccountRepositoryTest$$anonfun$3$$anon$1$1(AccountRepositoryTest.scala:39)
at unit.repositories.AccountRepositoryTest$$anonfun$3$$anon$1$delayedInit$body.apply(AccountRepositoryTest.scala:35)
It happens on line val futureUserId = accountRepo.create(user)
. Sadly but I have no idea why the second exception throws. Btw, I prefer to run tests in parallel of course but don't know how to achive it.
Any help would be appreciated!