summaryrefslogtreecommitdiff
path: root/crashboxd/src/test/scala/io/crashbox/ci/DockerExecutorSpec.scala
diff options
context:
space:
mode:
Diffstat (limited to 'crashboxd/src/test/scala/io/crashbox/ci/DockerExecutorSpec.scala')
-rw-r--r--crashboxd/src/test/scala/io/crashbox/ci/DockerExecutorSpec.scala122
1 files changed, 122 insertions, 0 deletions
diff --git a/crashboxd/src/test/scala/io/crashbox/ci/DockerExecutorSpec.scala b/crashboxd/src/test/scala/io/crashbox/ci/DockerExecutorSpec.scala
new file mode 100644
index 0000000..2b6dce7
--- /dev/null
+++ b/crashboxd/src/test/scala/io/crashbox/ci/DockerExecutorSpec.scala
@@ -0,0 +1,122 @@
+package io.crashbox.ci
+
+import java.io.{ByteArrayOutputStream, File}
+import java.nio.file.Files
+
+import scala.collection.JavaConverters._
+import scala.concurrent.Await
+import scala.concurrent.duration._
+
+import akka.actor.ActorSystem
+import org.scalatest._
+
+class DockerExecutorSpec
+ extends FlatSpec
+ with Matchers
+ with BeforeAndAfterAll {
+
+ val image = "crashbox"
+
+ val timeout = 30.seconds
+
+ implicit val system = ActorSystem("docker-test")
+ import system.dispatcher
+ val exec = new DockerExecutor
+
+ override def beforeAll: Unit = {
+ println("Pulling base docker image for running docker tests")
+ val base = "debian:jessie-backports"
+ exec.dockerClient.pull(base)
+
+ withTmp { dir =>
+ println("Adapting base image for tests")
+ val modifications = s"""|FROM $base
+ |RUN adduser crashbox
+ |USER crashbox
+ |""".stripMargin
+ Files.write((new File(dir, "Dockerfile")).toPath, modifications.getBytes)
+ exec.dockerClient.build(dir.toPath, image)
+ }
+
+ }
+
+ override def afterAll: Unit = {
+ system.terminate()
+ }
+
+ def withTmp[A](action: File => A): A = {
+ val dir = Files.createTempDirectory("crashbox-docker-test").toFile
+ try action(dir)
+ finally dir.delete()
+ }
+
+ def run[A](script: String)(tests: (Int, File, String) => A): A = withTmp {
+ dir =>
+ val out = new ByteArrayOutputStream(1024)
+ val awaitable = for (id <- exec.start(image, script, dir, out);
+ status <- exec.result(id)) yield {
+ status
+ }
+ val status = Await.result(awaitable, timeout)
+ tests(status, dir, new String(out.toByteArray()).trim())
+ }
+
+ "DockerExecutor" should "return expected exit codes" in {
+ run("true") {
+ case (status, _, _) =>
+ assert(status == 0)
+ }
+ run("false") {
+ case (status, _, _) =>
+ assert(status == 1)
+ }
+ run("nonexistant") {
+ case (status, _, _) =>
+ assert(status == 127)
+ }
+ }
+
+ it should "print the expected output" in {
+ run("echo hello world") {
+ case (_, _, out) =>
+ assert(out == "hello world")
+ }
+ run("echo hello world >&2") {
+ case (_, _, out) =>
+ assert(out == "hello world")
+ }
+ run("echo hello world > /dev/null") {
+ case (_, _, out) =>
+ assert(out == "")
+ }
+ }
+
+ it should "create expected files" in {
+ run("echo hello world > data") {
+ case (_, dir, _) =>
+ val data = Files
+ .lines((new File(dir, "data")).toPath)
+ .iterator()
+ .asScala
+ .mkString("\n")
+ assert(data == "hello world")
+ }
+ }
+
+ it should "allow cancellation" in {
+ withTmp { dir =>
+ val script = "while true; do sleep 1; echo sleeping; done"
+ val out = new ByteArrayOutputStream(1024)
+
+ val id = Await.result(exec.start(image, script, dir, out), timeout)
+ val check = exec.result(id).map { res =>
+ assert(res == 137)
+ }
+ exec.stop(id)
+ //TODO check if resoruces were cleaned up properly
+
+ Await.result(check, timeout)
+ }
+ }
+
+}