Skip to content

Commit 42607b4

Browse files
authored
Merge pull request #487 from greshny-forks/specs2-v2
specs2 integration
2 parents 8057481 + 94d0e6c commit 42607b4

File tree

13 files changed

+933
-2
lines changed

13 files changed

+933
-2
lines changed

build.sbt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ lazy val root = (project in file("."))
7373
.aggregate(
7474
core,
7575
munit,
76+
specs2,
7677
scalatest,
7778
scalatestSelenium,
7879
jdbc,
@@ -252,6 +253,15 @@ lazy val munit = (project in file("test-framework/munit"))
252253
libraryDependencies ++= Dependencies.munit.value
253254
)
254255

256+
lazy val specs2 = (project in file("test-framework/specs2"))
257+
.dependsOn(core % "compile->compile;test->test;provided->provided")
258+
.settings(commonSettings)
259+
.settings(
260+
name := "testcontainers-scala-specs2",
261+
libraryDependencies ++= Dependencies.specs2.value,
262+
Test / scalacOptions --= Seq("-Xfatal-warnings")
263+
)
264+
255265
lazy val scalatestSelenium = (project in file("test-framework/scalatest-selenium"))
256266
.dependsOn(scalatest % "compile->compile;test->test;provided->provided")
257267
.settings(commonSettings)

modules/gcloud/src/test/scala/com/dimafeng/testcontainers/FirestoreEmulatorContainerSpec.scala

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@ package com.dimafeng.testcontainers
22

33
import org.scalatest.matchers.should.Matchers
44
import org.scalatest.wordspec.AnyWordSpecLike
5+
import org.testcontainers.utility.DockerImageName
56

67
import scala.collection.JavaConverters._
78

