diff options
Diffstat (limited to 'crashboxd/src/test/scala/io/crashbox/ci')
-rw-r--r-- | crashboxd/src/test/scala/io/crashbox/ci/BuildStageSpec.scala | 63 | ||||
-rw-r--r-- | crashboxd/src/test/scala/io/crashbox/ci/DockerExecutorSpec.scala | 78 |
2 files changed, 134 insertions, 7 deletions
diff --git a/crashboxd/src/test/scala/io/crashbox/ci/BuildStageSpec.scala b/crashboxd/src/test/scala/io/crashbox/ci/BuildStageSpec.scala new file mode 100644 index 0000000..a3a68b6 --- /dev/null +++ b/crashboxd/src/test/scala/io/crashbox/ci/BuildStageSpec.scala @@ -0,0 +1,63 @@ +package io.crashbox.ci + +import akka.actor.ActorSystem +import akka.stream.{ ClosedShape, KillSwitch } +import akka.stream.scaladsl.{ GraphDSL, RunnableGraph, Sink, Source } +import akka.stream.{ ActorMaterializer, FanInShape2 } +import java.io.{ ByteArrayOutputStream, File } +import java.nio.file.Files +import org.scalatest._ +import scala.concurrent.Await +import scala.concurrent.duration._ + +class BuildStageSpec extends FlatSpec with Matchers with DockerSuite{ + + implicit val materializer = ActorMaterializer() + + val exec = new DockerExecutor + + def withTmp[A](action: (File, ByteArrayOutputStream) => A): A = { + val dir = Files.createTempDirectory("crashbox-build-stage-test").toFile + val out = new ByteArrayOutputStream(1024) + try action(dir, out) + finally dir.delete() + } + + "BuildStage" should "have a test!" in { + withTmp{ case (dir, out) => + val taskDef = TaskDef(DockerEnvironment("crashbox"), "sleep 100; exit 0") + + val resultSink = Sink.foreach[Builder.BuildState](x => println(x)) + + val graph = RunnableGraph.fromGraph(GraphDSL.create(resultSink) { + implicit b => sink => + import GraphDSL.Implicits._ + + val builder = b.add(new BuildStage(exec, _ => dir, _ => out)) + + val submissions = b.add( + Source.repeat(TaskId("123", 2) -> taskDef)) + val cancellations = b.add( + Source.tick(10.seconds, 10.seconds, TaskId("0", 0))) + + val ks = b.add(KillSwitch) + + submissions ~> builder.in0 + cancellations ~> builder.in1 + + builder.out ~> sink + + ClosedShape + }) + + graph.run() + Thread.sleep(30000) + println("terminating") + Await.result(system.terminate(), 60.seconds) + println("teminated") + Thread.sleep(5000) + println("eot") + } + + } +} diff --git a/crashboxd/src/test/scala/io/crashbox/ci/DockerExecutorSpec.scala b/crashboxd/src/test/scala/io/crashbox/ci/DockerExecutorSpec.scala index 2b6dce7..23cbced 100644 --- a/crashboxd/src/test/scala/io/crashbox/ci/DockerExecutorSpec.scala +++ b/crashboxd/src/test/scala/io/crashbox/ci/DockerExecutorSpec.scala @@ -1,5 +1,6 @@ package io.crashbox.ci +import com.spotify.docker.client.DockerClient.ListContainersParam import java.io.{ByteArrayOutputStream, File} import java.nio.file.Files @@ -9,6 +10,69 @@ import scala.concurrent.duration._ import akka.actor.ActorSystem import org.scalatest._ +import scala.util.Random + + +trait DockerSuite extends Suite with BeforeAndAfterAll { self => + + private val name = self.toString() + + private def withTmp[A](action: File => A): A = { + val dir = Files.createTempDirectory("crashbox-docker-test-" + name).toFile + try action(dir) + finally dir.delete() + } + + val baseImage = "debian:jessie-backports" + val dockerImage = "crashbox" + val dockerTimeout = 30.seconds + val dockerLabel = "test-" + Random.nextInt() + + implicit val system = ActorSystem("crashbox-docker-test-" + name) + import system.dispatcher + val executor = new DockerExecutor { + override def label = dockerLabel + } + + def buildImage(): Unit = { + println("Pulling base docker image for running docker tests") + executor.dockerClient.pull(baseImage) + + withTmp { dir => + println("Adapting base image for tests") + val modifications = s"""|FROM $baseImage + |RUN adduser crashbox + |USER crashbox + |""".stripMargin + Files.write((new File(dir, "Dockerfile")).toPath, modifications.getBytes) + executor.dockerClient.build(dir.toPath, dockerImage) + } + } + + def runningDockers: Seq[String] = { + val stale = executor.dockerClient + .listContainers( + ListContainersParam.withLabel("crashbox", dockerLabel) + ).asScala + stale.map(_.id()) + } + + override def beforeAll: Unit = { + buildImage() + } + + override def afterAll: Unit = { + val running = runningDockers + running.foreach { id => + executor.dockerClient.stopContainer(id, 0) + executor.dockerClient.removeContainer(id) + } + require(running.isEmpty, "Docker containers were left running after unit tests") + require(runningDockers.isEmpty, "Could not delete left over docker containers.") + } + +} + class DockerExecutorSpec extends FlatSpec @@ -52,13 +116,13 @@ class DockerExecutorSpec 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()) + 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 { |