From cd4781b83e2205d9edcb06e9e98c06867ea0ecc5 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Tue, 7 Apr 2020 01:04:36 +0530 Subject: [PATCH 01/21] Adds TestContainer support in kotest --- modules/kotest/build.gradle | 39 +++++++++++++++ .../containers/ContainerPerSpecListener.kt | 49 +++++++++++++++++++ .../containers/ContainerPerTestListener.kt | 44 +++++++++++++++++ .../ContainerPerSpecListenerTest.kt | 27 ++++++++++ .../ContainerPerTestListenerTest.kt | 28 +++++++++++ 5 files changed, 187 insertions(+) create mode 100644 modules/kotest/build.gradle create mode 100644 modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerSpecListener.kt create mode 100644 modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerTestListener.kt create mode 100644 modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerSpecListenerTest.kt create mode 100644 modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerTestListenerTest.kt diff --git a/modules/kotest/build.gradle b/modules/kotest/build.gradle new file mode 100644 index 00000000000..1352d8f5236 --- /dev/null +++ b/modules/kotest/build.gradle @@ -0,0 +1,39 @@ +plugins { + id "org.jetbrains.kotlin.jvm" version "1.3.71" + id "org.jetbrains.kotlin.kapt" version "1.3.71" +} + +ext { + kotestVersion = "4.0.2" +} + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + compile project(':testcontainers') + api("io.kotest:kotest-runner-junit5-jvm:$kotestVersion") + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + testImplementation("io.kotest:kotest-assertions-core-jvm:$kotestVersion") + testImplementation("io.mockk:mockk:1.9.3") +} + + +test { + useJUnitPlatform() +} + +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + javaParameters = true + } +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerSpecListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerSpecListener.kt new file mode 100644 index 00000000000..f0438287e6f --- /dev/null +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerSpecListener.kt @@ -0,0 +1,49 @@ +package org.testcontainers.containers + +import io.kotest.core.listeners.TestListener +import io.kotest.core.spec.Spec +import io.kotest.core.test.TestCase +import io.kotest.core.test.TestResult +import kotlin.reflect.KClass + + +/** + * [ContainerPerSpecListener] starts the given [genericContainers] before execution of any test in the spec + * and stops after execution of all tests. + * + * [genericContainers] can any of [GenericContainer] [ContainerisedDockerCompose] [LocalStackContainer] etc. + * + * This should be use when you want to a single container for all test in a single test class. + * + * @see + * [ContainerPerSpecListener] + * + * Usage: + * + * class RedisRepositoryTest: StringSpec() { + * private val redisContainer = GenericContainer("redis") + * + * override fun listeners(): List { + * return super.listeners() + ContainerPerSpecListener(redisContainer) + * } + * + * init { + * "should be able to connect redis server" { + * // your test goes here + * } + * } + * } + * */ + +class ContainerPerSpecListener(private vararg val genericContainers: GenericContainer) : TestListener { + + override suspend fun finalizeSpec(kclass: KClass, results: Map) { + genericContainers.forEach { it.stop() } + super.finalizeSpec(kclass, results) + } + + override suspend fun prepareSpec(kclass: KClass) { + genericContainers.forEach { it.start() } + super.prepareSpec(kclass) + } +} diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerTestListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerTestListener.kt new file mode 100644 index 00000000000..05594a416eb --- /dev/null +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerTestListener.kt @@ -0,0 +1,44 @@ +package org.testcontainers.containers + +import io.kotest.core.listeners.TestListener +import io.kotest.core.test.TestCase +import io.kotest.core.test.TestResult + + +/** + * [ContainerPerTestListener] starts the given [genericContainers] before execution of each test in the spec + * and stops after execution of each test. + * + * [genericContainers] can any of [GenericContainer] [ContainerisedDockerCompose] [LocalStackContainer] etc. + * + * This should be use when you want fresh container for each test. + * + * @see[ContainerPerSpecListener] + * Usage: + * + * class RedisRepositoryTest: StringSpec() { + * private val redisContainer = GenericContainer("redis") + * + * override fun listeners(): List { + * return super.listeners() + ContainerPerTestListener(redisContainer) + * } + * + * init { + * "should be able to connect redis server" { + * // your test goes here + * } + * } + * } + * */ +class ContainerPerTestListener(private vararg val genericContainers: GenericContainer) : TestListener { + + override suspend fun beforeTest(testCase: TestCase) { + genericContainers.forEach { it.start() } + super.beforeTest(testCase) + } + + override suspend fun afterTest(testCase: TestCase, result: TestResult) { + genericContainers.forEach { it.stop() } + super.afterTest(testCase, result) + } +} diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerSpecListenerTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerSpecListenerTest.kt new file mode 100644 index 00000000000..d436b51ded6 --- /dev/null +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerSpecListenerTest.kt @@ -0,0 +1,27 @@ +import io.kotest.core.spec.style.StringSpec +import io.mockk.mockk +import io.mockk.verify +import org.testcontainers.containers.ContainerPerSpecListener +import org.testcontainers.containers.GenericContainer + +class ContainerPerSpecListenerTest : StringSpec() { + init { + "should stop container in finalizeSpec callback" { + val mockContainer: GenericContainer = mockk(relaxed = true) + val containerPerSpecListener = ContainerPerSpecListener(mockContainer) + + containerPerSpecListener.finalizeSpec(mockk(), emptyMap()) + + verify(exactly = 1) { mockContainer.stop() } + } + + "should start container in prepareSpec callback" { + val mockContainer: GenericContainer = mockk(relaxed = true) + val containerPerSpecListener = ContainerPerSpecListener(mockContainer) + + containerPerSpecListener.prepareSpec(mockk()) + + verify(exactly = 1) { mockContainer.start() } + } + } +} diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerTestListenerTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerTestListenerTest.kt new file mode 100644 index 00000000000..fafcd5bda8a --- /dev/null +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerTestListenerTest.kt @@ -0,0 +1,28 @@ +import io.kotest.core.spec.style.StringSpec +import io.mockk.mockk +import io.mockk.verify +import org.testcontainers.containers.ContainerPerTestListener +import org.testcontainers.containers.GenericContainer + +class ContainerPerTestListenerTest: StringSpec() { + init { + + "should start container in beforeTest callback" { + val mockContainer: GenericContainer = mockk(relaxed = true) + val containerPerTestListener = ContainerPerTestListener(mockContainer) + + containerPerTestListener.beforeTest(mockk()) + + verify(exactly = 1) { mockContainer.start() } + } + + "should stop container in afterTest callback" { + val mockContainer: GenericContainer = mockk(relaxed = true) + val containerPerTestListener = ContainerPerTestListener(mockContainer) + + containerPerTestListener.afterTest(mockk(), mockk()) + + verify(exactly = 1) { mockContainer.stop() } + } + } +} From 9571cf639467a5a87ff6a5f9df8fedf01d4ac3be Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Wed, 15 Apr 2020 11:12:55 +0530 Subject: [PATCH 02/21] Upgrades kotest to latest 4.0.3 --- modules/kotest/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kotest/build.gradle b/modules/kotest/build.gradle index 1352d8f5236..0e10e141685 100644 --- a/modules/kotest/build.gradle +++ b/modules/kotest/build.gradle @@ -4,7 +4,7 @@ plugins { } ext { - kotestVersion = "4.0.2" + kotestVersion = "4.0.3" } sourceCompatibility = 1.8 From b45b02cb2fc3c6a9713e560d2702a3fbffdf4963 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Sat, 18 Apr 2020 00:34:16 +0530 Subject: [PATCH 03/21] Removes usage of ContainerPerSpecListener and ContainerPerSpecListener from java docs comment --- .../containers/ContainerPerSpecListener.kt | 38 +++++-------------- .../containers/ContainerPerTestListener.kt | 15 -------- .../ContainerPerSpecListenerTest.kt | 8 ++-- .../ContainerPerTestListenerTest.kt | 1 - 4 files changed, 13 insertions(+), 49 deletions(-) diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerSpecListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerSpecListener.kt index f0438287e6f..71c57f3d730 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerSpecListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerSpecListener.kt @@ -2,9 +2,6 @@ package org.testcontainers.containers import io.kotest.core.listeners.TestListener import io.kotest.core.spec.Spec -import io.kotest.core.test.TestCase -import io.kotest.core.test.TestResult -import kotlin.reflect.KClass /** @@ -16,34 +13,17 @@ import kotlin.reflect.KClass * This should be use when you want to a single container for all test in a single test class. * * @see - * [ContainerPerSpecListener] - * - * Usage: - * - * class RedisRepositoryTest: StringSpec() { - * private val redisContainer = GenericContainer("redis") - * - * override fun listeners(): List { - * return super.listeners() + ContainerPerSpecListener(redisContainer) - * } - * - * init { - * "should be able to connect redis server" { - * // your test goes here - * } - * } - * } + * [ContainerPerTestListener] * */ class ContainerPerSpecListener(private vararg val genericContainers: GenericContainer) : TestListener { + override suspend fun beforeSpec(spec: Spec) { + genericContainers.forEach { it.start() } + super.beforeSpec(spec) + } - override suspend fun finalizeSpec(kclass: KClass, results: Map) { - genericContainers.forEach { it.stop() } - super.finalizeSpec(kclass, results) - } - - override suspend fun prepareSpec(kclass: KClass) { - genericContainers.forEach { it.start() } - super.prepareSpec(kclass) - } + override suspend fun afterSpec(spec: Spec) { + genericContainers.forEach { it.stop() } + super.afterSpec(spec) + } } diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerTestListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerTestListener.kt index 05594a416eb..0285a001a19 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerTestListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerTestListener.kt @@ -14,21 +14,6 @@ import io.kotest.core.test.TestResult * This should be use when you want fresh container for each test. * * @see[ContainerPerSpecListener] - * Usage: - * - * class RedisRepositoryTest: StringSpec() { - * private val redisContainer = GenericContainer("redis") - * - * override fun listeners(): List { - * return super.listeners() + ContainerPerTestListener(redisContainer) - * } - * - * init { - * "should be able to connect redis server" { - * // your test goes here - * } - * } - * } * */ class ContainerPerTestListener(private vararg val genericContainers: GenericContainer) : TestListener { diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerSpecListenerTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerSpecListenerTest.kt index d436b51ded6..f57f53a9bb3 100644 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerSpecListenerTest.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerSpecListenerTest.kt @@ -6,20 +6,20 @@ import org.testcontainers.containers.GenericContainer class ContainerPerSpecListenerTest : StringSpec() { init { - "should stop container in finalizeSpec callback" { + "should stop container in beforeSpec callback" { val mockContainer: GenericContainer = mockk(relaxed = true) val containerPerSpecListener = ContainerPerSpecListener(mockContainer) - containerPerSpecListener.finalizeSpec(mockk(), emptyMap()) + containerPerSpecListener.afterSpec(mockk()) verify(exactly = 1) { mockContainer.stop() } } - "should start container in prepareSpec callback" { + "should start container in afterSpec callback" { val mockContainer: GenericContainer = mockk(relaxed = true) val containerPerSpecListener = ContainerPerSpecListener(mockContainer) - containerPerSpecListener.prepareSpec(mockk()) + containerPerSpecListener.beforeSpec(mockk()) verify(exactly = 1) { mockContainer.start() } } diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerTestListenerTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerTestListenerTest.kt index fafcd5bda8a..b0c14299f05 100644 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerTestListenerTest.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerTestListenerTest.kt @@ -6,7 +6,6 @@ import org.testcontainers.containers.GenericContainer class ContainerPerTestListenerTest: StringSpec() { init { - "should start container in beforeTest callback" { val mockContainer: GenericContainer = mockk(relaxed = true) val containerPerTestListener = ContainerPerTestListener(mockContainer) From ccabb4dc3331d4aa5b2b5ab835b0319389cbdfdf Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Sat, 18 Apr 2020 00:35:21 +0530 Subject: [PATCH 04/21] Adds example of ContainerPerSpecListener and ContainerPerSpecListener in examples/kotest module --- examples/kotest/build.gradle | 38 +++++++++++++++++++ .../TestContainerKotestIntegrationPerTest.kt | 37 ++++++++++++++++++ .../TestcontainerKotestIntegrationPerSpec.kt | 37 ++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 examples/kotest/build.gradle create mode 100644 examples/kotest/src/test/kotlin/com/example/kotest/TestContainerKotestIntegrationPerTest.kt create mode 100644 examples/kotest/src/test/kotlin/com/example/kotest/TestcontainerKotestIntegrationPerSpec.kt diff --git a/examples/kotest/build.gradle b/examples/kotest/build.gradle new file mode 100644 index 00000000000..2d87db00b2a --- /dev/null +++ b/examples/kotest/build.gradle @@ -0,0 +1,38 @@ +plugins { + id "org.jetbrains.kotlin.jvm" version "1.3.71" + id "org.jetbrains.kotlin.kapt" version "1.3.71" +} + +ext { + kotestVersion = "4.0.3" +} + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + testImplementation 'org.testcontainers:postgresql' + testImplementation("io.kotest:kotest-runner-junit5-jvm:$kotestVersion") + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + testImplementation("io.kotest:kotest-assertions-core-jvm:$kotestVersion") +} + + +test { + useJUnitPlatform() +} + +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + javaParameters = true + } +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/examples/kotest/src/test/kotlin/com/example/kotest/TestContainerKotestIntegrationPerTest.kt b/examples/kotest/src/test/kotlin/com/example/kotest/TestContainerKotestIntegrationPerTest.kt new file mode 100644 index 00000000000..d4fc721ee45 --- /dev/null +++ b/examples/kotest/src/test/kotlin/com/example/kotest/TestContainerKotestIntegrationPerTest.kt @@ -0,0 +1,37 @@ +package com.example.kotest + +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.shouldBe +import kotlinx.coroutines.delay + +class TestContainerKotestIntegrationPerTest : StringSpec({ + val container = GenericContainer("ubuntu") + setContainerCommand(container) // Set container command for first time to echo hello Kotest + + // Register the Listener + listeners(ContainerPerTestListener(container)) + + "test should echo hello Kotest for first test" { + container.logs.trim() shouldBe "hello Kotest" + // Set container command so that next time when container start we will have hello Kotest again in container log + setContainerCommand(container) + delay(1000) + } + + "test should echo hello Kotest for second spec as well" { + // presence of hello Kotest again verifies that container is restarted. + container.logs.trim() shouldBe "hello Kotest again" + } + +}) + +private var testCount = 0 +private fun setContainerCommand(container: GenericContainer) { + if (testCount == 0) { + container.setCommand("echo", "hello Kotest") + testCount += 1 + } else { + container.setCommand("echo", "hello Kotest again") + } +} + diff --git a/examples/kotest/src/test/kotlin/com/example/kotest/TestcontainerKotestIntegrationPerSpec.kt b/examples/kotest/src/test/kotlin/com/example/kotest/TestcontainerKotestIntegrationPerSpec.kt new file mode 100644 index 00000000000..ca156595e6d --- /dev/null +++ b/examples/kotest/src/test/kotlin/com/example/kotest/TestcontainerKotestIntegrationPerSpec.kt @@ -0,0 +1,37 @@ +package com.example.kotest + +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.shouldBe +import kotlinx.coroutines.delay + +class TestcontainerKotestIntegrationPerSpec : StringSpec({ + val container = GenericContainer("ubuntu") + setContainerCommand(container) // Set container command for first time to echo hello Kotest + + // Register the Listener + listeners(ContainerPerSpecListener(container)) + + "test should echo hello Kotest for first test" { + container.logs.trim() shouldBe "hello Kotest" + // Set container command so that next time when container start we will have hello Kotest again in container log + setContainerCommand(container) + delay(1000) + } + + "test should echo hello Kotest for second spec as well" { + // presence of "hello Kotest" verifies that container is not restarted. + container.logs.trim() shouldBe "hello Kotest" + } + +}) + +private var testCount = 0 +private fun setContainerCommand(container: GenericContainer) { + if (testCount == 0) { + container.setCommand("echo", "hello Kotest") + testCount += 1 + } else { + container.setCommand("echo", "hello Kotest again") + } +} + From 9f33df6327ed5c120065a87d81c73840cf6319d8 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Sat, 18 Apr 2020 01:03:32 +0530 Subject: [PATCH 05/21] Moves kotest examples to docs --- {examples => docs/examples}/kotest/build.gradle | 5 +++-- .../example/kotest/TestContainerKotestIntegrationPerTest.kt | 2 ++ .../example/kotest/TestcontainerKotestIntegrationPerSpec.kt | 2 ++ settings.gradle | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) rename {examples => docs/examples}/kotest/build.gradle (89%) rename {examples => docs/examples}/kotest/src/test/kotlin/com/example/kotest/TestContainerKotestIntegrationPerTest.kt (91%) rename {examples => docs/examples}/kotest/src/test/kotlin/com/example/kotest/TestcontainerKotestIntegrationPerSpec.kt (91%) diff --git a/examples/kotest/build.gradle b/docs/examples/kotest/build.gradle similarity index 89% rename from examples/kotest/build.gradle rename to docs/examples/kotest/build.gradle index 2d87db00b2a..394bbf05fe2 100644 --- a/examples/kotest/build.gradle +++ b/docs/examples/kotest/build.gradle @@ -14,9 +14,10 @@ repositories { } dependencies { - testImplementation 'org.testcontainers:postgresql' - testImplementation("io.kotest:kotest-runner-junit5-jvm:$kotestVersion") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + testCompile project(':testcontainers') + testCompile project(':kotest') + testImplementation("io.kotest:kotest-runner-junit5-jvm:$kotestVersion") testImplementation("io.kotest:kotest-assertions-core-jvm:$kotestVersion") } diff --git a/examples/kotest/src/test/kotlin/com/example/kotest/TestContainerKotestIntegrationPerTest.kt b/docs/examples/kotest/src/test/kotlin/com/example/kotest/TestContainerKotestIntegrationPerTest.kt similarity index 91% rename from examples/kotest/src/test/kotlin/com/example/kotest/TestContainerKotestIntegrationPerTest.kt rename to docs/examples/kotest/src/test/kotlin/com/example/kotest/TestContainerKotestIntegrationPerTest.kt index d4fc721ee45..434b55b76d2 100644 --- a/examples/kotest/src/test/kotlin/com/example/kotest/TestContainerKotestIntegrationPerTest.kt +++ b/docs/examples/kotest/src/test/kotlin/com/example/kotest/TestContainerKotestIntegrationPerTest.kt @@ -3,6 +3,8 @@ package com.example.kotest import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe import kotlinx.coroutines.delay +import org.testcontainers.containers.ContainerPerTestListener +import org.testcontainers.containers.GenericContainer class TestContainerKotestIntegrationPerTest : StringSpec({ val container = GenericContainer("ubuntu") diff --git a/examples/kotest/src/test/kotlin/com/example/kotest/TestcontainerKotestIntegrationPerSpec.kt b/docs/examples/kotest/src/test/kotlin/com/example/kotest/TestcontainerKotestIntegrationPerSpec.kt similarity index 91% rename from examples/kotest/src/test/kotlin/com/example/kotest/TestcontainerKotestIntegrationPerSpec.kt rename to docs/examples/kotest/src/test/kotlin/com/example/kotest/TestcontainerKotestIntegrationPerSpec.kt index ca156595e6d..6a81b2906f8 100644 --- a/examples/kotest/src/test/kotlin/com/example/kotest/TestcontainerKotestIntegrationPerSpec.kt +++ b/docs/examples/kotest/src/test/kotlin/com/example/kotest/TestcontainerKotestIntegrationPerSpec.kt @@ -3,6 +3,8 @@ package com.example.kotest import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe import kotlinx.coroutines.delay +import org.testcontainers.containers.ContainerPerSpecListener +import org.testcontainers.containers.GenericContainer class TestcontainerKotestIntegrationPerSpec : StringSpec({ val container = GenericContainer("ubuntu") diff --git a/settings.gradle b/settings.gradle index 5ec35718ef6..968120b9fda 100644 --- a/settings.gradle +++ b/settings.gradle @@ -54,6 +54,7 @@ include ':docs:examples:junit4:generic' include ':docs:examples:junit4:redis' include ':docs:examples:junit5:redis' include ':docs:examples:spock:redis' +include ':docs:examples:kotest' include 'test-support' From 0d312ce53953acb3836d7b1bd44fd87926f34363 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Sun, 19 Apr 2020 18:01:07 +0530 Subject: [PATCH 06/21] Removes kotest from docs, renames listener, add extension function for creating listener from container --- docs/examples/kotest/build.gradle | 39 ------------------- .../testcontainers/containers/Extensions.kt | 6 +++ ...istener.kt => StartablePerSpecListener.kt} | 13 ++++--- ...istener.kt => StartablePerTestListener.kt} | 13 ++++--- .../ContainerPerSpecListenerTest.kt | 27 ------------- .../ContainerPerTestListenerTest.kt | 27 ------------- .../TestContainerKotestIntegrationPerTest.kt | 6 +-- .../TestcontainerKotestIntegrationPerSpec.kt | 8 +--- settings.gradle | 1 - 9 files changed, 24 insertions(+), 116 deletions(-) delete mode 100644 docs/examples/kotest/build.gradle create mode 100644 modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt rename modules/kotest/src/main/kotlin/org/testcontainers/containers/{ContainerPerSpecListener.kt => StartablePerSpecListener.kt} (50%) rename modules/kotest/src/main/kotlin/org/testcontainers/containers/{ContainerPerTestListener.kt => StartablePerTestListener.kt} (52%) delete mode 100644 modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerSpecListenerTest.kt delete mode 100644 modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerTestListenerTest.kt rename {docs/examples/kotest/src/test/kotlin/com/example/kotest => modules/kotest/src/test/kotlin/org/testcontainers/containers}/TestContainerKotestIntegrationPerTest.kt (85%) rename {docs/examples/kotest/src/test/kotlin/com/example/kotest => modules/kotest/src/test/kotlin/org/testcontainers/containers}/TestcontainerKotestIntegrationPerSpec.kt (81%) diff --git a/docs/examples/kotest/build.gradle b/docs/examples/kotest/build.gradle deleted file mode 100644 index 394bbf05fe2..00000000000 --- a/docs/examples/kotest/build.gradle +++ /dev/null @@ -1,39 +0,0 @@ -plugins { - id "org.jetbrains.kotlin.jvm" version "1.3.71" - id "org.jetbrains.kotlin.kapt" version "1.3.71" -} - -ext { - kotestVersion = "4.0.3" -} - -sourceCompatibility = 1.8 - -repositories { - mavenCentral() -} - -dependencies { - implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") - testCompile project(':testcontainers') - testCompile project(':kotest') - testImplementation("io.kotest:kotest-runner-junit5-jvm:$kotestVersion") - testImplementation("io.kotest:kotest-assertions-core-jvm:$kotestVersion") -} - - -test { - useJUnitPlatform() -} - -compileTestKotlin { - kotlinOptions { - jvmTarget = "1.8" - javaParameters = true - } -} -compileKotlin { - kotlinOptions { - jvmTarget = "1.8" - } -} diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt new file mode 100644 index 00000000000..6191022f4fc --- /dev/null +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt @@ -0,0 +1,6 @@ +package org.testcontainers.containers + +import org.testcontainers.lifecycle.Startable + +fun Startable.perTest() = StartablePerTestListener(this) +fun Startable.perSpec() = StartablePerSpecListener(this) diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerSpecListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt similarity index 50% rename from modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerSpecListener.kt rename to modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt index 71c57f3d730..e25573fc0c9 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerSpecListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt @@ -2,28 +2,29 @@ package org.testcontainers.containers import io.kotest.core.listeners.TestListener import io.kotest.core.spec.Spec +import org.testcontainers.lifecycle.Startable /** - * [ContainerPerSpecListener] starts the given [genericContainers] before execution of any test in the spec + * [StartablePerSpecListener] starts the given [startables] before execution of any test in the spec * and stops after execution of all tests. * - * [genericContainers] can any of [GenericContainer] [ContainerisedDockerCompose] [LocalStackContainer] etc. + * [startables] can any of [GenericContainer] [ContainerisedDockerCompose] [LocalStackContainer] etc. * * This should be use when you want to a single container for all test in a single test class. * * @see - * [ContainerPerTestListener] + * [StartablePerTestListener] * */ -class ContainerPerSpecListener(private vararg val genericContainers: GenericContainer) : TestListener { +class StartablePerSpecListener(private vararg val startables: Startable) : TestListener { override suspend fun beforeSpec(spec: Spec) { - genericContainers.forEach { it.start() } + startables.forEach { it.start() } super.beforeSpec(spec) } override suspend fun afterSpec(spec: Spec) { - genericContainers.forEach { it.stop() } + startables.forEach { it.stop() } super.afterSpec(spec) } } diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerTestListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt similarity index 52% rename from modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerTestListener.kt rename to modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt index 0285a001a19..8bdd374331a 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/ContainerPerTestListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt @@ -3,27 +3,28 @@ package org.testcontainers.containers import io.kotest.core.listeners.TestListener import io.kotest.core.test.TestCase import io.kotest.core.test.TestResult +import org.testcontainers.lifecycle.Startable /** - * [ContainerPerTestListener] starts the given [genericContainers] before execution of each test in the spec + * [StartablePerTestListener] starts the given [startables] before execution of each test in the spec * and stops after execution of each test. * - * [genericContainers] can any of [GenericContainer] [ContainerisedDockerCompose] [LocalStackContainer] etc. + * [startables] can any of [GenericContainer] [ContainerisedDockerCompose] [LocalStackContainer] etc. * * This should be use when you want fresh container for each test. * - * @see[ContainerPerSpecListener] + * @see[StartablePerSpecListener] * */ -class ContainerPerTestListener(private vararg val genericContainers: GenericContainer) : TestListener { +class StartablePerTestListener(private vararg val startables: Startable) : TestListener { override suspend fun beforeTest(testCase: TestCase) { - genericContainers.forEach { it.start() } + startables.forEach { it.start() } super.beforeTest(testCase) } override suspend fun afterTest(testCase: TestCase, result: TestResult) { - genericContainers.forEach { it.stop() } + startables.forEach { it.stop() } super.afterTest(testCase, result) } } diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerSpecListenerTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerSpecListenerTest.kt deleted file mode 100644 index f57f53a9bb3..00000000000 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerSpecListenerTest.kt +++ /dev/null @@ -1,27 +0,0 @@ -import io.kotest.core.spec.style.StringSpec -import io.mockk.mockk -import io.mockk.verify -import org.testcontainers.containers.ContainerPerSpecListener -import org.testcontainers.containers.GenericContainer - -class ContainerPerSpecListenerTest : StringSpec() { - init { - "should stop container in beforeSpec callback" { - val mockContainer: GenericContainer = mockk(relaxed = true) - val containerPerSpecListener = ContainerPerSpecListener(mockContainer) - - containerPerSpecListener.afterSpec(mockk()) - - verify(exactly = 1) { mockContainer.stop() } - } - - "should start container in afterSpec callback" { - val mockContainer: GenericContainer = mockk(relaxed = true) - val containerPerSpecListener = ContainerPerSpecListener(mockContainer) - - containerPerSpecListener.beforeSpec(mockk()) - - verify(exactly = 1) { mockContainer.start() } - } - } -} diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerTestListenerTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerTestListenerTest.kt deleted file mode 100644 index b0c14299f05..00000000000 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/ContainerPerTestListenerTest.kt +++ /dev/null @@ -1,27 +0,0 @@ -import io.kotest.core.spec.style.StringSpec -import io.mockk.mockk -import io.mockk.verify -import org.testcontainers.containers.ContainerPerTestListener -import org.testcontainers.containers.GenericContainer - -class ContainerPerTestListenerTest: StringSpec() { - init { - "should start container in beforeTest callback" { - val mockContainer: GenericContainer = mockk(relaxed = true) - val containerPerTestListener = ContainerPerTestListener(mockContainer) - - containerPerTestListener.beforeTest(mockk()) - - verify(exactly = 1) { mockContainer.start() } - } - - "should stop container in afterTest callback" { - val mockContainer: GenericContainer = mockk(relaxed = true) - val containerPerTestListener = ContainerPerTestListener(mockContainer) - - containerPerTestListener.afterTest(mockk(), mockk()) - - verify(exactly = 1) { mockContainer.stop() } - } - } -} diff --git a/docs/examples/kotest/src/test/kotlin/com/example/kotest/TestContainerKotestIntegrationPerTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt similarity index 85% rename from docs/examples/kotest/src/test/kotlin/com/example/kotest/TestContainerKotestIntegrationPerTest.kt rename to modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt index 434b55b76d2..5dc4683e20a 100644 --- a/docs/examples/kotest/src/test/kotlin/com/example/kotest/TestContainerKotestIntegrationPerTest.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt @@ -1,17 +1,15 @@ -package com.example.kotest +package org.testcontainers.containers import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe import kotlinx.coroutines.delay -import org.testcontainers.containers.ContainerPerTestListener -import org.testcontainers.containers.GenericContainer class TestContainerKotestIntegrationPerTest : StringSpec({ val container = GenericContainer("ubuntu") setContainerCommand(container) // Set container command for first time to echo hello Kotest // Register the Listener - listeners(ContainerPerTestListener(container)) + listeners(container.perTest()) "test should echo hello Kotest for first test" { container.logs.trim() shouldBe "hello Kotest" diff --git a/docs/examples/kotest/src/test/kotlin/com/example/kotest/TestcontainerKotestIntegrationPerSpec.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestcontainerKotestIntegrationPerSpec.kt similarity index 81% rename from docs/examples/kotest/src/test/kotlin/com/example/kotest/TestcontainerKotestIntegrationPerSpec.kt rename to modules/kotest/src/test/kotlin/org/testcontainers/containers/TestcontainerKotestIntegrationPerSpec.kt index 6a81b2906f8..4c88d7a660b 100644 --- a/docs/examples/kotest/src/test/kotlin/com/example/kotest/TestcontainerKotestIntegrationPerSpec.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestcontainerKotestIntegrationPerSpec.kt @@ -1,23 +1,19 @@ -package com.example.kotest +package org.testcontainers.containers import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe -import kotlinx.coroutines.delay -import org.testcontainers.containers.ContainerPerSpecListener -import org.testcontainers.containers.GenericContainer class TestcontainerKotestIntegrationPerSpec : StringSpec({ val container = GenericContainer("ubuntu") setContainerCommand(container) // Set container command for first time to echo hello Kotest // Register the Listener - listeners(ContainerPerSpecListener(container)) + listeners(container.perSpec()) "test should echo hello Kotest for first test" { container.logs.trim() shouldBe "hello Kotest" // Set container command so that next time when container start we will have hello Kotest again in container log setContainerCommand(container) - delay(1000) } "test should echo hello Kotest for second spec as well" { diff --git a/settings.gradle b/settings.gradle index 968120b9fda..5ec35718ef6 100644 --- a/settings.gradle +++ b/settings.gradle @@ -54,7 +54,6 @@ include ':docs:examples:junit4:generic' include ':docs:examples:junit4:redis' include ':docs:examples:junit5:redis' include ':docs:examples:spock:redis' -include ':docs:examples:kotest' include 'test-support' From 2e7bb5852a66c978867e995ba8daa53f74e6a47b Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Tue, 21 Apr 2020 09:28:22 +0530 Subject: [PATCH 07/21] Removes mockk dependency --- modules/kotest/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/kotest/build.gradle b/modules/kotest/build.gradle index 0e10e141685..393b72ee5fc 100644 --- a/modules/kotest/build.gradle +++ b/modules/kotest/build.gradle @@ -18,7 +18,6 @@ dependencies { api("io.kotest:kotest-runner-junit5-jvm:$kotestVersion") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") testImplementation("io.kotest:kotest-assertions-core-jvm:$kotestVersion") - testImplementation("io.mockk:mockk:1.9.3") } From b75fcc3d910d5bdc49536a28e2ed40cecdc0b4ef Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Tue, 21 Apr 2020 15:06:20 +0530 Subject: [PATCH 08/21] Removes delay between test and use alpine image for containers --- .../containers/TestContainerKotestIntegrationPerTest.kt | 6 +++--- .../containers/TestcontainerKotestIntegrationPerSpec.kt | 4 +++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt index 5dc4683e20a..883ee9cd522 100644 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt @@ -2,10 +2,11 @@ package org.testcontainers.containers import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe -import kotlinx.coroutines.delay +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy class TestContainerKotestIntegrationPerTest : StringSpec({ - val container = GenericContainer("ubuntu") + val container = GenericContainer("alpine") + container.withStartupCheckStrategy(OneShotStartupCheckStrategy()) setContainerCommand(container) // Set container command for first time to echo hello Kotest // Register the Listener @@ -15,7 +16,6 @@ class TestContainerKotestIntegrationPerTest : StringSpec({ container.logs.trim() shouldBe "hello Kotest" // Set container command so that next time when container start we will have hello Kotest again in container log setContainerCommand(container) - delay(1000) } "test should echo hello Kotest for second spec as well" { diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestcontainerKotestIntegrationPerSpec.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestcontainerKotestIntegrationPerSpec.kt index 4c88d7a660b..4ecae6bbb2a 100644 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestcontainerKotestIntegrationPerSpec.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestcontainerKotestIntegrationPerSpec.kt @@ -2,9 +2,11 @@ package org.testcontainers.containers import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe +import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy class TestcontainerKotestIntegrationPerSpec : StringSpec({ - val container = GenericContainer("ubuntu") + val container = GenericContainer("alpine") + container.withStartupCheckStrategy(OneShotStartupCheckStrategy()) setContainerCommand(container) // Set container command for first time to echo hello Kotest // Register the Listener From 636567ab12b973f8086b8928982803e51a01b93b Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Tue, 21 Apr 2020 15:15:36 +0530 Subject: [PATCH 09/21] Makes StartablePerSpecListener and StartablePerTestListener as private --- .../containers/StartablePerSpecListener.kt | 10 ++++----- .../containers/StartablePerTestListener.kt | 22 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt index e25573fc0c9..23975f49f41 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt @@ -6,10 +6,10 @@ import org.testcontainers.lifecycle.Startable /** - * [StartablePerSpecListener] starts the given [startables] before execution of any test in the spec + * [StartablePerSpecListener] starts the given [startable] before execution of any test in the spec * and stops after execution of all tests. * - * [startables] can any of [GenericContainer] [ContainerisedDockerCompose] [LocalStackContainer] etc. + * [startable] can any of [GenericContainer] [DockerComposeContainer] [LocalStackContainer] etc. * * This should be use when you want to a single container for all test in a single test class. * @@ -17,14 +17,14 @@ import org.testcontainers.lifecycle.Startable * [StartablePerTestListener] * */ -class StartablePerSpecListener(private vararg val startables: Startable) : TestListener { +private class StartablePerSpecListener(private vararg val startable: Startable) : TestListener { override suspend fun beforeSpec(spec: Spec) { - startables.forEach { it.start() } + startable.forEach { it.start() } super.beforeSpec(spec) } override suspend fun afterSpec(spec: Spec) { - startables.forEach { it.stop() } + startable.forEach { it.stop() } super.afterSpec(spec) } } diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt index 8bdd374331a..74b4e6e9862 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt @@ -7,24 +7,24 @@ import org.testcontainers.lifecycle.Startable /** - * [StartablePerTestListener] starts the given [startables] before execution of each test in the spec + * [StartablePerTestListener] starts the given [startable] before execution of each test in the spec * and stops after execution of each test. * - * [startables] can any of [GenericContainer] [ContainerisedDockerCompose] [LocalStackContainer] etc. + * [startable] can any of [GenericContainer] [DockerComposeContainer] [LocalStackContainer] etc. * * This should be use when you want fresh container for each test. * * @see[StartablePerSpecListener] * */ -class StartablePerTestListener(private vararg val startables: Startable) : TestListener { +private class StartablePerTestListener(private vararg val startable: Startable) : TestListener { - override suspend fun beforeTest(testCase: TestCase) { - startables.forEach { it.start() } - super.beforeTest(testCase) - } + override suspend fun beforeTest(testCase: TestCase) { + startable.forEach { it.start() } + super.beforeTest(testCase) + } - override suspend fun afterTest(testCase: TestCase, result: TestResult) { - startables.forEach { it.stop() } - super.afterTest(testCase, result) - } + override suspend fun afterTest(testCase: TestCase, result: TestResult) { + startable.forEach { it.stop() } + super.afterTest(testCase, result) + } } From fbfecb3a97c963b66159eec76562b26fb5580a8c Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Tue, 21 Apr 2020 16:31:19 +0530 Subject: [PATCH 10/21] Removes private keyword from StartablePerSpecListener and StartablePerSpecListener as that causes compilation errors --- .../testcontainers/containers/StartablePerSpecListener.kt | 7 +++++-- .../testcontainers/containers/StartablePerTestListener.kt | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt index 23975f49f41..29c0a160b02 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt @@ -2,6 +2,7 @@ package org.testcontainers.containers import io.kotest.core.listeners.TestListener import io.kotest.core.spec.Spec +import kotlinx.coroutines.coroutineScope import org.testcontainers.lifecycle.Startable @@ -17,9 +18,11 @@ import org.testcontainers.lifecycle.Startable * [StartablePerTestListener] * */ -private class StartablePerSpecListener(private vararg val startable: Startable) : TestListener { +class StartablePerSpecListener(private vararg val startable: Startable) : TestListener { override suspend fun beforeSpec(spec: Spec) { - startable.forEach { it.start() } + coroutineScope { + startable.forEach { it.start() } + } super.beforeSpec(spec) } diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt index 74b4e6e9862..73a4c0e4f59 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt @@ -16,7 +16,7 @@ import org.testcontainers.lifecycle.Startable * * @see[StartablePerSpecListener] * */ -private class StartablePerTestListener(private vararg val startable: Startable) : TestListener { +class StartablePerTestListener(private vararg val startable: Startable) : TestListener { override suspend fun beforeTest(testCase: TestCase) { startable.forEach { it.start() } From 3bfdc0648382b40b5db4dca9b16e916a9175038c Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Tue, 21 Apr 2020 17:22:07 +0530 Subject: [PATCH 11/21] Replace container based test with mock implementation of startable --- .../TestContainerKotestIntegrationPerTest.kt | 32 ++++--------------- .../containers/TestStartable.kt | 12 +++++++ .../TestcontainerKotestIntegrationPerSpec.kt | 32 ++++--------------- 3 files changed, 24 insertions(+), 52 deletions(-) create mode 100644 modules/kotest/src/test/kotlin/org/testcontainers/containers/TestStartable.kt diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt index 883ee9cd522..2b239d465f3 100644 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt @@ -2,36 +2,16 @@ package org.testcontainers.containers import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe -import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy class TestContainerKotestIntegrationPerTest : StringSpec({ - val container = GenericContainer("alpine") - container.withStartupCheckStrategy(OneShotStartupCheckStrategy()) - setContainerCommand(container) // Set container command for first time to echo hello Kotest + val testStartable = TestStartable() + listeners(testStartable.perSpec()) - // Register the Listener - listeners(container.perTest()) - - "test should echo hello Kotest for first test" { - container.logs.trim() shouldBe "hello Kotest" - // Set container command so that next time when container start we will have hello Kotest again in container log - setContainerCommand(container) + "start count for first test should be one" { + testStartable.startCount shouldBe 1 } - "test should echo hello Kotest for second spec as well" { - // presence of hello Kotest again verifies that container is restarted. - container.logs.trim() shouldBe "hello Kotest again" + "start count for second test should be two" { + testStartable.startCount shouldBe 2 } - }) - -private var testCount = 0 -private fun setContainerCommand(container: GenericContainer) { - if (testCount == 0) { - container.setCommand("echo", "hello Kotest") - testCount += 1 - } else { - container.setCommand("echo", "hello Kotest again") - } -} - diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestStartable.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestStartable.kt new file mode 100644 index 00000000000..092edc6831e --- /dev/null +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestStartable.kt @@ -0,0 +1,12 @@ +package org.testcontainers.containers + +import org.testcontainers.lifecycle.Startable + +internal class TestStartable : Startable { + var startCount = 0 + override fun start() { + startCount++ + } + override fun stop() { + } +} diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestcontainerKotestIntegrationPerSpec.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestcontainerKotestIntegrationPerSpec.kt index 4ecae6bbb2a..2d14f696c82 100644 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestcontainerKotestIntegrationPerSpec.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestcontainerKotestIntegrationPerSpec.kt @@ -2,36 +2,16 @@ package org.testcontainers.containers import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe -import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy class TestcontainerKotestIntegrationPerSpec : StringSpec({ - val container = GenericContainer("alpine") - container.withStartupCheckStrategy(OneShotStartupCheckStrategy()) - setContainerCommand(container) // Set container command for first time to echo hello Kotest + val testStartable = TestStartable() + listeners(testStartable.perSpec()) - // Register the Listener - listeners(container.perSpec()) - - "test should echo hello Kotest for first test" { - container.logs.trim() shouldBe "hello Kotest" - // Set container command so that next time when container start we will have hello Kotest again in container log - setContainerCommand(container) + "start count for first test should be one" { + testStartable.startCount shouldBe 1 } - "test should echo hello Kotest for second spec as well" { - // presence of "hello Kotest" verifies that container is not restarted. - container.logs.trim() shouldBe "hello Kotest" + "start count for second test should also be one" { + testStartable.startCount shouldBe 1 } - }) - -private var testCount = 0 -private fun setContainerCommand(container: GenericContainer) { - if (testCount == 0) { - container.setCommand("echo", "hello Kotest") - testCount += 1 - } else { - container.setCommand("echo", "hello Kotest again") - } -} - From e9b3a61b09266970eacbf41752ed16ffbaf2cf39 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Tue, 21 Apr 2020 17:41:59 +0530 Subject: [PATCH 12/21] Fixes failing test --- .../containers/TestContainerKotestIntegrationPerTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt index 2b239d465f3..5670ebbf228 100644 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestContainerKotestIntegrationPerTest.kt @@ -5,7 +5,7 @@ import io.kotest.matchers.shouldBe class TestContainerKotestIntegrationPerTest : StringSpec({ val testStartable = TestStartable() - listeners(testStartable.perSpec()) + listeners(testStartable.perTest()) "start count for first test should be one" { testStartable.startCount shouldBe 1 From 14c514c40dcb76b2414848c1cc5c5bd4b329c1b7 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Tue, 21 Apr 2020 18:22:09 +0530 Subject: [PATCH 13/21] Makes StartablePerSpecListener and StartablePerTestListener internal and start-stop startable in IO coroutine context --- .../org/testcontainers/containers/Extensions.kt | 5 +++-- .../containers/StartablePerSpecListener.kt | 15 ++++++++------- .../containers/StartablePerTestListener.kt | 14 +++++++++----- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt index 6191022f4fc..2701a2e601e 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt @@ -1,6 +1,7 @@ package org.testcontainers.containers +import io.kotest.core.listeners.TestListener import org.testcontainers.lifecycle.Startable -fun Startable.perTest() = StartablePerTestListener(this) -fun Startable.perSpec() = StartablePerSpecListener(this) +fun Startable.perTest(): TestListener = StartablePerTestListener(this) +fun Startable.perSpec(): TestListener = StartablePerSpecListener(this) diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt index 29c0a160b02..f96848f5220 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt @@ -2,7 +2,8 @@ package org.testcontainers.containers import io.kotest.core.listeners.TestListener import io.kotest.core.spec.Spec -import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import org.testcontainers.lifecycle.Startable @@ -18,16 +19,16 @@ import org.testcontainers.lifecycle.Startable * [StartablePerTestListener] * */ -class StartablePerSpecListener(private vararg val startable: Startable) : TestListener { +internal class StartablePerSpecListener(private val startable: Startable) : TestListener { override suspend fun beforeSpec(spec: Spec) { - coroutineScope { - startable.forEach { it.start() } + withContext(Dispatchers.IO) { + startable.start() } - super.beforeSpec(spec) } override suspend fun afterSpec(spec: Spec) { - startable.forEach { it.stop() } - super.afterSpec(spec) + withContext(Dispatchers.IO) { + startable.stop() + } } } diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt index 73a4c0e4f59..5b84eb3acc6 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt @@ -3,6 +3,8 @@ package org.testcontainers.containers import io.kotest.core.listeners.TestListener import io.kotest.core.test.TestCase import io.kotest.core.test.TestResult +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import org.testcontainers.lifecycle.Startable @@ -16,15 +18,17 @@ import org.testcontainers.lifecycle.Startable * * @see[StartablePerSpecListener] * */ -class StartablePerTestListener(private vararg val startable: Startable) : TestListener { +internal class StartablePerTestListener(private val startable: Startable) : TestListener { override suspend fun beforeTest(testCase: TestCase) { - startable.forEach { it.start() } - super.beforeTest(testCase) + withContext(Dispatchers.IO) { + startable.start() + } } override suspend fun afterTest(testCase: TestCase, result: TestResult) { - startable.forEach { it.stop() } - super.afterTest(testCase, result) + withContext(Dispatchers.IO) { + startable.stop() + } } } From 4d93f7d87e780e9975c8e46be9b1c50f63802900 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Tue, 21 Apr 2020 18:22:52 +0530 Subject: [PATCH 14/21] Adds support for TestLifecycleAware --- .../testcontainers/containers/Extensions.kt | 2 ++ .../containers/TestLifecycleAwareListener.kt | 36 +++++++++++++++++++ .../TestLifecycleAwareListenerTest.kt | 27 ++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt create mode 100644 modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt index 2701a2e601e..e3793a5aec0 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt @@ -2,6 +2,8 @@ package org.testcontainers.containers import io.kotest.core.listeners.TestListener import org.testcontainers.lifecycle.Startable +import org.testcontainers.lifecycle.TestLifecycleAware fun Startable.perTest(): TestListener = StartablePerTestListener(this) fun Startable.perSpec(): TestListener = StartablePerSpecListener(this) +fun TestLifecycleAware.perTest(): TestListener = TestLifecycleAwareListener(this) diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt new file mode 100644 index 00000000000..f81ef608310 --- /dev/null +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt @@ -0,0 +1,36 @@ +package org.testcontainers.containers + +import io.kotest.core.listeners.TestListener +import io.kotest.core.test.TestCase +import io.kotest.core.test.TestResult +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.testcontainers.lifecycle.TestDescription +import org.testcontainers.lifecycle.TestLifecycleAware +import java.util.* + +internal class TestLifecycleAwareListener(private val testLifecycleAware: TestLifecycleAware) : TestListener { + override suspend fun beforeTest(testCase: TestCase) { + withContext(Dispatchers.IO) { + testLifecycleAware.beforeTest(testCase.toTestDescription()) + } + } + + override suspend fun afterTest(testCase: TestCase, result: TestResult) { + withContext(Dispatchers.IO) { + testLifecycleAware.afterTest(testCase.toTestDescription(), Optional.ofNullable(result.error)) + } + } +} + +private fun TestCase.toTestDescription() = object : TestDescription { + + override fun getFilesystemFriendlyName(): String { + return name.replace(" ", "-") + } + + override fun getTestId(): String { + return description.id() + } +} + diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt new file mode 100644 index 00000000000..14518190d82 --- /dev/null +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt @@ -0,0 +1,27 @@ +package org.testcontainers.containers + +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.shouldBe +import org.testcontainers.lifecycle.TestDescription +import org.testcontainers.lifecycle.TestLifecycleAware + +class TestLifecycleAwareListenerTest : StringSpec({ + val mockTestLifecycleAware = MockTestLifecycleAware() + listener(mockTestLifecycleAware.perTest()) + + "beforeTestCalledCount for first test should be one" { + mockTestLifecycleAware.beforeTestCalledCount shouldBe 1 + } + + "beforeTestCalledCount for second test should be two" { + mockTestLifecycleAware.beforeTestCalledCount shouldBe 2 + } +}) + +private class MockTestLifecycleAware : TestLifecycleAware { + var beforeTestCalledCount = 0 + + override fun beforeTest(description: TestDescription?) { + beforeTestCalledCount++ + } +} From f03e1c19b814dcb25a3ea0e8163c924c25d1f677 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Tue, 21 Apr 2020 20:42:58 +0530 Subject: [PATCH 15/21] Removes TestLifecycleAwareListener and call TestLifecycleAware methods in per test listener --- .../testcontainers/containers/Extensions.kt | 2 -- .../containers/StartablePerTestListener.kt | 28 +++++++++++++++ .../containers/TestLifecycleAwareListener.kt | 36 ------------------- .../containers/StartableTestLifecycleAware.kt | 16 +++++++++ .../TestLifecycleAwareListenerTest.kt | 27 -------------- .../containers/TestLifecycleAwareTest.kt | 17 +++++++++ .../containers/TestStartable.kt | 2 +- 7 files changed, 62 insertions(+), 66 deletions(-) delete mode 100644 modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt create mode 100644 modules/kotest/src/test/kotlin/org/testcontainers/containers/StartableTestLifecycleAware.kt delete mode 100644 modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt create mode 100644 modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt index e3793a5aec0..2701a2e601e 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/Extensions.kt @@ -2,8 +2,6 @@ package org.testcontainers.containers import io.kotest.core.listeners.TestListener import org.testcontainers.lifecycle.Startable -import org.testcontainers.lifecycle.TestLifecycleAware fun Startable.perTest(): TestListener = StartablePerTestListener(this) fun Startable.perSpec(): TestListener = StartablePerSpecListener(this) -fun TestLifecycleAware.perTest(): TestListener = TestLifecycleAwareListener(this) diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt index 5b84eb3acc6..8e60a253955 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt @@ -6,6 +6,9 @@ import io.kotest.core.test.TestResult import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.testcontainers.lifecycle.Startable +import org.testcontainers.lifecycle.TestDescription +import org.testcontainers.lifecycle.TestLifecycleAware +import java.util.* /** @@ -22,13 +25,38 @@ internal class StartablePerTestListener(private val startable: Startable) : Test override suspend fun beforeTest(testCase: TestCase) { withContext(Dispatchers.IO) { + runBeforeTestForTestLifecycleAware(testCase) startable.start() } } override suspend fun afterTest(testCase: TestCase, result: TestResult) { withContext(Dispatchers.IO) { + runAfterTestForTestLifecycleAware(testCase, result) startable.stop() } } + + private fun runBeforeTestForTestLifecycleAware(testCase: TestCase) { + startable.toTestLifecycleAware()?.beforeTest(testCase.toTestDescription()) + } + + private fun runAfterTestForTestLifecycleAware(testCase: TestCase, result: TestResult) { + startable.toTestLifecycleAware()?.afterTest(testCase.toTestDescription(), Optional.ofNullable(result.error)) + } + + private fun Startable.toTestLifecycleAware() = this as? TestLifecycleAware } + + +private fun TestCase.toTestDescription() = object : TestDescription { + + override fun getFilesystemFriendlyName(): String { + return name.replace(" ", "-") + } + + override fun getTestId(): String { + return description.id() + } +} + diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt deleted file mode 100644 index f81ef608310..00000000000 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.testcontainers.containers - -import io.kotest.core.listeners.TestListener -import io.kotest.core.test.TestCase -import io.kotest.core.test.TestResult -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import org.testcontainers.lifecycle.TestDescription -import org.testcontainers.lifecycle.TestLifecycleAware -import java.util.* - -internal class TestLifecycleAwareListener(private val testLifecycleAware: TestLifecycleAware) : TestListener { - override suspend fun beforeTest(testCase: TestCase) { - withContext(Dispatchers.IO) { - testLifecycleAware.beforeTest(testCase.toTestDescription()) - } - } - - override suspend fun afterTest(testCase: TestCase, result: TestResult) { - withContext(Dispatchers.IO) { - testLifecycleAware.afterTest(testCase.toTestDescription(), Optional.ofNullable(result.error)) - } - } -} - -private fun TestCase.toTestDescription() = object : TestDescription { - - override fun getFilesystemFriendlyName(): String { - return name.replace(" ", "-") - } - - override fun getTestId(): String { - return description.id() - } -} - diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/StartableTestLifecycleAware.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/StartableTestLifecycleAware.kt new file mode 100644 index 00000000000..e1d4ac6b35b --- /dev/null +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/StartableTestLifecycleAware.kt @@ -0,0 +1,16 @@ +package org.testcontainers.containers + +import org.testcontainers.lifecycle.TestDescription +import org.testcontainers.lifecycle.TestLifecycleAware +import java.util.* + +internal class StartableTestLifecycleAware : TestStartable(), TestLifecycleAware { + var beforeTestCount = 0 + + override fun beforeTest(description: TestDescription?) { + beforeTestCount++ + } + + override fun afterTest(description: TestDescription?, throwable: Optional?) { + } +} diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt deleted file mode 100644 index 14518190d82..00000000000 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt +++ /dev/null @@ -1,27 +0,0 @@ -package org.testcontainers.containers - -import io.kotest.core.spec.style.StringSpec -import io.kotest.matchers.shouldBe -import org.testcontainers.lifecycle.TestDescription -import org.testcontainers.lifecycle.TestLifecycleAware - -class TestLifecycleAwareListenerTest : StringSpec({ - val mockTestLifecycleAware = MockTestLifecycleAware() - listener(mockTestLifecycleAware.perTest()) - - "beforeTestCalledCount for first test should be one" { - mockTestLifecycleAware.beforeTestCalledCount shouldBe 1 - } - - "beforeTestCalledCount for second test should be two" { - mockTestLifecycleAware.beforeTestCalledCount shouldBe 2 - } -}) - -private class MockTestLifecycleAware : TestLifecycleAware { - var beforeTestCalledCount = 0 - - override fun beforeTest(description: TestDescription?) { - beforeTestCalledCount++ - } -} diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt new file mode 100644 index 00000000000..c3bb7665407 --- /dev/null +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt @@ -0,0 +1,17 @@ +package org.testcontainers.containers + +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.shouldBe + +class TestLifecycleAwareListenerTest : StringSpec({ + val startableTestLifecycleAware = StartableTestLifecycleAware() + listener(startableTestLifecycleAware.perTest()) + + "beforeTestCount for first test should be one" { + startableTestLifecycleAware.beforeTestCount shouldBe 1 + } + + "beforeTestCount for second test should be two" { + startableTestLifecycleAware.beforeTestCount shouldBe 2 + } +}) diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestStartable.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestStartable.kt index 092edc6831e..32abd20af06 100644 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestStartable.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestStartable.kt @@ -2,7 +2,7 @@ package org.testcontainers.containers import org.testcontainers.lifecycle.Startable -internal class TestStartable : Startable { +internal open class TestStartable : Startable { var startCount = 0 override fun start() { startCount++ From 38b686289075b9e0573c8ed5656d31986c65e66f Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Tue, 21 Apr 2020 20:46:01 +0530 Subject: [PATCH 16/21] Updates doc --- .../org/testcontainers/containers/StartablePerTestListener.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt index 8e60a253955..3e968d78310 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt @@ -13,7 +13,8 @@ import java.util.* /** * [StartablePerTestListener] starts the given [startable] before execution of each test in the spec - * and stops after execution of each test. + * and stops after execution of each test. If the [startable] also inherit from [TestLifecycleAware] + * then its [beforeTest] and [afterTest] method are also called by the listener. * * [startable] can any of [GenericContainer] [DockerComposeContainer] [LocalStackContainer] etc. * From 5572b99f7afc095bd0d6d1f18d00ee045e92db66 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Tue, 21 Apr 2020 21:58:27 +0530 Subject: [PATCH 17/21] Adds test around test descriptor name --- .../containers/StartableTestLifecycleAware.kt | 4 ++-- .../containers/TestLifecycleAwareTest.kt | 11 +++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/StartableTestLifecycleAware.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/StartableTestLifecycleAware.kt index e1d4ac6b35b..eff76f6a5db 100644 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/StartableTestLifecycleAware.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/StartableTestLifecycleAware.kt @@ -5,10 +5,10 @@ import org.testcontainers.lifecycle.TestLifecycleAware import java.util.* internal class StartableTestLifecycleAware : TestStartable(), TestLifecycleAware { - var beforeTestCount = 0 + val testDescriptions = mutableListOf() override fun beforeTest(description: TestDescription?) { - beforeTestCount++ + testDescriptions.add(description) } override fun afterTest(description: TestDescription?, throwable: Optional?) { diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt index c3bb7665407..ac993bf5bca 100644 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt @@ -1,6 +1,7 @@ package org.testcontainers.containers import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.shouldBe class TestLifecycleAwareListenerTest : StringSpec({ @@ -8,10 +9,16 @@ class TestLifecycleAwareListenerTest : StringSpec({ listener(startableTestLifecycleAware.perTest()) "beforeTestCount for first test should be one" { - startableTestLifecycleAware.beforeTestCount shouldBe 1 + startableTestLifecycleAware.testDescriptions shouldHaveSize 1 } "beforeTestCount for second test should be two" { - startableTestLifecycleAware.beforeTestCount shouldBe 2 + startableTestLifecycleAware.testDescriptions shouldHaveSize 2 + } + + "test id in test description should be combination of test name and package name" { + val testDescription = startableTestLifecycleAware.testDescriptions[2] + testDescription?.testId shouldBe "org.testcontainers.containers.TestLifecycleAwareListenerTest/test id in test" + + " description should be combination of test name and package name" } }) From 439876a616692ab7e80535e1bd7f0b590efc3002 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Tue, 21 Apr 2020 22:35:05 +0530 Subject: [PATCH 18/21] Encode test name to make it filesystemFriendlyName and updates docs --- .../testcontainers/containers/StartablePerSpecListener.kt | 2 +- .../testcontainers/containers/StartablePerTestListener.kt | 5 +++-- .../testcontainers/containers/TestLifecycleAwareTest.kt | 7 +++++++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt index f96848f5220..6895d38ea07 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt @@ -13,7 +13,7 @@ import org.testcontainers.lifecycle.Startable * * [startable] can any of [GenericContainer] [DockerComposeContainer] [LocalStackContainer] etc. * - * This should be use when you want to a single container for all test in a single test class. + * This listener should be used when you want to use a single container for all tests in a single spec class. * * @see * [StartablePerTestListener] diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt index 3e968d78310..5d5caae943d 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt @@ -8,6 +8,7 @@ import kotlinx.coroutines.withContext import org.testcontainers.lifecycle.Startable import org.testcontainers.lifecycle.TestDescription import org.testcontainers.lifecycle.TestLifecycleAware +import java.net.URLEncoder import java.util.* @@ -18,7 +19,7 @@ import java.util.* * * [startable] can any of [GenericContainer] [DockerComposeContainer] [LocalStackContainer] etc. * - * This should be use when you want fresh container for each test. + * This should be used when you want a fresh container for each test. * * @see[StartablePerSpecListener] * */ @@ -53,7 +54,7 @@ internal class StartablePerTestListener(private val startable: Startable) : Test private fun TestCase.toTestDescription() = object : TestDescription { override fun getFilesystemFriendlyName(): String { - return name.replace(" ", "-") + return URLEncoder.encode(name, "UTF-8") } override fun getTestId(): String { diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt index ac993bf5bca..c455d033fc5 100644 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt @@ -21,4 +21,11 @@ class TestLifecycleAwareListenerTest : StringSpec({ testDescription?.testId shouldBe "org.testcontainers.containers.TestLifecycleAwareListenerTest/test id in test" + " description should be combination of test name and package name" } + + "fileSystemFriendlyName in test description should be encoded test name" { + val testDescription = startableTestLifecycleAware.testDescriptions[3] + val encodedTestName = "fileSystemFriendlyName+in+test+description+should+be+encoded+test+name" + + testDescription?.filesystemFriendlyName shouldBe encodedTestName + } }) From 2bd5127f68b1ae197ac3aaad6ebdfba5af9bd2d7 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Sat, 25 Apr 2020 14:50:51 +0530 Subject: [PATCH 19/21] Moves TestLifecycleAwareListener in a separate file --- .../containers/StartablePerTestListener.kt | 30 ++--------------- .../containers/TestLifecycleAwareListener.kt | 33 +++++++++++++++++++ 2 files changed, 36 insertions(+), 27 deletions(-) create mode 100644 modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt index 5d5caae943d..43cb3c338e8 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerTestListener.kt @@ -6,10 +6,7 @@ import io.kotest.core.test.TestResult import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.testcontainers.lifecycle.Startable -import org.testcontainers.lifecycle.TestDescription import org.testcontainers.lifecycle.TestLifecycleAware -import java.net.URLEncoder -import java.util.* /** @@ -24,41 +21,20 @@ import java.util.* * @see[StartablePerSpecListener] * */ internal class StartablePerTestListener(private val startable: Startable) : TestListener { + private val testLifecycleAwareListener = TestLifecycleAwareListener(startable) override suspend fun beforeTest(testCase: TestCase) { withContext(Dispatchers.IO) { - runBeforeTestForTestLifecycleAware(testCase) + testLifecycleAwareListener.beforeTest(testCase) startable.start() } } override suspend fun afterTest(testCase: TestCase, result: TestResult) { withContext(Dispatchers.IO) { - runAfterTestForTestLifecycleAware(testCase, result) + testLifecycleAwareListener.afterTest(testCase, result) startable.stop() } } - - private fun runBeforeTestForTestLifecycleAware(testCase: TestCase) { - startable.toTestLifecycleAware()?.beforeTest(testCase.toTestDescription()) - } - - private fun runAfterTestForTestLifecycleAware(testCase: TestCase, result: TestResult) { - startable.toTestLifecycleAware()?.afterTest(testCase.toTestDescription(), Optional.ofNullable(result.error)) - } - - private fun Startable.toTestLifecycleAware() = this as? TestLifecycleAware -} - - -private fun TestCase.toTestDescription() = object : TestDescription { - - override fun getFilesystemFriendlyName(): String { - return URLEncoder.encode(name, "UTF-8") - } - - override fun getTestId(): String { - return description.id() - } } diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt new file mode 100644 index 00000000000..7ba1da1ad7b --- /dev/null +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt @@ -0,0 +1,33 @@ +package org.testcontainers.containers + +import io.kotest.core.listeners.TestListener +import io.kotest.core.test.TestCase +import io.kotest.core.test.TestResult +import org.testcontainers.lifecycle.Startable +import org.testcontainers.lifecycle.TestDescription +import org.testcontainers.lifecycle.TestLifecycleAware +import java.net.URLEncoder +import java.util.* + +class TestLifecycleAwareListener(startable: Startable) : TestListener { + private val testLifecycleAware = startable as? TestLifecycleAware + + override suspend fun beforeTest(testCase: TestCase) { + testLifecycleAware?.beforeTest(testCase.toTestDescription()) + } + + override suspend fun afterTest(testCase: TestCase, result: TestResult) { + testLifecycleAware?.afterTest(testCase.toTestDescription(), Optional.ofNullable(result.error)) + } +} + +private fun TestCase.toTestDescription() = object : TestDescription { + + override fun getFilesystemFriendlyName(): String { + return URLEncoder.encode(name, "UTF-8") + } + + override fun getTestId(): String { + return description.id() + } +} From cf4b30b144563c5fc7ac8cec909b6c4c4aeed2a7 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Sat, 25 Apr 2020 15:06:46 +0530 Subject: [PATCH 20/21] Adds TestLifecycleAware support in StartablePerSpecListener --- .../containers/StartablePerSpecListener.kt | 20 +++++++++++++++++- .../containers/TestLifecycleAwareListener.kt | 2 +- .../StartableTestLifecycleAwareTest.kt | 21 +++++++++++++++++++ ...t.kt => TestLifecycleAwareListenerTest.kt} | 19 ++++++----------- 4 files changed, 47 insertions(+), 15 deletions(-) create mode 100644 modules/kotest/src/test/kotlin/org/testcontainers/containers/StartableTestLifecycleAwareTest.kt rename modules/kotest/src/test/kotlin/org/testcontainers/containers/{TestLifecycleAwareTest.kt => TestLifecycleAwareListenerTest.kt} (56%) diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt index 6895d38ea07..fb66f608ff6 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/StartablePerSpecListener.kt @@ -2,14 +2,18 @@ package org.testcontainers.containers import io.kotest.core.listeners.TestListener import io.kotest.core.spec.Spec +import io.kotest.core.test.TestCase +import io.kotest.core.test.TestResult import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.testcontainers.lifecycle.Startable +import org.testcontainers.lifecycle.TestLifecycleAware /** * [StartablePerSpecListener] starts the given [startable] before execution of any test in the spec - * and stops after execution of all tests. + * and stops after execution of all tests. If the [startable] also inherit from [TestLifecycleAware] + * then its [beforeTest] and [afterTest] method are also called by the listener. * * [startable] can any of [GenericContainer] [DockerComposeContainer] [LocalStackContainer] etc. * @@ -20,15 +24,29 @@ import org.testcontainers.lifecycle.Startable * */ internal class StartablePerSpecListener(private val startable: Startable) : TestListener { + private val testLifecycleAwareListener = TestLifecycleAwareListener(startable) + override suspend fun beforeSpec(spec: Spec) { withContext(Dispatchers.IO) { startable.start() } } + override suspend fun beforeTest(testCase: TestCase) { + withContext(Dispatchers.IO) { + testLifecycleAwareListener.beforeTest(testCase) + } + } + override suspend fun afterSpec(spec: Spec) { withContext(Dispatchers.IO) { startable.stop() } } + + override suspend fun afterTest(testCase: TestCase, result: TestResult) { + withContext(Dispatchers.IO) { + testLifecycleAwareListener.afterTest(testCase, result) + } + } } diff --git a/modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt b/modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt index 7ba1da1ad7b..1640a58f33b 100644 --- a/modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt +++ b/modules/kotest/src/main/kotlin/org/testcontainers/containers/TestLifecycleAwareListener.kt @@ -9,7 +9,7 @@ import org.testcontainers.lifecycle.TestLifecycleAware import java.net.URLEncoder import java.util.* -class TestLifecycleAwareListener(startable: Startable) : TestListener { +internal class TestLifecycleAwareListener(startable: Startable) : TestListener { private val testLifecycleAware = startable as? TestLifecycleAware override suspend fun beforeTest(testCase: TestCase) { diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/StartableTestLifecycleAwareTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/StartableTestLifecycleAwareTest.kt new file mode 100644 index 00000000000..cfec9feb538 --- /dev/null +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/StartableTestLifecycleAwareTest.kt @@ -0,0 +1,21 @@ +package org.testcontainers.containers + +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.collections.shouldHaveSize + +class StartableTestLifecycleAwareTest : StringSpec({ + val startableTestLifecycleAwareForPerTest = StartableTestLifecycleAware() + val startableTestLifecycleAwareForPerSpec = StartableTestLifecycleAware() + + listeners(startableTestLifecycleAwareForPerTest.perTest(), startableTestLifecycleAwareForPerSpec.perSpec()) + + "beforeTestCount for first test should be one" { + startableTestLifecycleAwareForPerTest.testDescriptions shouldHaveSize 1 + startableTestLifecycleAwareForPerSpec.testDescriptions shouldHaveSize 1 + } + + "beforeTestCount for second test should be two" { + startableTestLifecycleAwareForPerTest.testDescriptions shouldHaveSize 2 + startableTestLifecycleAwareForPerTest.testDescriptions shouldHaveSize 2 + } +}) diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt similarity index 56% rename from modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt rename to modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt index c455d033fc5..9e055e08d7e 100644 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareTest.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt @@ -1,30 +1,23 @@ package org.testcontainers.containers import io.kotest.core.spec.style.StringSpec -import io.kotest.matchers.collections.shouldHaveSize import io.kotest.matchers.shouldBe class TestLifecycleAwareListenerTest : StringSpec({ val startableTestLifecycleAware = StartableTestLifecycleAware() - listener(startableTestLifecycleAware.perTest()) + val testLifecycleAwareListener = TestLifecycleAwareListener(startableTestLifecycleAware) - "beforeTestCount for first test should be one" { - startableTestLifecycleAware.testDescriptions shouldHaveSize 1 - } - - "beforeTestCount for second test should be two" { - startableTestLifecycleAware.testDescriptions shouldHaveSize 2 - } + listener(testLifecycleAwareListener) "test id in test description should be combination of test name and package name" { - val testDescription = startableTestLifecycleAware.testDescriptions[2] + val testDescription = startableTestLifecycleAware.testDescriptions[0] testDescription?.testId shouldBe "org.testcontainers.containers.TestLifecycleAwareListenerTest/test id in test" + " description should be combination of test name and package name" } - "fileSystemFriendlyName in test description should be encoded test name" { - val testDescription = startableTestLifecycleAware.testDescriptions[3] - val encodedTestName = "fileSystemFriendlyName+in+test+description+should+be+encoded+test+name" + "fileSystemFriendlyName .. in /// test description should be encoded test name" { + val testDescription = startableTestLifecycleAware.testDescriptions[1] + val encodedTestName = "fileSystemFriendlyName+..+in+%2F%2F%2F+test+description+should+be+encoded+test+name" testDescription?.filesystemFriendlyName shouldBe encodedTestName } From 64eda9ff74663ebd41d3d83f6a9375cde0ff149a Mon Sep 17 00:00:00 2001 From: Ashish Kumar Joy Date: Sat, 25 Apr 2020 15:47:49 +0530 Subject: [PATCH 21/21] Adds a test to verify TestLifecycleAwareListener does not fail when startable is not of type TestLifeCycleAware --- .../containers/TestLifecycleAwareListenerTest.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt index 9e055e08d7e..a2236b334c0 100644 --- a/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt +++ b/modules/kotest/src/test/kotlin/org/testcontainers/containers/TestLifecycleAwareListenerTest.kt @@ -5,18 +5,24 @@ import io.kotest.matchers.shouldBe class TestLifecycleAwareListenerTest : StringSpec({ val startableTestLifecycleAware = StartableTestLifecycleAware() + val startable = TestStartable() val testLifecycleAwareListener = TestLifecycleAwareListener(startableTestLifecycleAware) + val anotherTestLifecycleAwareListener = TestLifecycleAwareListener(startable) - listener(testLifecycleAwareListener) + listeners(testLifecycleAwareListener, anotherTestLifecycleAwareListener) + + "it should not break for listener having startable which is not of type testLifecycleAware" { + startable.startCount shouldBe 0 + } "test id in test description should be combination of test name and package name" { - val testDescription = startableTestLifecycleAware.testDescriptions[0] + val testDescription = startableTestLifecycleAware.testDescriptions[1] testDescription?.testId shouldBe "org.testcontainers.containers.TestLifecycleAwareListenerTest/test id in test" + " description should be combination of test name and package name" } "fileSystemFriendlyName .. in /// test description should be encoded test name" { - val testDescription = startableTestLifecycleAware.testDescriptions[1] + val testDescription = startableTestLifecycleAware.testDescriptions[2] val encodedTestName = "fileSystemFriendlyName+..+in+%2F%2F%2F+test+description+should+be+encoded+test+name" testDescription?.filesystemFriendlyName shouldBe encodedTestName