Search code examples
scalaplayframeworkspecs2scalikejdbc

Applying evolutions to ScalikeJDBC in-memory test DB


I'm using ScalikeJDBC with Play. I want to apply evolutions to an in-memory database for my Specs2 tests.

import org.specs2.mutable.Specification
import org.specs2.specification.BeforeAfterAll
import play.api.db.{Database, Databases}
import play.api.db.evolutions.Evolutions
import scalikejdbc.ConnectionPool.DEFAULT_NAME
import scalikejdbc.{ConnectionPool, DataSourceConnectionPool}

import scalikejdbc.{AutoSession, _}

class PaymentRepoSpec extends Specification with BeforeAfterAll {

  private var database: Option[Database] = None

  def beforeAll(): Unit = {
    database = Some(Databases.inMemory(
      name = "payment-repo",
      urlOptions = Map("MODE" -> "PostgreSQL", "DATABASE_TO_UPPER" -> "FALSE"),
      config = Map()
    ))
    database.foreach(Evolutions.applyEvolutions(_))
    database.foreach(db => ConnectionPool.add(DEFAULT_NAME, new DataSourceConnectionPool(db.dataSource)))
  }

  def afterAll(): Unit = {
    database.foreach(Evolutions.cleanupEvolutions(_))
    database.foreach(_.shutdown())
  }

  "fruitcakes" should {
    "be delicious" >> {

      import scalikejdbc._

      DB.readOnly { implicit s =>
        sql"""select id from payments"""
          .map(_.int(1)).list().apply().foreach(println)
      }
      ok
    }
  }
}

This fails, because the evolutions have not been applied.

org.h2.jdbc.JdbcSQLException: Table "payments" not found; SQL statement:
select id from payments [42102-192]

application.conf includes

modules.enabled += "scalikejdbc.PlayModule"
modules.disabled += "play.api.db.DBModule"

evolutions.default/1.sql includes

CREATE TABLE payments(
    id                  SERIAL PRIMARY KEY,
    source              CHAR(56) NOT NULL,
    destination         CHAR(56) NOT NULL,
    code                VARCHAR(12) NOT NULL,
    issuer              CHAR(56),
    units               NUMERIC NOT NULL,
    received            TIMESTAMP NOT NULL,
    scheduled           TIMESTAMP NOT NULL,
    submitted           TIMESTAMP,
    status              VARCHAR(9) NOT NULL CHECK (status IN ('pending', 'submitted', 'failed', 'succeeded')),
    op_result           VARCHAR(64)
);

(and this works when running the app)

build.sbt includes

libraryDependencies ++= Seq(
  guice, evolutions, jdbc, specs2 % Test,
  "io.github.synesso" %% "scala-stellar-sdk" % "0.5.1",
  "com.nrinaudo" %% "kantan.csv-generic" % "0.4.0",
  "com.h2database" % "h2" % "1.4.192",
  "org.postgresql" % "postgresql" % "42.2.5",
  "org.scalikejdbc" %% "scalikejdbc" % "3.3.0",
  "org.scalikejdbc" %% "scalikejdbc-config" % "3.3.0",
  "org.scalikejdbc" %% "scalikejdbc-play-initializer" % "2.6.0-scalikejdbc-3.3",
  "org.webjars.npm" % "bulma" % "0.7.2",
  "org.webjars" % "font-awesome" % "5.6.3",
  "org.specs2" %% "specs2-scalacheck" % "4.3.6" % Test
)

How can I get the test to run the evolutions against my ScalikeJDBC DB?


Solution

  • The parameter name in Databases.inMemory must match the folder under evolutions.

    For example, if the evolutions are in evolutions/default/*.sql, then you must call Databases.inMemory(name="default", db).