diff --git a/.travis.yml b/.travis.yml index bf766fc..9513363 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,11 +13,3 @@ sudo: required services: - docker - -before_install: - - docker run - --detach - --publish 2379:2379 - quay.io/coreos/etcd:v2.3.7 - --listen-client-urls http://0.0.0.0:2379 - --advertise-client-urls http://127.0.0.1:2379 diff --git a/build.sbt b/build.sbt index ebf5370..884c0e8 100644 --- a/build.sbt +++ b/build.sbt @@ -18,7 +18,7 @@ lazy val core = project .enablePlugins(AutomateHeaderPlugin) .configs(MultiJvm) - .dependsOn(coordination,`coordination-etcd` % "test->compile") + .dependsOn(coordination,`coordination-etcd` % "test->test") .settings(settings) .settings(multiJvmSettings) .settings( @@ -30,7 +30,9 @@ lazy val core = library.akkaTestkit % Test, library.log4jCore % Test, library.mockitoCore % Test, - library.scalaTest % Test + library.scalaTest % Test, + library.dockerTestKit % Test, + library.dockerTestKitSpotify % Test ) ) @@ -55,11 +57,15 @@ lazy val `coordination-etcd` = libraryDependencies ++= Seq( library.akkaHttp, library.circeParser, - library.akkaTestkit % Test, - library.scalaTest % Test + library.akkaTestkit % Test, + library.scalaTest % Test, + library.dockerTestKit % Test, + library.dockerTestKitSpotify % Test ) ) +parallelExecution in Global := false + // ***************************************************************************** // Library dependencies // ***************************************************************************** @@ -67,25 +73,28 @@ lazy val `coordination-etcd` = lazy val library = new { object Version { - final val akka = "2.4.17" - final val akkaHttp = "10.0.3" - final val akkaLog4j = "1.3.0" - final val circe = "0.7.0" - final val log4j = "2.8" - final val mockito = "2.6.8" - final val scalaTest = "3.0.1" + final val akka = "2.4.17" + final val akkaHttp = "10.0.3" + final val akkaLog4j = "1.3.0" + final val circe = "0.7.0" + final val log4j = "2.8" + final val mockito = "2.6.8" + final val scalaTest = "3.0.1" + final val dockerTestKit = "0.9.1" } - val akkaActor = "com.typesafe.akka" %% "akka-actor" % Version.akka - val akkaCluster = "com.typesafe.akka" %% "akka-cluster" % Version.akka - val akkaHttp = "com.typesafe.akka" %% "akka-http" % Version.akkaHttp - val akkaLog4j = "de.heikoseeberger" %% "akka-log4j" % Version.akkaLog4j - val akkaMultiNodeTestkit = "com.typesafe.akka" %% "akka-multi-node-testkit" % Version.akka - val akkaSlf4j = "com.typesafe.akka" %% "akka-slf4j" % Version.akka - val akkaTestkit = "com.typesafe.akka" %% "akka-testkit" % Version.akka - val circeParser = "io.circe" %% "circe-parser" % Version.circe - val log4jCore = "org.apache.logging.log4j" % "log4j-core" % Version.log4j - val mockitoCore = "org.mockito" % "mockito-core" % Version.mockito - val scalaTest = "org.scalatest" %% "scalatest" % Version.scalaTest + val akkaActor = "com.typesafe.akka" %% "akka-actor" % Version.akka + val akkaCluster = "com.typesafe.akka" %% "akka-cluster" % Version.akka + val akkaHttp = "com.typesafe.akka" %% "akka-http" % Version.akkaHttp + val akkaLog4j = "de.heikoseeberger" %% "akka-log4j" % Version.akkaLog4j + val akkaMultiNodeTestkit = "com.typesafe.akka" %% "akka-multi-node-testkit" % Version.akka + val akkaSlf4j = "com.typesafe.akka" %% "akka-slf4j" % Version.akka + val akkaTestkit = "com.typesafe.akka" %% "akka-testkit" % Version.akka + val circeParser = "io.circe" %% "circe-parser" % Version.circe + val log4jCore = "org.apache.logging.log4j" % "log4j-core" % Version.log4j + val mockitoCore = "org.mockito" % "mockito-core" % Version.mockito + val scalaTest = "org.scalatest" %% "scalatest" % Version.scalaTest + val dockerTestKit = "com.whisk" %% "docker-testkit-scalatest" % Version.dockerTestKit + val dockerTestKitSpotify = "com.whisk" %% "docker-testkit-impl-spotify" % Version.dockerTestKit } // ***************************************************************************** diff --git a/coordination-etcd/src/test/scala/de/heikoseeberger/constructr/coordination/etcd/EtcdCoordinationSpec.scala b/coordination-etcd/src/test/scala/de/heikoseeberger/constructr/coordination/etcd/EtcdCoordinationSpec.scala index cd315d6..0e4b0d8 100644 --- a/coordination-etcd/src/test/scala/de/heikoseeberger/constructr/coordination/etcd/EtcdCoordinationSpec.scala +++ b/coordination-etcd/src/test/scala/de/heikoseeberger/constructr/coordination/etcd/EtcdCoordinationSpec.scala @@ -20,7 +20,12 @@ import akka.Done import akka.actor.{ ActorSystem, AddressFromURIString } import akka.testkit.{ TestDuration, TestProbe } import com.typesafe.config.ConfigFactory +import com.whisk.docker.impl.spotify.DockerKitSpotify +import com.whisk.docker.scalatest.DockerTestKit +import de.heikoseeberger.constructr.coordination.etcd.utils.DockerEtcdService +import org.scalatest.concurrent.ScalaFutures import org.scalatest.{ BeforeAndAfterAll, Matchers, WordSpec } + import scala.concurrent.duration.{ Duration, DurationInt, FiniteDuration } import scala.concurrent.{ Await, Awaitable } import scala.util.Random @@ -39,7 +44,10 @@ object EtcdCoordinationSpec { class EtcdCoordinationSpec extends WordSpec with Matchers - with BeforeAndAfterAll { + with BeforeAndAfterAll + with DockerEtcdService + with DockerTestKit + with DockerKitSpotify { import EtcdCoordinationSpec._ private implicit val system = { @@ -78,7 +86,7 @@ class EtcdCoordinationSpec } } - override protected def afterAll() = { + override def afterAll() = { Await.ready(system.terminate(), Duration.Inf) super.afterAll() } diff --git a/coordination-etcd/src/test/scala/de/heikoseeberger/constructr/coordination/etcd/utils/DockerEtcdService.scala b/coordination-etcd/src/test/scala/de/heikoseeberger/constructr/coordination/etcd/utils/DockerEtcdService.scala new file mode 100644 index 0000000..ca46f53 --- /dev/null +++ b/coordination-etcd/src/test/scala/de/heikoseeberger/constructr/coordination/etcd/utils/DockerEtcdService.scala @@ -0,0 +1,35 @@ +/* + * Copyright 2015 Heiko Seeberger + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package de.heikoseeberger.constructr.coordination.etcd.utils + +import com.whisk.docker.{ DockerContainer, DockerKit, DockerReadyChecker } + +trait DockerEtcdService extends DockerKit { + val DefaultEtcdPort = 2379 + + val etcdContainer = DockerContainer("quay.io/coreos/etcd:v2.3.7") + .withPorts(DefaultEtcdPort -> Some(DefaultEtcdPort)) + .withReadyChecker(DockerReadyChecker.LogLineContains( + "setting up the initial cluster version to")) + .withCommand("--listen-client-urls", + "http://0.0.0.0:2379", + "--advertise-client-urls", + "http://0.0.0.0:2379") + + abstract override def dockerContainers: List[DockerContainer] = + etcdContainer :: super.dockerContainers +} diff --git a/core/src/multi-jvm/scala/de/heikoseeberger/constructr/MultiNodeConstructrSpec.scala b/core/src/multi-jvm/scala/de/heikoseeberger/constructr/MultiNodeConstructrSpec.scala index 86a011a..a290633 100644 --- a/core/src/multi-jvm/scala/de/heikoseeberger/constructr/MultiNodeConstructrSpec.scala +++ b/core/src/multi-jvm/scala/de/heikoseeberger/constructr/MultiNodeConstructrSpec.scala @@ -29,9 +29,14 @@ import akka.stream.ActorMaterializer import akka.testkit.TestDuration import akka.util.Timeout import com.typesafe.config.ConfigFactory +import com.whisk.docker.impl.spotify.DockerKitSpotify +import com.whisk.docker.scalatest.DockerTestKit +import de.heikoseeberger.constructr.coordination.etcd.utils.DockerEtcdService import org.scalatest.{ BeforeAndAfterAll, FreeSpecLike, Matchers } + import scala.concurrent.Await import scala.concurrent.duration.DurationInt +import scala.util.Success object ConstructrMultiNodeConfig { val coordinationHost = { @@ -71,7 +76,9 @@ abstract class MultiNodeConstructrSpec( ) extends MultiNodeSpec(new ConstructrMultiNodeConfig(coordinationPort)) with FreeSpecLike with Matchers - with BeforeAndAfterAll { + with BeforeAndAfterAll + with DockerEtcdService + with DockerKitSpotify { import ConstructrMultiNodeConfig._ import RequestBuilding._ import system.dispatcher @@ -80,6 +87,8 @@ abstract class MultiNodeConstructrSpec( "Constructr should manage an Akka cluster" in { runOn(roles.head) { + startAllOrFail() + within(20.seconds.dilated) { awaitAssert { val coordinationStatus = @@ -146,16 +155,20 @@ abstract class MultiNodeConstructrSpec( } enterBarrier("done") + + runOn(roles.head) { + stopAllQuietly() + } } override def initialParticipants = roles.size - override protected def beforeAll() = { + override def beforeAll() = { super.beforeAll() multiNodeSpecBeforeAll() } - override protected def afterAll() = { + override def afterAll() = { multiNodeSpecAfterAll() super.afterAll() }