diff options
Diffstat (limited to 'core-testkit/src/main/scala/xyz/driver/core/testkit/postgres')
2 files changed, 120 insertions, 0 deletions
diff --git a/core-testkit/src/main/scala/xyz/driver/core/testkit/postgres/DockerPostgresDatabase.scala b/core-testkit/src/main/scala/xyz/driver/core/testkit/postgres/DockerPostgresDatabase.scala new file mode 100644 index 0000000..41e6e0d --- /dev/null +++ b/core-testkit/src/main/scala/xyz/driver/core/testkit/postgres/DockerPostgresDatabase.scala @@ -0,0 +1,46 @@ +package xyz.driver.core.testkit +package postgres + +import xyz.driver.core.make + +trait DockerPostgresDatabase { + import com.spotify.docker.client._ + import com.spotify.docker.client.messages._ + + lazy val dockerClient: DockerClient = DefaultDockerClient.fromEnv().build() + + val postgresVersion: String = "9.6" + + def setupDockerDatabase( + username: String = "postgres", + password: String = "postgres", + database: String = "postgres", + hostPort: Int = 15432): String = { + import collection.JavaConverters._ + + dockerClient.pull(s"postgres:$postgresVersion") + + val portBindings: Map[String, List[PortBinding]] = Map("5432" -> List(PortBinding.of("0.0.0.0", hostPort))) + val portBindingsJava = portBindings.mapValues(_.asJava).asJava + val hostConfig = HostConfig.builder().portBindings(portBindingsJava).build() + val containerConfig = + ContainerConfig + .builder() + .hostConfig(hostConfig) + .image(s"postgres:$postgresVersion") + .exposedPorts("5432") + .env( + s"POSTGRES_USER=$username", + s"POSTGRES_DB=$database", + s"POSTGRES_PASSWORD=$password" + ) + .build() + + make(dockerClient.createContainer(containerConfig).id())(dockerClient.startContainer) + } + + def killDockerDatabase(containerId: String): Unit = { + dockerClient.killContainer(containerId) + dockerClient.removeContainer(containerId) + } +} diff --git a/core-testkit/src/main/scala/xyz/driver/core/testkit/postgres/DockerPostgresFixtureDatabase.scala b/core-testkit/src/main/scala/xyz/driver/core/testkit/postgres/DockerPostgresFixtureDatabase.scala new file mode 100644 index 0000000..3e00bf5 --- /dev/null +++ b/core-testkit/src/main/scala/xyz/driver/core/testkit/postgres/DockerPostgresFixtureDatabase.scala @@ -0,0 +1,74 @@ +package xyz.driver.core.testkit +package postgres + +import java.net.ServerSocket + +import org.scalatest.{BeforeAndAfterAll, Suite} +import slick.jdbc.PostgresProfile +import xyz.driver.core.using + +import scala.concurrent.Await +import scala.concurrent.duration._ + +trait DockerPostgresFixtureDatabase + extends FixtureDatabase[PostgresProfile] with DockerPostgresDatabase with BeforeAndAfterAll { + self: Suite => + private val dbName: String = sys.env.getOrElse("TEST_DB_NAME", "postgres") + private val username: String = sys.env.getOrElse("TEST_DB_USERNAME", "postgres") + private val password: String = sys.env.getOrElse("TEST_DB_PASSWORD", "postgres") + private val port: Int = sys.env.get("TEST_DB_PORT").fold(getRandomPort())(_.toInt) + + private val enabled: Boolean = !sys.env.get("DISABLE_DOCKER_TEST_DB").contains("true") + + protected val connectionTimeout: Duration = 16.seconds + + final val profile = PostgresProfile + final override val database = profile.backend.Database.forURL( + driver = "org.postgresql.Driver", + url = s"jdbc:postgresql://localhost:$port/$dbName", + user = username, + password = password) + + object driverDatabase extends xyz.driver.core.database.Database { + override val profile = self.profile + override val database = self.database + } + + private def getRandomPort(): Int = using(new ServerSocket(0))(_.getLocalPort()) + + @SuppressWarnings(Array("org.wartremover.warts.Var")) + private var dockerContainerId: Option[String] = None + + private def waitForContainer(): Unit = { + import concurrent.ExecutionContext.Implicits.global + import profile.api._ + + val expiration = System.currentTimeMillis() + connectionTimeout.toMillis + + val query = sql"SELECT 1;".as[Int] + def dbReady = Await.result( + database + .run(query) + .map(_ == Vector(1)) + .recover({ case _: org.postgresql.util.PSQLException => false }), + connectionTimeout + ) + + while (!dbReady && System.currentTimeMillis() < expiration) { + Thread.sleep(100) + } + } + + override protected def beforeAll(): Unit = { + if (enabled) { + dockerContainerId = Some(super.setupDockerDatabase(username, password, dbName, port)) + waitForContainer() + } + super.beforeAll() + } + + override protected def afterAll(): Unit = { + try super.afterAll() + finally dockerContainerId.foreach(killDockerDatabase) + } +} |