diff --git a/build.gradle.kts b/build.gradle.kts index b856f1a..b95e532 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -42,9 +42,11 @@ dependencies { api(libs.kafka.client) api(libs.hikari) + testImplementation(libs.logback) testImplementation(libs.kotest.assertions.core) testImplementation(libs.kotest.runner.junit5) testImplementation(libs.jedis) testImplementation(libs.testcontainers.mysql) + testImplementation(libs.testcontainers.redis) testImplementation(libs.mysql.connector.java) } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 6c5c44e..6167448 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -1,7 +1,14 @@ +import org.jetbrains.kotlin.gradle.dsl.JvmTarget + plugins { `kotlin-dsl` } +kotlin { + jvmToolchain(11) + compilerOptions.jvmTarget.set(JvmTarget.JVM_11) +} + repositories { mavenCentral() } diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts new file mode 100644 index 0000000..7913224 --- /dev/null +++ b/buildSrc/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name="buildSrc" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ab72ccd..dbde34d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,12 +9,14 @@ jedis = { module = "redis.clients:jedis", version = "4.3.1" } mysql-connector-java = { module = "mysql:mysql-connector-java", version = "8.0.33" } kafka-client = { module = "org.apache.kafka:kafka-clients", version = "3.5.1" } elastic-client = { module = "co.elastic.clients:elasticsearch-java", version = "7.17.21" } +logback = { module = "ch.qos.logback:logback-classic", version = "1.5.6" } testcontainers-elastic = { module = "org.testcontainers:elasticsearch", version.ref = "testcontainers" } testcontainers-mysql = { module = "org.testcontainers:mysql", version.ref = "testcontainers" } testcontainers-kafka = { module = "org.testcontainers:kafka", version.ref = "testcontainers" } testcontainers-jdbc = { module = "org.testcontainers:jdbc", version.ref = "testcontainers" } testcontainers-core = { module = "org.testcontainers:testcontainers", version.ref = "testcontainers" } +testcontainers-redis = { module = "com.redis:testcontainers-redis", version = "1.7.0" } kotest-runner-junit5 = { module = "io.kotest:kotest-runner-junit5", version.ref = "kotest" } kotest-assertions-core = { module = "io.kotest:kotest-assertions-core", version.ref = "kotest" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ac72c34..a441313 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/io/kotest/extensions/testcontainers/RuntimeSqlException.java b/src/main/java/io/kotest/extensions/testcontainers/RuntimeSqlException.java deleted file mode 100644 index 01553cf..0000000 --- a/src/main/java/io/kotest/extensions/testcontainers/RuntimeSqlException.java +++ /dev/null @@ -1,24 +0,0 @@ -package io.kotest.extensions.testcontainers; - -@Deprecated -class RuntimeSqlException extends RuntimeException { - - private static final long serialVersionUID = 5224696788505678598L; - - public RuntimeSqlException() { - super(); - } - - public RuntimeSqlException(String message) { - super(message); - } - - public RuntimeSqlException(String message, Throwable cause) { - super(message, cause); - } - - public RuntimeSqlException(Throwable cause) { - super(cause); - } - -} diff --git a/src/main/java/io/kotest/extensions/testcontainers/ScriptRunner.java b/src/main/java/io/kotest/extensions/testcontainers/ScriptRunner.java deleted file mode 100644 index 444d7c1..0000000 --- a/src/main/java/io/kotest/extensions/testcontainers/ScriptRunner.java +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Copyright 2009-2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.kotest.extensions.testcontainers; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.BufferedReader; -import java.io.Reader; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.SQLWarning; -import java.sql.Statement; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * This is an internal testing utility.
- * You are welcome to use this class for your own purposes,
- * but if there is some feature/enhancement you need for your own usage,
- * please make and modify your own copy instead of sending us an enhancement request.
- * - * @author Clinton Begin - * @deprecated - */ -@Deprecated -public class ScriptRunner { - - private static final String LINE_SEPARATOR = System.lineSeparator(); - - private static final String DEFAULT_DELIMITER = ";"; - - private static final Pattern DELIMITER_PATTERN = Pattern.compile("^\\s*((--)|(//))?\\s*(//)?\\s*@DELIMITER\\s+([^\\s]+)", Pattern.CASE_INSENSITIVE); - - private final Connection connection; - - private boolean stopOnError; - private boolean throwWarning; - private boolean autoCommit; - private boolean sendFullScript; - private boolean removeCRs; - private boolean escapeProcessing = true; - - private static final Logger LOGGER = LoggerFactory.getLogger(ScriptRunner.class); - - private String delimiter = DEFAULT_DELIMITER; - private boolean fullLineDelimiter; - - public ScriptRunner(Connection connection) { - this.connection = connection; - } - - public void setStopOnError(boolean stopOnError) { - this.stopOnError = stopOnError; - } - - public void setThrowWarning(boolean throwWarning) { - this.throwWarning = throwWarning; - } - - public void setAutoCommit(boolean autoCommit) { - this.autoCommit = autoCommit; - } - - public void setSendFullScript(boolean sendFullScript) { - this.sendFullScript = sendFullScript; - } - - public void setRemoveCRs(boolean removeCRs) { - this.removeCRs = removeCRs; - } - - /** - * Sets the escape processing. - * - * @param escapeProcessing the new escape processing - * @since 3.1.1 - */ - public void setEscapeProcessing(boolean escapeProcessing) { - this.escapeProcessing = escapeProcessing; - } - - public void setDelimiter(String delimiter) { - this.delimiter = delimiter; - } - - public void setFullLineDelimiter(boolean fullLineDelimiter) { - this.fullLineDelimiter = fullLineDelimiter; - } - - public void runScript(Reader reader) { - setAutoCommit(); - - try { - if (sendFullScript) { - executeFullScript(reader); - } else { - executeLineByLine(reader); - } - } finally { - rollbackConnection(); - } - } - - private void executeFullScript(Reader reader) { - StringBuilder script = new StringBuilder(); - try { - BufferedReader lineReader = new BufferedReader(reader); - String line; - while ((line = lineReader.readLine()) != null) { - script.append(line); - script.append(LINE_SEPARATOR); - } - String command = script.toString(); - LOGGER.debug(command); - executeStatement(command); - commitConnection(); - } catch (Exception e) { - String message = "Error executing: " + script + ". Cause: " + e; - LOGGER.error(message); - throw new RuntimeSqlException(message, e); - } - } - - private void executeLineByLine(Reader reader) { - StringBuilder command = new StringBuilder(); - try { - BufferedReader lineReader = new BufferedReader(reader); - String line; - while ((line = lineReader.readLine()) != null) { - handleLine(command, line); - } - commitConnection(); - checkForMissingLineTerminator(command); - } catch (Exception e) { - String message = "Error executing: " + command + ". Cause: " + e; - LOGGER.error(message); - throw new RuntimeSqlException(message, e); - } - } - - private void setAutoCommit() { - try { - if (autoCommit != connection.getAutoCommit()) { - connection.setAutoCommit(autoCommit); - } - } catch (Exception t) { - throw new RuntimeSqlException("Could not set AutoCommit to " + autoCommit + ". Cause: " + t, t); - } - } - - private void commitConnection() { - try { - if (!connection.getAutoCommit()) { - connection.commit(); - } - } catch (Exception t) { - throw new RuntimeSqlException("Could not commit transaction. Cause: " + t, t); - } - } - - private void rollbackConnection() { - try { - if (!connection.getAutoCommit()) { - connection.rollback(); - } - } catch (Exception t) { - // ignore - } - } - - private void checkForMissingLineTerminator(StringBuilder command) { - if (command != null && command.toString().trim().length() > 0) { - throw new RuntimeSqlException("Line missing end-of-line terminator (" + delimiter + ") => " + command); - } - } - - private void handleLine(StringBuilder command, String line) throws SQLException { - String trimmedLine = line.trim(); - if (lineIsComment(trimmedLine)) { - Matcher matcher = DELIMITER_PATTERN.matcher(trimmedLine); - if (matcher.find()) { - delimiter = matcher.group(5); - } - LOGGER.debug(trimmedLine); - } else if (commandReadyToExecute(trimmedLine)) { - command.append(line, 0, line.lastIndexOf(delimiter)); - command.append(LINE_SEPARATOR); - LOGGER.debug(command.toString()); - executeStatement(command.toString()); - command.setLength(0); - } else if (trimmedLine.length() > 0) { - command.append(line); - command.append(LINE_SEPARATOR); - } - } - - private boolean lineIsComment(String trimmedLine) { - return trimmedLine.startsWith("//") || trimmedLine.startsWith("--"); - } - - private boolean commandReadyToExecute(String trimmedLine) { - // issue #561 remove anything after the delimiter - return !fullLineDelimiter && trimmedLine.contains(delimiter) || fullLineDelimiter && trimmedLine.equals(delimiter); - } - - private void executeStatement(String command) throws SQLException { - try (Statement statement = connection.createStatement()) { - statement.setEscapeProcessing(escapeProcessing); - String sql = command; - if (removeCRs) { - sql = sql.replace("\r\n", "\n"); - } - try { - boolean hasResults = statement.execute(sql); - while (!(!hasResults && statement.getUpdateCount() == -1)) { - checkWarnings(statement); - printResults(statement, hasResults); - hasResults = statement.getMoreResults(); - } - } catch (SQLWarning e) { - throw e; - } catch (SQLException e) { - if (stopOnError) { - throw e; - } else { - String message = "Error executing: " + command + ". Cause: " + e; - LOGGER.error(message); - } - } - } - } - - private void checkWarnings(Statement statement) throws SQLException { - if (!throwWarning) { - return; - } - // In Oracle, CREATE PROCEDURE, FUNCTION, etc. returns warning - // instead of throwing exception if there is compilation error. - SQLWarning warning = statement.getWarnings(); - if (warning != null) { - throw warning; - } - } - - private void printResults(Statement statement, boolean hasResults) { - if (!hasResults) { - return; - } - try (ResultSet rs = statement.getResultSet()) { - ResultSetMetaData md = rs.getMetaData(); - int cols = md.getColumnCount(); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < cols; i++) { - String name = md.getColumnLabel(i + 1); - sb.append(name + "\t"); - } - sb.append(System.lineSeparator()); - while (rs.next()) { - for (int i = 0; i < cols; i++) { - String value = rs.getString(i + 1); - sb.append(value + "\t"); - } - sb.append(System.lineSeparator()); - LOGGER.debug(sb.toString()); - } - } catch (SQLException e) { - LOGGER.error("Error printing results: " + e.getMessage()); - } - } -} diff --git a/src/main/kotlin/io/kotest/extensions/testcontainers/ContainerExtension.kt b/src/main/kotlin/io/kotest/extensions/testcontainers/ContainerExtension.kt index 4778a81..f25f3a3 100644 --- a/src/main/kotlin/io/kotest/extensions/testcontainers/ContainerExtension.kt +++ b/src/main/kotlin/io/kotest/extensions/testcontainers/ContainerExtension.kt @@ -56,14 +56,14 @@ import org.testcontainers.containers.GenericContainer class ContainerExtension>( private val container: T, private val mode: ContainerLifecycleMode = ContainerLifecycleMode.Project, - private val beforeStart: () -> Unit = {}, - private val afterStart: () -> Unit = {}, + private val beforeStart: T.() -> Unit = {}, + private val afterStart: T.() -> Unit = {}, private val beforeTest: suspend (TestCase) -> Unit = { _ -> }, private val afterTest: suspend (TestCase) -> Unit = { _ -> }, private val beforeSpec: suspend (Spec) -> Unit = { _ -> }, private val afterSpec: suspend (Spec) -> Unit = { _ -> }, - private val beforeShutdown: () -> Unit = {}, - private val afterShutdown: () -> Unit = {}, + private val beforeShutdown: suspend T.() -> Unit = {}, + private val afterShutdown: suspend T.() -> Unit = {}, ) : MountableExtension, AfterProjectListener, BeforeTestListener, @@ -75,14 +75,14 @@ class ContainerExtension>( * Mounts the container, starting it if necessary. The [configure] block will be invoked * every time the container is mounted, and after the container has started. */ - override fun mount(configure: T.() -> Unit): T { - if (!container.isRunning) { + override fun mount(configure: T.() -> Unit): T = container.apply{ + if (!isRunning) { beforeStart() - container.start() + start() afterStart() } - container.configure() - return container + + configure() } override suspend fun beforeTest(testCase: TestCase) { @@ -108,9 +108,9 @@ class ContainerExtension>( private suspend fun close() { withContext(Dispatchers.IO) { - beforeShutdown() + container.beforeShutdown() container.stop() - afterShutdown() + container.afterShutdown() } } } diff --git a/src/main/kotlin/io/kotest/extensions/testcontainers/DockerComposeContainersExtension.kt b/src/main/kotlin/io/kotest/extensions/testcontainers/DockerComposeContainersExtension.kt deleted file mode 100644 index 494fade..0000000 --- a/src/main/kotlin/io/kotest/extensions/testcontainers/DockerComposeContainersExtension.kt +++ /dev/null @@ -1,99 +0,0 @@ -package io.kotest.extensions.testcontainers - -import io.kotest.core.extensions.MountableExtension -import io.kotest.core.listeners.AfterSpecListener -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 io.kotest.core.test.TestType -import io.kotest.core.test.isRootTest -import java.io.File -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import org.testcontainers.lifecycle.TestLifecycleAware -import java.util.Optional -import org.testcontainers.containers.DockerComposeContainer - -@Deprecated("use DockerComposeContainerExtension") -class DockerComposeContainersExtension>( - private val container: DockerComposeContainer, - private val lifecycleMode: LifecycleMode = LifecycleMode.Spec, -) : MountableExtension, TestListener, AfterSpecListener { - - companion object { - operator fun invoke(composeFile: File): DockerComposeContainersExtension> = - DockerComposeContainersExtension(DockerComposeContainer(composeFile)) - - operator fun invoke( - composeFile: File, - lifecycleMode: LifecycleMode - ): DockerComposeContainersExtension> = - DockerComposeContainersExtension(DockerComposeContainer(composeFile), lifecycleMode) - } - - override fun mount(configure: T.() -> Unit): T { - @Suppress("UNCHECKED_CAST") - (container as T).configure() - if (lifecycleMode == LifecycleMode.Spec) { - container.start() - } - return container - } - - override suspend fun afterSpec(spec: Spec) { - withContext(Dispatchers.IO) { - stop() - } - } - - override suspend fun beforeAny(testCase: TestCase) { - val every = lifecycleMode == LifecycleMode.EveryTest - val root = lifecycleMode == LifecycleMode.Root && testCase.isRootTest() - val leaf = lifecycleMode == LifecycleMode.Leaf && testCase.type == TestType.Test - if (every || root || leaf) { - lifecycleBeforeTest(testCase) - start() - } - } - - override suspend fun afterAny(testCase: TestCase, result: TestResult) { - val every = lifecycleMode == LifecycleMode.EveryTest - val root = lifecycleMode == LifecycleMode.Root && testCase.isRootTest() - val leaf = lifecycleMode == LifecycleMode.Leaf && testCase.type == TestType.Test - if (every || root || leaf) { - lifecycleAfterTest(testCase, result) - stop() - } - } - - private suspend fun start() { - withContext(Dispatchers.IO) { - container.start() - } - } - - private suspend fun stop() { - withContext(Dispatchers.IO) { - container.stop() - } - } - - private suspend fun lifecycleBeforeTest(testCase: TestCase) { - when (container) { - is TestLifecycleAware -> withContext(Dispatchers.IO) { - container.beforeTest(testCase.toTestDescription()) - } - } - } - - private suspend fun lifecycleAfterTest(testCase: TestCase, result: TestResult) { - when (container) { - is TestLifecycleAware -> withContext(Dispatchers.IO) { - container.afterTest( - testCase.toTestDescription(), Optional.ofNullable(result.errorOrNull) - ) - } - } - } -} diff --git a/src/main/kotlin/io/kotest/extensions/testcontainers/Extensions.kt b/src/main/kotlin/io/kotest/extensions/testcontainers/Extensions.kt index 637bfdc..57c3956 100644 --- a/src/main/kotlin/io/kotest/extensions/testcontainers/Extensions.kt +++ b/src/main/kotlin/io/kotest/extensions/testcontainers/Extensions.kt @@ -1,6 +1,5 @@ package io.kotest.extensions.testcontainers -import io.kotest.core.TestConfiguration import org.testcontainers.lifecycle.Startable fun T.perTest(): StartablePerTestListener = StartablePerTestListener(this) @@ -8,25 +7,3 @@ fun T.perTest(): StartablePerTestListener = StartablePerTestL fun T.perSpec(): StartablePerSpecListener = StartablePerSpecListener(this) fun T.perProject(): StartablePerProjectListener = StartablePerProjectListener(this) - -@Deprecated("use perProject()") -fun T.perProject(containerName: String): StartablePerProjectListener = - StartablePerProjectListener(this) - -@Deprecated("use perTest") -fun TestConfiguration.configurePerTest(startable: T): T { - listener(StartablePerTestListener(startable)) - return startable -} - -@Deprecated("use perSpec") -fun TestConfiguration.configurePerSpec(startable: T): T { - listener(StartablePerSpecListener(startable)) - return startable -} - -@Deprecated("use perProject") -fun TestConfiguration.configurePerProject(startable: T, containerName: String): T { - listener(StartablePerProjectListener(startable)) - return startable -} diff --git a/src/main/kotlin/io/kotest/extensions/testcontainers/JdbcDatabaseContainerExtension.kt b/src/main/kotlin/io/kotest/extensions/testcontainers/JdbcDatabaseContainerExtension.kt index 36d168c..ff10b53 100644 --- a/src/main/kotlin/io/kotest/extensions/testcontainers/JdbcDatabaseContainerExtension.kt +++ b/src/main/kotlin/io/kotest/extensions/testcontainers/JdbcDatabaseContainerExtension.kt @@ -14,6 +14,7 @@ import io.kotest.core.test.TestResult import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.testcontainers.containers.JdbcDatabaseContainer +import org.testcontainers.lifecycle.Startable /** * A Kotest [MountableExtension] for [JdbcDatabaseContainer]s which is started the first time they are diff --git a/src/main/kotlin/io/kotest/extensions/testcontainers/JdbcTestContainerExtension.kt b/src/main/kotlin/io/kotest/extensions/testcontainers/JdbcTestContainerExtension.kt deleted file mode 100644 index 4f45929..0000000 --- a/src/main/kotlin/io/kotest/extensions/testcontainers/JdbcTestContainerExtension.kt +++ /dev/null @@ -1,118 +0,0 @@ -package io.kotest.extensions.testcontainers - -import com.zaxxer.hikari.HikariDataSource -import io.kotest.core.extensions.MountableExtension -import io.kotest.core.listeners.AfterSpecListener -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 io.kotest.core.test.TestType -import io.kotest.core.test.isRootTest -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import org.testcontainers.containers.JdbcDatabaseContainer -import java.sql.Connection -import javax.sql.DataSource - -/** - * A Kotest [MountableExtension] for [JdbcDatabaseContainer]s that will launch the container - * upon install, and close after the spec has completed. - * - * This extension will create a pooled [HikariDataSource] attached to the database and - * return that to the user as the materialized value. - * - * The pool can be configured in the mount configure method. - * - * Note: This extension requires Kotest 5.0+ - * - * @param container the specific test container type - * @param lifecycleMode determines how the container should be reset between tests - * - * @since 1.1.0 - */ -@Deprecated("use JdbcDatabaseContainerExtension") -class JdbcTestContainerExtension( - private val container: JdbcDatabaseContainer, - private val lifecycleMode: LifecycleMode = LifecycleMode.Spec, -) : MountableExtension, AfterSpecListener, TestListener { - - private val ds = SettableDataSource(null) - private var configure: TestContainerHikariConfig.() -> Unit = {} - - override fun mount(configure: TestContainerHikariConfig.() -> Unit): DataSource { - this.configure = configure - if (lifecycleMode == LifecycleMode.Spec) { - container.start() - ds.setDataSource(createDataSource()) - } - return ds - } - - private fun createDataSource(): HikariDataSource { - val config = TestContainerHikariConfig() - config.jdbcUrl = container.jdbcUrl - config.username = container.username - config.password = container.password - config.configure() - val ds = HikariDataSource(config) - runInitScripts(ds.connection, config.dbInitScripts) - return ds - } - - override suspend fun afterSpec(spec: Spec) { - withContext(Dispatchers.IO) { - stop() - } - } - - override suspend fun beforeAny(testCase: TestCase) { - val every = lifecycleMode == LifecycleMode.EveryTest - val root = lifecycleMode == LifecycleMode.Root && testCase.isRootTest() - val leaf = lifecycleMode == LifecycleMode.Leaf && testCase.type == TestType.Test - if (every || root || leaf) { - start() - } - } - - override suspend fun afterAny(testCase: TestCase, result: TestResult) { - val every = lifecycleMode == LifecycleMode.EveryTest - val root = lifecycleMode == LifecycleMode.Root && testCase.isRootTest() - val leaf = lifecycleMode == LifecycleMode.Leaf && testCase.type == TestType.Test - if (every || root || leaf) { - stop() - } - } - - private suspend fun start() { - withContext(Dispatchers.IO) { - container.start() - ds.setDataSource(createDataSource()) - } - } - - private suspend fun stop() { - withContext(Dispatchers.IO) { - ds.setDataSource(null) - container.stop() - } - } - - private fun runInitScripts(connection: Connection, dbInitScripts: List) { - - val scriptRunner = ScriptRunner(connection) - - if (dbInitScripts.isNotEmpty()) { - dbInitScripts.forEach { - val resourceList = ResourceLoader().resolveResource(it) - - resourceList - .filter { resource -> resource.endsWith(".sql") } - .forEach { resource -> - scriptRunner.runScript(resource.loadToReader()) - } - } - } - } -} - diff --git a/src/main/kotlin/io/kotest/extensions/testcontainers/LifecycleMode.kt b/src/main/kotlin/io/kotest/extensions/testcontainers/LifecycleMode.kt deleted file mode 100644 index 6cc4049..0000000 --- a/src/main/kotlin/io/kotest/extensions/testcontainers/LifecycleMode.kt +++ /dev/null @@ -1,7 +0,0 @@ -package io.kotest.extensions.testcontainers - -@Deprecated("To be removed") -enum class LifecycleMode { - Spec, EveryTest, Leaf, Root -} - diff --git a/src/main/kotlin/io/kotest/extensions/testcontainers/ResourceLoader.kt b/src/main/kotlin/io/kotest/extensions/testcontainers/ResourceLoader.kt deleted file mode 100644 index 2db4600..0000000 --- a/src/main/kotlin/io/kotest/extensions/testcontainers/ResourceLoader.kt +++ /dev/null @@ -1,84 +0,0 @@ -package io.kotest.extensions.testcontainers - -import java.io.BufferedReader -import java.nio.file.FileSystems -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.Paths -import java.util.stream.Collectors -import kotlin.io.path.exists -import kotlin.io.path.isDirectory -import kotlin.io.path.isRegularFile -import kotlin.io.path.name - -@Deprecated("use Flyway or another db migration tool") -sealed interface Resource { - data class Classpath(val resource: String) : Resource - data class File(val path: Path) : Resource -} - -@Deprecated("use Flyway or another db migration tool") -fun Resource.endsWith(name: String): Boolean = when (this) { - is Resource.Classpath -> this.resource.endsWith(name) - is Resource.File -> this.path.name.endsWith(name) -} - -@Deprecated("use Flyway or another db migration tool") -fun Resource.loadToReader(): BufferedReader = when (this) { - is Resource.Classpath -> javaClass.getResourceAsStream(this.resource)?.bufferedReader() ?: error("$this was not found on classpath") - is Resource.File -> Files.newBufferedReader(this.path) -} - -@Deprecated("use Flyway or another db migration tool") -class ResourceLoader { - - private fun Path.getDirContentsOrItself(): List { - return if (this.isDirectory()) { - Files.newDirectoryStream(this) - .use { stream -> stream.toList() } - .filter { it.isRegularFile() } - } else { - listOf(this) - } - } - - private fun getFileResourcesFromPath(path: Path): List { - if (!path.exists()) error("Resource $path does not exist on the classpath or on the local filesystem") - - return when (path.isRegularFile()) { - true -> listOf(Resource.File(path)) - else -> Files.walk(path) - .filter { it.isRegularFile() } - .sorted() - .map { Resource.File(it) } - .collect(Collectors.toList()) - } - } - - private fun getClasspathResourcesFromJar(resource: String) : List { - val uri = javaClass.getResource(resource)!!.toURI() - FileSystems.newFileSystem(uri, mutableMapOf()).use { fs -> - val pathList = fs.getPath(resource).getDirContentsOrItself() - return pathList.map { Resource.Classpath(it.toString()) }.sortedBy { it.toString() } - } - } - - fun resolveResource(resource: String): List { - val url = javaClass.getResource(resource) - - return if (url == null) { - //Not on classpath, check file system - val path = Paths.get(resource) - getFileResourcesFromPath(path) - - } else { - //On Classpath - when(url.protocol){ - "jar" -> getClasspathResourcesFromJar(resource) - "file" -> getFileResourcesFromPath(Paths.get(url.toURI())) - else -> error("Unhandled protocol: ${url.protocol}") - } - } - } -} - diff --git a/src/main/kotlin/io/kotest/extensions/testcontainers/SharedJdbcDatabaseContainerExtension.kt b/src/main/kotlin/io/kotest/extensions/testcontainers/SharedJdbcDatabaseContainerExtension.kt deleted file mode 100644 index b7b80cd..0000000 --- a/src/main/kotlin/io/kotest/extensions/testcontainers/SharedJdbcDatabaseContainerExtension.kt +++ /dev/null @@ -1,111 +0,0 @@ -package io.kotest.extensions.testcontainers - -import com.zaxxer.hikari.HikariConfig -import com.zaxxer.hikari.HikariDataSource -import io.kotest.core.extensions.MountableExtension -import io.kotest.core.listeners.AfterProjectListener -import io.kotest.core.listeners.AfterSpecListener -import io.kotest.core.listeners.AfterTestListener -import io.kotest.core.listeners.BeforeSpecListener -import io.kotest.core.listeners.BeforeTestListener -import io.kotest.core.spec.Spec -import io.kotest.core.test.TestCase -import io.kotest.core.test.TestResult -import org.testcontainers.containers.JdbcDatabaseContainer -import java.sql.Connection - -/** - * A Kotest [MountableExtension] for [JdbcDatabaseContainer]s that are started the first time they are - * installed in a test, and then shared throughout the same gradle module. The container is shutdown - * after all specs have completed. - * - * If no spec is executed that installs a particular container, then that container is never started. - * - * This extension will create a pooled [HikariDataSource] attached to the database and - * return that to the user as the materialized value. - * - * The Hikari pool can be configured in the constructor through the [configure] parameter, or through - * the install method per spec. If the latter option is used, then only the configure function from - * the install where the container is first started will be executed. - * - * Note: This extension requires Kotest 5.0+ - * - * @param container the specific database test container type - * @param beforeSpec a beforeSpec callback - * @param afterSpec an afterSpec callback - * @param beforeTest a beforeTest callback - * @param afterTest a afterTest callback - * @param afterStart called one time, after the container is started - * @param configure a callback to configure the [HikariConfig] instance that is used to create the [HikariDataSource]. - * - * @since 1.3.0 - */ -@Deprecated("use JdbcDatabaseContainerExtension") -class SharedJdbcDatabaseContainerExtension( - private val container: JdbcDatabaseContainer<*>, - private val beforeTest: suspend (HikariDataSource) -> Unit = {}, - private val afterTest: suspend (HikariDataSource) -> Unit = {}, - private val beforeSpec: suspend (HikariDataSource) -> Unit = {}, - private val afterSpec: suspend (HikariDataSource) -> Unit = {}, - private val afterStart: (HikariDataSource) -> Unit = {}, - private val configure: TestContainerHikariConfig.() -> Unit = {}, -) : MountableExtension, - AfterProjectListener, - BeforeTestListener, - BeforeSpecListener, - AfterTestListener, - AfterSpecListener { - - private var ds: HikariDataSource? = null - - override fun mount(configure: TestContainerHikariConfig.() -> Unit): HikariDataSource { - if (!container.isRunning) { - container.start() - ds = createDataSource().apply(afterStart) - } - return ds ?: error("DataSource was not initialized") - } - - override suspend fun afterProject() { - if (container.isRunning) container.stop() - } - - override suspend fun beforeTest(testCase: TestCase) { - beforeTest(ds ?: error("DataSource was not initialized")) - } - - override suspend fun afterTest(testCase: TestCase, result: TestResult) { - afterTest(ds ?: error("DataSource was not initialized")) - } - - override suspend fun beforeSpec(spec: Spec) { - beforeSpec(ds ?: error("DataSource was not initialized")) - } - - override suspend fun afterSpec(spec: Spec) { - afterSpec(ds ?: error("DataSource was not initialized")) - } - - private fun runInitScripts(connection: Connection, dbInitScripts: List) { - if (dbInitScripts.isNotEmpty()) { - val scriptRunner = ScriptRunner(connection) - dbInitScripts.forEach { script -> - ResourceLoader() - .resolveResource(script) - .filter { it.endsWith(".sql") } - .forEach { scriptRunner.runScript(it.loadToReader()) } - } - } - } - - private fun createDataSource(): HikariDataSource { - val config = TestContainerHikariConfig() - config.jdbcUrl = container.jdbcUrl - config.username = container.username - config.password = container.password - config.configure() - val ds = HikariDataSource(config) - runInitScripts(ds.connection, config.dbInitScripts) - return ds - } -} diff --git a/src/main/kotlin/io/kotest/extensions/testcontainers/SharedTestContainerExtension.kt b/src/main/kotlin/io/kotest/extensions/testcontainers/SharedTestContainerExtension.kt deleted file mode 100644 index e8084b6..0000000 --- a/src/main/kotlin/io/kotest/extensions/testcontainers/SharedTestContainerExtension.kt +++ /dev/null @@ -1,102 +0,0 @@ -package io.kotest.extensions.testcontainers - -import io.kotest.core.extensions.MountableExtension -import io.kotest.core.listeners.AfterProjectListener -import io.kotest.core.listeners.AfterSpecListener -import io.kotest.core.listeners.AfterTestListener -import io.kotest.core.listeners.BeforeSpecListener -import io.kotest.core.listeners.BeforeTestListener -import io.kotest.core.spec.Spec -import io.kotest.core.test.TestCase -import io.kotest.core.test.TestResult -import org.testcontainers.containers.GenericContainer - -/** - * A Kotest [MountableExtension] for [GenericContainer]s that are started the first time they are - * installed in a test, and then shared throughout the same gradle module. The container is shutdown - * after all specs have completed. - * - * If no spec is executed that installs a particular container, then that container is never started. - * - * The returned materialized value can be adapted through the [mapper] parameter, to allow returning something other - * than the raw container. For example, you could return a RedisClient that was preconnected to a redis container, - * rather than returning the container itself. - * - * Note: This extension requires Kotest 5.0+ - * - * @param container the specific database test container type - * @param beforeSpec a beforeSpec callback, can be used to configure the container. - * @param afterSpec an afterSpec callback, can be used to configure the container. - * @param beforeTest a beforeTest callback, can be used to configure the container. - * @param afterTest a afterTest callback, can be used to configure the container. - * @param configure called one time after the container is started. Can configure the container without needing to - * specify the configuration code at every use site. - * @param mapper optional mapping function to adapt the materialized value. - * - * @since 1.3.0 - */ -@Deprecated("use ContainerExtension") -class SharedTestContainerExtension, U>( - private val container: T, - private val beforeTest: suspend (T) -> Unit = {}, - private val afterTest: suspend (T) -> Unit = {}, - private val beforeSpec: suspend (T) -> Unit = {}, - private val afterSpec: suspend (T) -> Unit = {}, - private val configure: T.() -> Unit = {}, - private val mapper: T.() -> U, -) : MountableExtension, - AfterProjectListener, - BeforeTestListener, - BeforeSpecListener, - AfterTestListener, - AfterSpecListener { - - companion object { - operator fun > invoke( - container: T, - beforeTest: (T) -> Unit = {}, - afterTest: (T) -> Unit = {}, - beforeSpec: (T) -> Unit = {}, - afterSpec: (T) -> Unit = {}, - configure: T.() -> Unit = {}, - ): SharedTestContainerExtension { - return SharedTestContainerExtension( - container, - beforeTest, - afterTest, - beforeSpec, - afterSpec, - configure - ) { this } - } - } - - override fun mount(configure: T.() -> Unit): U { - if (!container.isRunning) { - container.start() - configure(container) - this@SharedTestContainerExtension.configure(container) - } - return this@SharedTestContainerExtension.mapper(container) - } - - override suspend fun afterProject() { - if (container.isRunning) container.stop() - } - - override suspend fun beforeTest(testCase: TestCase) { - beforeTest(container) - } - - override suspend fun afterTest(testCase: TestCase, result: TestResult) { - afterTest(container) - } - - override suspend fun beforeSpec(spec: Spec) { - beforeSpec(container) - } - - override suspend fun afterSpec(spec: Spec) { - afterSpec(container) - } -} diff --git a/src/main/kotlin/io/kotest/extensions/testcontainers/StartablePerProjectListener.kt b/src/main/kotlin/io/kotest/extensions/testcontainers/StartablePerProjectListener.kt index 5abd6ee..8562daf 100644 --- a/src/main/kotlin/io/kotest/extensions/testcontainers/StartablePerProjectListener.kt +++ b/src/main/kotlin/io/kotest/extensions/testcontainers/StartablePerProjectListener.kt @@ -21,9 +21,6 @@ import org.testcontainers.lifecycle.Startable * */ class StartablePerProjectListener(private val startable: T) : TestListener, ProjectListener { - @Deprecated("The containerName arg is no longer used") - constructor(startable: T, containerName: String) : this(startable) - private val testLifecycleAwareListener = TestLifecycleAwareListener(startable) override suspend fun beforeProject() { diff --git a/src/main/kotlin/io/kotest/extensions/testcontainers/TestContainerExtension.kt b/src/main/kotlin/io/kotest/extensions/testcontainers/TestContainerExtension.kt deleted file mode 100644 index 4a42eb2..0000000 --- a/src/main/kotlin/io/kotest/extensions/testcontainers/TestContainerExtension.kt +++ /dev/null @@ -1,96 +0,0 @@ -package io.kotest.extensions.testcontainers - -import io.kotest.core.extensions.MountableExtension -import io.kotest.core.listeners.AfterSpecListener -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 io.kotest.core.test.TestType -import io.kotest.core.test.isRootTest -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import org.testcontainers.containers.GenericContainer -import org.testcontainers.lifecycle.TestLifecycleAware -import java.util.Optional - -@Deprecated("use ContainerExtension") -class TestContainerExtension>( - private val container: GenericContainer, - private val lifecycleMode: LifecycleMode = LifecycleMode.Spec, -) : MountableExtension, TestListener, AfterSpecListener { - - companion object { - operator fun invoke(name: String): TestContainerExtension> = - TestContainerExtension(GenericContainer(name)) - - operator fun invoke(name: String, lifecycleMode: LifecycleMode): TestContainerExtension> = - TestContainerExtension(GenericContainer(name), lifecycleMode) - } - - override fun mount(configure: T.() -> Unit): T { - (container as T).configure() - if (lifecycleMode == LifecycleMode.Spec) { - container.start() - } - return container - } - - override suspend fun afterSpec(spec: Spec) { - if (container.isRunning) { - withContext(Dispatchers.IO) { - stop() - } - } - } - - override suspend fun beforeAny(testCase: TestCase) { - val every = lifecycleMode == LifecycleMode.EveryTest - val root = lifecycleMode == LifecycleMode.Root && testCase.isRootTest() - val leaf = lifecycleMode == LifecycleMode.Leaf && testCase.type == TestType.Test - if (every || root || leaf) { - lifecycleBeforeTest(testCase) - start() - } - } - - override suspend fun afterAny(testCase: TestCase, result: TestResult) { - val every = lifecycleMode == LifecycleMode.EveryTest - val root = lifecycleMode == LifecycleMode.Root && testCase.isRootTest() - val leaf = lifecycleMode == LifecycleMode.Leaf && testCase.type == TestType.Test - if (every || root || leaf) { - lifecycleAfterTest(testCase, result) - stop() - } - } - - private suspend fun start() { - withContext(Dispatchers.IO) { - container.start() - } - } - - private suspend fun stop() { - withContext(Dispatchers.IO) { - container.stop() - } - } - - private suspend fun lifecycleBeforeTest(testCase: TestCase) { - when (container) { - is TestLifecycleAware -> withContext(Dispatchers.IO) { - container.beforeTest(testCase.toTestDescription()) - } - } - } - - private suspend fun lifecycleAfterTest(testCase: TestCase, result: TestResult) { - when (container) { - is TestLifecycleAware -> withContext(Dispatchers.IO) { - container.afterTest( - testCase.toTestDescription(), Optional.ofNullable(result.errorOrNull) - ) - } - } - } -} diff --git a/src/main/kotlin/io/kotest/extensions/testcontainers/TestContainerHikariConfig.kt b/src/main/kotlin/io/kotest/extensions/testcontainers/TestContainerHikariConfig.kt deleted file mode 100644 index 6cf1304..0000000 --- a/src/main/kotlin/io/kotest/extensions/testcontainers/TestContainerHikariConfig.kt +++ /dev/null @@ -1,10 +0,0 @@ -package io.kotest.extensions.testcontainers - -import com.zaxxer.hikari.HikariConfig - -@Deprecated("use Flyway or another db migration tool") -class TestContainerHikariConfig : HikariConfig() { - - var dbInitScripts: List = emptyList() - -} diff --git a/src/main/kotlin/io/kotest/extensions/testcontainers/kafka/kafka.kt b/src/main/kotlin/io/kotest/extensions/testcontainers/kafka/kafka.kt deleted file mode 100644 index d28449f..0000000 --- a/src/main/kotlin/io/kotest/extensions/testcontainers/kafka/kafka.kt +++ /dev/null @@ -1,60 +0,0 @@ -package io.kotest.extensions.testcontainers.kafka - -import org.apache.kafka.clients.CommonClientConfigs -import org.apache.kafka.clients.admin.AdminClient -import org.apache.kafka.clients.consumer.KafkaConsumer -import org.apache.kafka.clients.producer.KafkaProducer -import org.apache.kafka.common.serialization.Deserializer -import org.apache.kafka.common.serialization.Serializer -import org.apache.kafka.common.serialization.StringDeserializer -import org.apache.kafka.common.serialization.StringSerializer -import org.testcontainers.containers.KafkaContainer -import java.util.Properties -import java.util.UUID - -@Deprecated("Use the kafka module") -fun KafkaContainer.createStringStringProducer( - configure: Properties.() -> Unit = {}, -): KafkaProducer { - return createProducer(StringSerializer(), StringSerializer(), configure) -} - -@Deprecated("Use the kafka module") -fun KafkaContainer.createProducer( - kserializer: Serializer, - vserializer: Serializer, - configure: Properties.() -> Unit = {}, -): KafkaProducer { - val props = Properties() - props[CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG] = bootstrapServers - props.configure() - return KafkaProducer(props, kserializer, vserializer) -} - -@Deprecated("Use the kafka module") -fun KafkaContainer.createStringStringConsumer( - configure: Properties.() -> Unit = {}, -): KafkaConsumer { - return createConsumer(StringDeserializer(), StringDeserializer(), configure) -} - -@Deprecated("Use the kafka module") -fun KafkaContainer.createConsumer( - kserializer: Deserializer, - vserializer: Deserializer, - configure: Properties.() -> Unit = {}, -): KafkaConsumer { - val props = Properties() - props[CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG] = bootstrapServers - props[CommonClientConfigs.GROUP_ID_CONFIG] = UUID.randomUUID().toString().replace("-", "") - props.configure() - return KafkaConsumer(props, kserializer, vserializer) -} - -@Deprecated("Use the kafka module") -fun KafkaContainer.createAdminClient(configure: Properties.() -> Unit = {}): AdminClient { - val props = Properties() - props[CommonClientConfigs.BOOTSTRAP_SERVERS_CONFIG] = bootstrapServers - props.configure() - return AdminClient.create(props) -} diff --git a/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerExtensionSpecTest.kt b/src/test/kotlin/io/kotest/extensions/testcontainers/ContainerExtensionSpecLifecycleTest.kt similarity index 74% rename from src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerExtensionSpecTest.kt rename to src/test/kotlin/io/kotest/extensions/testcontainers/ContainerExtensionSpecLifecycleTest.kt index 1f684a5..14e2226 100644 --- a/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerExtensionSpecTest.kt +++ b/src/test/kotlin/io/kotest/extensions/testcontainers/ContainerExtensionSpecLifecycleTest.kt @@ -1,14 +1,15 @@ package io.kotest.extensions.testcontainers +import com.redis.testcontainers.RedisContainer import io.kotest.core.extensions.install import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import redis.clients.jedis.JedisPool -class TestContainerExtensionSpecTest : FunSpec() { +class ContainerExtensionSpecLifecycleTest : FunSpec() { init { - val container = install(TestContainerExtension("redis:5.0.3-alpine", LifecycleMode.Spec)) { + val container = install(ContainerExtension(RedisContainer("7.2.5-alpine"), ContainerLifecycleMode.Spec)) { startupAttempts = 2 withExposedPorts(6379) } diff --git a/src/test/kotlin/io/kotest/extensions/testcontainers/DockerComposeContainersExtensionTest.kt b/src/test/kotlin/io/kotest/extensions/testcontainers/DockerComposeContainersExtensionTest.kt deleted file mode 100644 index 7f32acb..0000000 --- a/src/test/kotlin/io/kotest/extensions/testcontainers/DockerComposeContainersExtensionTest.kt +++ /dev/null @@ -1,19 +0,0 @@ -package io.kotest.extensions.testcontainers - -import io.kotest.core.extensions.install -import io.kotest.core.spec.style.StringSpec -import io.kotest.matchers.optional.shouldBePresent -import io.kotest.matchers.string.shouldContain -import java.io.File - -class DockerComposeContainersExtensionTest: StringSpec() { - init { - - val container = install(DockerComposeContainersExtension(File("src/test/resources/docker-compose/docker-compose.yml"))) { - } - - "should setup using docker-compose" { - container.getContainerByServiceName("hello_world").shouldBePresent().logs shouldContain "Hello world" - } - } -} diff --git a/src/test/kotlin/io/kotest/extensions/testcontainers/JdbcTestContainerExtensionSpecTest.kt b/src/test/kotlin/io/kotest/extensions/testcontainers/JdbcDatabaseContainerExtensionSpecTest.kt similarity index 91% rename from src/test/kotlin/io/kotest/extensions/testcontainers/JdbcTestContainerExtensionSpecTest.kt rename to src/test/kotlin/io/kotest/extensions/testcontainers/JdbcDatabaseContainerExtensionSpecTest.kt index 01296a7..a75f9ef 100644 --- a/src/test/kotlin/io/kotest/extensions/testcontainers/JdbcTestContainerExtensionSpecTest.kt +++ b/src/test/kotlin/io/kotest/extensions/testcontainers/JdbcDatabaseContainerExtensionSpecTest.kt @@ -5,7 +5,7 @@ import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import org.testcontainers.containers.MySQLContainer -class JdbcTestContainerExtensionSpecTest : FunSpec() { +class JdbcDatabaseContainerExtensionSpecTest : FunSpec() { init { val mysql = MySQLContainer("mysql:8.0.26").apply { @@ -15,7 +15,7 @@ class JdbcTestContainerExtensionSpecTest : FunSpec() { withUrlParam("zeroDateTimeBehavior", "convertToNull") } - val ds = install(JdbcTestContainerExtension(mysql)) { + val ds = install(JdbcDatabaseContainerExtension(mysql)) { maximumPoolSize = 8 minimumIdle = 4 } diff --git a/src/test/kotlin/io/kotest/extensions/testcontainers/JdbcMultiScriptContainerInitTest.kt b/src/test/kotlin/io/kotest/extensions/testcontainers/JdbcMultiScriptContainerInitTest.kt index c12b5cb..99a8c3c 100644 --- a/src/test/kotlin/io/kotest/extensions/testcontainers/JdbcMultiScriptContainerInitTest.kt +++ b/src/test/kotlin/io/kotest/extensions/testcontainers/JdbcMultiScriptContainerInitTest.kt @@ -4,6 +4,7 @@ import io.kotest.core.extensions.install import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import org.testcontainers.containers.MySQLContainer +import org.testcontainers.utility.MountableFile.forClasspathResource class JdbcMultiScriptContainerInitTest : FunSpec({ @@ -11,11 +12,16 @@ class JdbcMultiScriptContainerInitTest : FunSpec({ startupAttempts = 1 withUrlParam("connectionTimeZone", "Z") withUrlParam("zeroDateTimeBehavior", "convertToNull") + + val sqlInitDir = "/docker-entrypoint-initdb.d/" + withCopyToContainer(forClasspathResource("init.sql"), sqlInitDir + "000-init.sql") + withCopyToContainer(forClasspathResource("sql-changesets/001-people.sql"), sqlInitDir + "001-people.sql") + withCopyToContainer(forClasspathResource("sql-changesets/002-places.sql"), sqlInitDir + "002-places.sql") } - val ds = install(JdbcTestContainerExtension(mysql, LifecycleMode.Leaf)) { + + val ds = install(JdbcDatabaseContainerExtension(mysql, ContainerLifecycleMode.Spec)) { maximumPoolSize = 8 minimumIdle = 4 - dbInitScripts = listOf("/init.sql", "/sql-changesets") } @@ -41,24 +47,4 @@ class JdbcMultiScriptContainerInitTest : FunSpec({ } } - - context("with fresh container init"){ - test("db should be reset per lifecycle mode") { - ds.connection.use { - - var rsCount = it.createStatement().executeQuery("SELECT count(*) FROM hashtags") - rsCount.next() - rsCount.getLong(1) shouldBe 1 - - rsCount = it.createStatement().executeQuery("SELECT count(*) FROM people") - rsCount.next() - rsCount.getLong(1) shouldBe 2 - - rsCount = it.createStatement().executeQuery("SELECT count(*) FROM places") - rsCount.next() - rsCount.getLong(1) shouldBe 2 - } - } - } - }) diff --git a/src/test/kotlin/io/kotest/extensions/testcontainers/JdbcTestContainerExtensionLeafTest.kt b/src/test/kotlin/io/kotest/extensions/testcontainers/JdbcTestContainerExtensionLeafTest.kt deleted file mode 100644 index 47d9f15..0000000 --- a/src/test/kotlin/io/kotest/extensions/testcontainers/JdbcTestContainerExtensionLeafTest.kt +++ /dev/null @@ -1,50 +0,0 @@ -@file:Suppress("SqlResolve") - -package io.kotest.extensions.testcontainers - -import io.kotest.core.extensions.install -import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.shouldBe -import org.testcontainers.containers.MySQLContainer - -class JdbcTestContainerExtensionLeafTest : DescribeSpec() { - init { - - val mysql = MySQLContainer("mysql:8.0.26").apply { - withInitScript("init.sql") - startupAttempts = 1 - withUrlParam("connectionTimeZone", "Z") - withUrlParam("zeroDateTimeBehavior", "convertToNull") - } - - val ds = install(JdbcTestContainerExtension(mysql, LifecycleMode.Leaf)) { - maximumPoolSize = 8 - minimumIdle = 4 - } - - describe("context") { - mysql.isRunning shouldBe false - it("should initialize per leaf") { - ds.connection.use { - val rs1 = it.createStatement().executeQuery("SELECT * FROM hashtags") - rs1.next() - rs1.getString("tag") shouldBe "startrek" - - it.createStatement().executeUpdate("INSERT INTO hashtags(tag) VALUES ('foo')") - - val rs2 = it.createStatement().executeQuery("SELECT count(*) FROM hashtags") - rs2.next() - rs2.getLong(1) shouldBe 2 - } - } - - it("this root test should have a different container container") { - ds.connection.use { - val rs = it.createStatement().executeQuery("SELECT count(*) FROM hashtags") - rs.next() - rs.getLong(1) shouldBe 1 - } - } - } - } -} diff --git a/src/test/kotlin/io/kotest/extensions/testcontainers/JdbcTestContainerExtensionRootTest.kt b/src/test/kotlin/io/kotest/extensions/testcontainers/JdbcTestContainerExtensionRootTest.kt deleted file mode 100644 index 1166238..0000000 --- a/src/test/kotlin/io/kotest/extensions/testcontainers/JdbcTestContainerExtensionRootTest.kt +++ /dev/null @@ -1,45 +0,0 @@ -package io.kotest.extensions.testcontainers - -import io.kotest.core.extensions.install -import io.kotest.core.spec.style.FunSpec -import io.kotest.matchers.shouldBe -import org.testcontainers.containers.MySQLContainer - -class JdbcTestContainerExtensionRootTest : FunSpec() { - init { - - val mysql = MySQLContainer("mysql:8.0.26").apply { - withInitScript("init.sql") - startupAttempts = 1 - withUrlParam("connectionTimeZone", "Z") - withUrlParam("zeroDateTimeBehavior", "convertToNull") - } - - val ds = install(JdbcTestContainerExtension(mysql, LifecycleMode.Root)) { - maximumPoolSize = 8 - minimumIdle = 4 - } - - test("should initialize per root") { - ds.connection.use { - val rs1 = it.createStatement().executeQuery("SELECT * FROM hashtags") - rs1.next() - rs1.getString("tag") shouldBe "startrek" - - it.createStatement().executeUpdate("INSERT INTO hashtags(tag) VALUES ('foo')") - - val rs2 = it.createStatement().executeQuery("SELECT count(*) FROM hashtags") - rs2.next() - rs2.getLong(1) shouldBe 2 - } - } - - test("this root test should have a different container") { - ds.connection.use { - val rs = it.createStatement().executeQuery("SELECT count(*) FROM hashtags") - rs.next() - rs.getLong(1) shouldBe 1 - } - } - } -} diff --git a/src/test/kotlin/io/kotest/extensions/testcontainers/KafkaTestContainerExtensionTest.kt b/src/test/kotlin/io/kotest/extensions/testcontainers/KafkaTestContainerExtensionTest.kt deleted file mode 100644 index d6abac3..0000000 --- a/src/test/kotlin/io/kotest/extensions/testcontainers/KafkaTestContainerExtensionTest.kt +++ /dev/null @@ -1,42 +0,0 @@ -package io.kotest.extensions.testcontainers - -import io.kotest.core.extensions.install -import io.kotest.core.spec.style.FunSpec -import io.kotest.extensions.testcontainers.kafka.createStringStringConsumer -import io.kotest.extensions.testcontainers.kafka.createStringStringProducer -import io.kotest.matchers.collections.shouldHaveSize -import org.apache.kafka.clients.consumer.ConsumerConfig -import org.apache.kafka.clients.producer.ProducerRecord -import org.testcontainers.containers.KafkaContainer -import org.testcontainers.utility.DockerImageName -import java.time.Duration - -@Deprecated("To be removed") -class KafkaTestContainerExtensionTest : FunSpec() { - init { - - val kafka = install(TestContainerExtension(KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.2.1")))) { - withEmbeddedZookeeper() - withEnv("KAFKA_AUTO_CREATE_TOPICS_ENABLE", "true") - withCreateContainerCmdModifier { it.withPlatform("linux/amd64") } - } - - test("should setup kafka") { - - val producer = kafka.createStringStringProducer() - producer.send(ProducerRecord("foo", "key", "bubble bobble")) - producer.flush() - producer.close() - - val consumer = kafka.createStringStringConsumer { - this[ConsumerConfig.MAX_POLL_RECORDS_CONFIG] = 1 - this[ConsumerConfig.AUTO_OFFSET_RESET_CONFIG] = "earliest" - } - - consumer.subscribe(listOf("foo")) - val records = consumer.poll(Duration.ofSeconds(15)) - records.shouldHaveSize(1) - consumer.close() - } - } -} diff --git a/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerExtensionLeafTest.kt b/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerExtensionLeafTest.kt deleted file mode 100644 index 038d5bc..0000000 --- a/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerExtensionLeafTest.kt +++ /dev/null @@ -1,30 +0,0 @@ -package io.kotest.extensions.testcontainers - -import io.kotest.core.extensions.install -import io.kotest.core.spec.style.DescribeSpec -import io.kotest.matchers.shouldBe -import redis.clients.jedis.JedisPool - -class TestContainerExtensionLeafTest : DescribeSpec() { - init { - - val container = install(TestContainerExtension("redis:5.0.3-alpine", LifecycleMode.Leaf)) { - startupAttempts = 1 - withExposedPorts(6379) - } - - describe("context") { - container.isRunning shouldBe false - it("should initialize per leaf") { - val jedis = JedisPool(container.host, container.firstMappedPort) - jedis.resource.set("foo", "bar") - jedis.resource.get("foo") shouldBe "bar" - } - - it("this test should have a new container") { - val jedis = JedisPool(container.host, container.firstMappedPort) - jedis.resource.get("foo") shouldBe null - } - } - } -} diff --git a/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerExtensionRootTest.kt b/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerExtensionRootTest.kt deleted file mode 100644 index 9590618..0000000 --- a/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerExtensionRootTest.kt +++ /dev/null @@ -1,27 +0,0 @@ -package io.kotest.extensions.testcontainers - -import io.kotest.core.extensions.install -import io.kotest.core.spec.style.FunSpec -import io.kotest.matchers.shouldBe -import redis.clients.jedis.JedisPool - -class TestContainerExtensionRootTest : FunSpec() { - init { - - val container = install(TestContainerExtension("redis:5.0.3-alpine", LifecycleMode.Root)) { - startupAttempts = 2 - withExposedPorts(6379) - } - - test("should initialize per root") { - val jedis = JedisPool(container.host, container.firstMappedPort) - jedis.resource.set("foo", "bar") - jedis.resource.get("foo") shouldBe "bar" - } - - test("this root test should have a different container") { - val jedis = JedisPool(container.host, container.firstMappedPort) - jedis.resource.get("foo") shouldBe null - } - } -} diff --git a/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerIntegrationPerSpec.kt b/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerIntegrationPerSpec.kt index e4104f0..87f55f9 100644 --- a/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerIntegrationPerSpec.kt +++ b/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerIntegrationPerSpec.kt @@ -5,7 +5,8 @@ import io.kotest.matchers.shouldBe class TestContainerIntegrationPerSpec : StringSpec({ - val testStartable = configurePerSpec(TestStartable()) + val testStartable = TestStartable() + listener(testStartable.perSpec()) "start count for first test should be one" { testStartable.startCount shouldBe 1 diff --git a/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerIntegrationPerTest.kt b/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerIntegrationPerTest.kt index 49b2c68..369e21c 100644 --- a/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerIntegrationPerTest.kt +++ b/src/test/kotlin/io/kotest/extensions/testcontainers/TestContainerIntegrationPerTest.kt @@ -5,7 +5,8 @@ import io.kotest.matchers.shouldBe class TestContainerIntegrationPerTest : StringSpec({ - val testStartable = configurePerTest(TestStartable()) + val testStartable = TestStartable() + listener(testStartable.perTest()) "start count for first test should be one" { testStartable.startCount shouldBe 1