8-
class FirestoreEmulatorContainerSpec extends AnyWordSpecLike with Matchers with ForAllTestContainer {
9+
class FirestoreEmulatorContainerSpec
10+
extends AnyWordSpecLike
11+
with Matchers
12+
with ForAllTestContainer {
913

10-
override val container: FirestoreEmulatorContainer = FirestoreEmulatorContainer()
14+
override val container: FirestoreEmulatorContainer =
15+
FirestoreEmulatorContainer(
16+
DockerImageName.parse("gcr.io/google.com/cloudsdktool/cloud-sdk:382.0.0")
17+
)
1118

1219
"Firestore emulator container" should {
1320

project/Dependencies.scala

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ object Dependencies {
2121
private val scalaTestSeleniumVersion_scala3 = "3.2.9.0"
2222
private val junitVersion = "4.13.2"
2323
private val munitVersion = "1.1.1"
24+
25+
private val specs2Version = Def.setting {
26+
CrossVersion.partialVersion(scalaVersion.value) match {
27+
case Some((2, _)) => "4.20.5"
28+
case _ => "5.6.4" // Scala 3
29+
}
30+
}
2431
private val mysqlConnectorVersion = "5.1.42"
2532
private val neo4jConnectorVersion = "4.0.0"
2633
private val oracleDriverVersion = "21.18.0.0"
@@ -82,6 +89,14 @@ object Dependencies {
8289
)
8390
)
8491

92+
val specs2 = Def.setting {
93+
PROVIDED(
94+
"org.specs2" %% "specs2-core" % specs2Version.value
95+
) ++ TEST(
96+
"org.mockito" % "mockito-core" % mockitoVersion
97+
)
98+
}
99+
85100
val scalatestSelenium = Def.setting(
86101
COMPILE(
87102
"org.testcontainers" % "selenium" % testcontainersVersion,
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.dimafeng.testcontainers.specs2
2+
3+
import com.dimafeng.testcontainers.ContainerDef
4+
import org.specs2.specification.core.SpecificationStructure
5+
6+
trait TestContainerForAll extends TestContainersForAll { self: SpecificationStructure =>
7+
val containerDef: ContainerDef
8+
final override type Containers = containerDef.Container
9+
override def startContainers(): containerDef.Container = containerDef.start()
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.dimafeng.testcontainers.specs2
2+
3+
import com.dimafeng.testcontainers.ContainerDef
4+
import org.specs2.specification.core.SpecificationStructure
5+
6+
trait TestContainerForEach extends TestContainersForEach { self: SpecificationStructure =>
7+
val containerDef: ContainerDef
8+
final override type Containers = containerDef.Container
9+
override def startContainers(): containerDef.Container = containerDef.start()
10+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.dimafeng.testcontainers.specs2
2+
3+
import com.dimafeng.testcontainers.lifecycle.Andable
4+
import org.specs2.execute.{AsResult, Result}
5+
import org.specs2.specification.core.SpecificationStructure
6+
import org.specs2.specification.{AroundEach, BeforeAfterAll}
7+
8+
trait TestContainersForAll extends TestContainersSuite with BeforeAfterAll with AroundEach { self: SpecificationStructure =>
9+
10+
override def beforeAll(): Unit = {
11+
val containers = startContainers()
12+
startedContainers = Some(containers)
13+
try {
14+
afterContainersStart(containers)
15+
} catch {
16+
case e: Throwable =>
17+
stopContainers(containers)
18+
throw e
19+
}
20+
}
21+
22+
override def around[R: AsResult](r: => R): Result = {
23+
startedContainers.foreach(beforeTest)
24+
val result = AsResult(r)
25+
val throwable = result match {
26+
case f: org.specs2.execute.Failure => Some(f.exception)
27+
case e: org.specs2.execute.Error => Some(e.exception)
28+
case _ => None
29+
}
30+
startedContainers.foreach(afterTest(_, throwable))
31+
result
32+
}
33+
34+
override def afterAll(): Unit = {
35+
startedContainers.foreach(stopContainers)
36+
}
37+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.dimafeng.testcontainers.specs2
2+
3+
import com.dimafeng.testcontainers.lifecycle.Andable
4+
import org.specs2.execute.{AsResult, Result}
5+
import org.specs2.specification.core.SpecificationStructure
6+
import org.specs2.specification.AroundEach
7+
8+
trait TestContainersForEach extends TestContainersSuite with AroundEach { self: SpecificationStructure =>
9+
10+
override def around[R: AsResult](r: => R): Result = {
11+
val containers = startContainers()
12+
startedContainers = Some(containers)
13+
try {
14+
afterContainersStart(containers)
15+
beforeTest(containers)
16+
17+
val result = AsResult(r)
18+
19+
val throwable = result match {
20+
case f: org.specs2.execute.Failure => Some(f.exception)
21+
case e: org.specs2.execute.Error => Some(e.exception)
22+
case _ => None
23+
}
24+
afterTest(containers, throwable)
25+
result
26+
} finally {
27+
stopContainers(containers)
28+
}
29+
}
30+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.dimafeng.testcontainers.specs2
2+
3+
import com.dimafeng.testcontainers.implicits.DockerImageNameConverters
4+
import com.dimafeng.testcontainers.lifecycle.{Andable, TestLifecycleAware}
5+
import org.specs2.specification.core.SpecificationStructure
6+
import org.junit.runner.{Description => JunitDescription}
7+
import org.testcontainers.lifecycle.TestDescription
8+
9+
trait TestContainersSuite extends DockerImageNameConverters { self: SpecificationStructure =>
10+
type Containers <: Andable
11+
12+
def startContainers(): Containers
13+
14+
def withContainers[A](runTest: Containers => A): A = {
15+
val c = startedContainers.getOrElse(throw new IllegalStateException(
16+
"'withContainers' method can't be used before all containers are started. " +
17+
"'withContainers' method should be used only in test cases to prevent this."
18+
))
19+
runTest(c)
20+
}
21+
22+
def afterContainersStart(containers: Containers): Unit = {}
23+
def beforeContainersStop(containers: Containers): Unit = {}
24+
25+
@volatile private[testcontainers] var startedContainers: Option[Containers] = None
26+
27+
private[testcontainers] val suiteDescription: TestDescription = {
28+
val description = JunitDescription.createSuiteDescription(self.getClass)
29+
new TestDescription {
30+
override def getTestId: String = description.getDisplayName
31+
override def getFilesystemFriendlyName: String = s"${description.getClassName}-${description.getMethodName}"
32+
}
33+
}
34+
35+
private[testcontainers] def beforeTest(containers: Containers): Unit = {
36+
containers.foreach {
37+
case container: TestLifecycleAware => container.beforeTest(suiteDescription)
38+
case _ => // do nothing
39+
}
40+
}
41+
42+
private[testcontainers] def afterTest(containers: Containers, throwable: Option[Throwable]): Unit = {
43+
containers.foreach {
44+
case container: TestLifecycleAware => container.afterTest(suiteDescription, throwable)
45+
case _ => // do nothing
46+
}
47+
}
48+
49+
private[testcontainers] def stopContainers(containers: Containers): Unit = {
50+
try {
51+
beforeContainersStop(containers)
52+
} finally {
53+
try {
54+
startedContainers.foreach(_.stop())
55+
} finally {
56+
startedContainers = None
57+
}
58+
}
59+
}
60+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.dimafeng.testcontainers.specs2
2+
3+
import java.util.Optional
4+
import com.dimafeng.testcontainers.{ContainerDef, SingleContainer}
5+
import com.dimafeng.testcontainers.lifecycle.TestLifecycleAware
6+
import org.testcontainers.containers.{GenericContainer => JavaGenericContainer}
7+
import org.testcontainers.lifecycle.{TestDescription, TestLifecycleAware => JavaTestLifecycleAware}
8+
9+
case class SampleContainer(sampleJavaContainer: SampleContainer.SampleJavaContainer)
10+
extends SingleContainer[SampleContainer.SampleJavaContainer] with TestLifecycleAware {
11+
override implicit val container: SampleContainer.SampleJavaContainer = sampleJavaContainer
12+
13+
override def beforeTest(description: TestDescription): Unit = {
14+
container.beforeTest(description)
15+
}
16+
17+
override def afterTest(description: TestDescription, throwable: Option[Throwable]): Unit = {
18+
container.afterTest(description, throwable.fold[Optional[Throwable]](Optional.empty())(Optional.of))
19+
}
20+
}
21+
22+
object SampleContainer {
23+
class SampleJavaContainer extends JavaGenericContainer[SampleJavaContainer] with JavaTestLifecycleAware {
24+
override def beforeTest(description: TestDescription): Unit = {}
25+
override def afterTest(description: TestDescription, throwable: Optional[Throwable]): Unit = {}
26+
override def start(): Unit = {}
27+
override def stop(): Unit = {}
28+
}
29+
30+
case class Def(sampleJavaContainer: SampleJavaContainer) extends ContainerDef {
31+
override type Container = SampleContainer
32+
override protected def createContainer(): SampleContainer = SampleContainer(sampleJavaContainer)
33+
}
34+
}

0 commit comments

Comments
 (0)