locations) {
if (locations.isEmpty()) {
logger.warn("Empty locations for schema migration for engine '{}' for connection: {}",
getClass().getSimpleName(), connection);
diff --git a/cassandra/src/main/java/io/goodforgod/testcontainers/extensions/cassandra/TestcontainersCassandra.java b/cassandra/src/main/java/io/goodforgod/testcontainers/extensions/cassandra/TestcontainersCassandra.java
index e9b9045..46e9a3f 100644
--- a/cassandra/src/main/java/io/goodforgod/testcontainers/extensions/cassandra/TestcontainersCassandra.java
+++ b/cassandra/src/main/java/io/goodforgod/testcontainers/extensions/cassandra/TestcontainersCassandra.java
@@ -5,9 +5,10 @@
import java.lang.annotation.*;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.testcontainers.containers.CassandraContainer;
/**
- * Extension that is running {@link CassandraContainerExtra} for tests in different modes with
+ * Extension that is running {@link CassandraContainer} for tests in different modes with
* database
* schema migration support between test executions
*/
@@ -26,7 +27,6 @@
* 3) Image environment variable can have default value if empty using syntax:
* "${MY_IMAGE_ENV|cassandra:4.1}"
*
- * @see TestcontainersCassandraExtension#getContainerDefault(CassandraMetadata)
*/
String image() default "cassandra:4.1";
@@ -43,5 +43,5 @@
Migration migration() default @Migration(engine = Migration.Engines.SCRIPTS,
apply = Migration.Mode.NONE,
drop = Migration.Mode.NONE,
- migrations = {});
+ locations = {});
}
diff --git a/cassandra/src/main/java/io/goodforgod/testcontainers/extensions/cassandra/TestcontainersCassandraExtension.java b/cassandra/src/main/java/io/goodforgod/testcontainers/extensions/cassandra/TestcontainersCassandraExtension.java
index de5accc..23ef681 100644
--- a/cassandra/src/main/java/io/goodforgod/testcontainers/extensions/cassandra/TestcontainersCassandraExtension.java
+++ b/cassandra/src/main/java/io/goodforgod/testcontainers/extensions/cassandra/TestcontainersCassandraExtension.java
@@ -1,35 +1,66 @@
package io.goodforgod.testcontainers.extensions.cassandra;
import io.goodforgod.testcontainers.extensions.AbstractTestcontainersExtension;
+import io.goodforgod.testcontainers.extensions.ContainerContext;
import io.goodforgod.testcontainers.extensions.ContainerMode;
import java.lang.annotation.Annotation;
+import java.time.Duration;
import java.util.*;
import org.jetbrains.annotations.ApiStatus.Internal;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.extension.ExtensionConfigurationException;
import org.junit.jupiter.api.extension.ExtensionContext;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.CassandraContainer;
import org.testcontainers.containers.Network;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.DockerImageName;
@Internal
class TestcontainersCassandraExtension extends
- AbstractTestcontainersExtension, CassandraMetadata> {
+ AbstractTestcontainersExtension, CassandraMetadata> {
private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace
.create(TestcontainersCassandraExtension.class);
+ @SuppressWarnings("unchecked")
+ protected Class> getContainerType() {
+ return (Class>) ((Class>) CassandraContainer.class);
+ }
+
+ protected Class extends Annotation> getContainerAnnotation() {
+ return ContainerCassandra.class;
+ }
+
+ protected Class extends Annotation> getConnectionAnnotation() {
+ return ConnectionCassandra.class;
+ }
+
+ @Override
+ protected ExtensionContext.Namespace getNamespace() {
+ return NAMESPACE;
+ }
+
@Override
protected Class getConnectionType() {
return CassandraConnection.class;
}
@Override
- protected CassandraContainerExtra> getContainerDefault(CassandraMetadata metadata) {
- var dockerImage = DockerImageName.parse(metadata.image())
+ protected CassandraContainer> createContainerDefault(CassandraMetadata metadata) {
+ var image = DockerImageName.parse(metadata.image())
.asCompatibleSubstituteFor(DockerImageName.parse("cassandra"));
- var container = new CassandraContainerExtra<>(dockerImage);
- container.setNetworkAliases(new ArrayList<>(List.of(metadata.networkAliasOrDefault())));
+ final CassandraContainer> container = new CassandraContainer<>(image);
+ final String alias = Optional.ofNullable(metadata.networkAlias())
+ .orElseGet(() -> "cassandra-" + System.currentTimeMillis());
+ container.withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger(CassandraContainer.class))
+ .withMdc("image", image.asCanonicalNameString())
+ .withMdc("alias", alias));
+ container.waitingFor(Wait.forListeningPort());
+ container.withStartupTimeout(Duration.ofMinutes(5));
+ container.setNetworkAliases(new ArrayList<>(List.of(alias)));
if (metadata.networkShared()) {
container.withNetwork(Network.SHARED);
}
@@ -38,21 +69,8 @@ protected CassandraContainerExtra> getContainerDefault(CassandraMetadata metad
}
@Override
- protected ExtensionContext.Namespace getNamespace() {
- return NAMESPACE;
- }
-
- @SuppressWarnings("unchecked")
- protected Class> getContainerType() {
- return (Class>) ((Class>) CassandraContainerExtra.class);
- }
-
- protected Class extends Annotation> getContainerAnnotation() {
- return ContainerCassandra.class;
- }
-
- protected Class extends Annotation> getConnectionAnnotation() {
- return ContainerCassandraConnection.class;
+ protected ContainerContext createContainerContext(CassandraContainer> container) {
+ return new CassandraContext(container);
}
@NotNull
@@ -61,20 +79,15 @@ protected Optional findMetadata(@NotNull ExtensionContext con
.map(a -> new CassandraMetadata(a.network().shared(), a.network().alias(), a.image(), a.mode(), a.migration()));
}
- @NotNull
- protected CassandraConnection getConnectionForContainer(CassandraMetadata metadata, CassandraContainerExtra> container) {
- return container.connection();
- }
-
private void tryMigrateIfRequired(CassandraMetadata annotation, CassandraConnection connection) {
if (annotation.migration().engine() == Migration.Engines.SCRIPTS) {
- new ScriptCassandraMigrationEngine(connection).migrate(Arrays.asList(annotation.migration().migrations()));
+ new ScriptCassandraMigrationEngine(connection).apply(Arrays.asList(annotation.migration().locations()));
}
}
private void tryDropIfRequired(CassandraMetadata annotation, CassandraConnection connection) {
if (annotation.migration().engine() == Migration.Engines.SCRIPTS) {
- new ScriptCassandraMigrationEngine(connection).drop(Arrays.asList(annotation.migration().migrations()));
+ new ScriptCassandraMigrationEngine(connection).drop(Arrays.asList(annotation.migration().locations()));
}
}
@@ -85,7 +98,7 @@ public void beforeAll(ExtensionContext context) {
var metadata = getMetadata(context);
if (metadata.migration().apply() == Migration.Mode.PER_CLASS) {
var storage = getStorage(context);
- var connectionCurrent = getConnectionCurrent(context);
+ var connectionCurrent = getContainerContext(context).connection();
tryMigrateIfRequired(metadata, connectionCurrent);
storage.put(Migration.class, metadata.migration().apply());
}
@@ -103,7 +116,7 @@ public void beforeEach(ExtensionContext context) {
super.beforeEach(context);
if (metadata.migration().apply() == Migration.Mode.PER_METHOD) {
- var connectionCurrent = getConnectionCurrent(context);
+ var connectionCurrent = getContainerContext(context).connection();
tryMigrateIfRequired(metadata, connectionCurrent);
}
}
@@ -115,7 +128,7 @@ public void afterEach(ExtensionContext context) {
storage.remove(Migration.class);
if (metadata.migration().drop() == Migration.Mode.PER_METHOD) {
if (metadata.runMode() != ContainerMode.PER_METHOD) {
- var connectionCurrent = getConnectionCurrent(context);
+ var connectionCurrent = getContainerContext(context).connection();
tryDropIfRequired(metadata, connectionCurrent);
}
}
@@ -126,7 +139,7 @@ public void afterEach(ExtensionContext context) {
@Override
public void afterAll(ExtensionContext context) {
var metadata = getMetadata(context);
- var connectionCurrent = getConnectionCurrent(context);
+ var connectionCurrent = getContainerContext(context).connection();
if (metadata.migration().drop() == Migration.Mode.PER_CLASS) {
if (metadata.runMode() == ContainerMode.PER_RUN) {
tryDropIfRequired(metadata, connectionCurrent);
diff --git a/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraConnectionAssertsTests.java b/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraConnectionAssertsTests.java
index bf1f24a..0c21d6a 100644
--- a/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraConnectionAssertsTests.java
+++ b/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraConnectionAssertsTests.java
@@ -11,29 +11,29 @@
engine = Migration.Engines.SCRIPTS,
apply = Migration.Mode.PER_METHOD,
drop = Migration.Mode.PER_METHOD,
- migrations = { "migration/setup.cql" }))
+ locations = { "migration/setup.cql" }))
class CassandraConnectionAssertsTests {
@Test
- void execute(@ContainerCassandraConnection CassandraConnection connection) {
+ void execute(@ConnectionCassandra CassandraConnection connection) {
assertThrows(CassandraConnectionException.class,
() -> connection.execute("CREATE TABLE cassandra.users(id INT, PRIMARY KEY (id))"));
}
@Test
- void executeFromResources(@ContainerCassandraConnection CassandraConnection connection) {
+ void executeFromResources(@ConnectionCassandra CassandraConnection connection) {
connection.executeFromResources("migration/setup.cql");
}
@Test
- void queryOne(@ContainerCassandraConnection CassandraConnection connection) {
+ void queryOne(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
var usersFound = connection.queryOne("SELECT * FROM cassandra.users;", r -> r.getInt(0)).orElse(null);
assertEquals(1, usersFound);
}
@Test
- void queryMany(@ContainerCassandraConnection CassandraConnection connection) {
+ void queryMany(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
connection.execute("INSERT INTO cassandra.users(id) VALUES(2);");
var usersFound = connection.queryMany("SELECT * FROM cassandra.users;", r -> r.getInt(0));
@@ -41,148 +41,148 @@ void queryMany(@ContainerCassandraConnection CassandraConnection connection) {
}
@Test
- void count(@ContainerCassandraConnection CassandraConnection connection) {
+ void count(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
assertEquals(1, connection.count("cassandra.users"));
}
@Test
- void assertCountsNoneWhenMore(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertCountsNoneWhenMore(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
assertThrows(AssertionFailedError.class, () -> connection.assertCountsNone("cassandra.users"));
}
@Test
- void assertCountsNoneWhenZero(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertCountsNoneWhenZero(@ConnectionCassandra CassandraConnection connection) {
assertDoesNotThrow(() -> connection.assertCountsNone("cassandra.users"));
}
@Test
- void assertCountsAtLeastWhenZero(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertCountsAtLeastWhenZero(@ConnectionCassandra CassandraConnection connection) {
assertThrows(AssertionFailedError.class, () -> connection.assertCountsAtLeast(1, "cassandra.users"));
}
@Test
- void assertCountsAtLeastWhenMore(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertCountsAtLeastWhenMore(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
connection.execute("INSERT INTO cassandra.users(id) VALUES(2);");
assertDoesNotThrow(() -> connection.assertCountsAtLeast(1, "cassandra.users"));
}
@Test
- void assertCountsAtLeastWhenEquals(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertCountsAtLeastWhenEquals(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
assertDoesNotThrow(() -> connection.assertCountsAtLeast(1, "cassandra.users"));
}
@Test
- void assertCountsExactWhenZero(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertCountsExactWhenZero(@ConnectionCassandra CassandraConnection connection) {
assertThrows(AssertionFailedError.class, () -> connection.assertCountsEquals(1, "cassandra.users"));
}
@Test
- void assertCountsExactWhenMore(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertCountsExactWhenMore(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
connection.execute("INSERT INTO cassandra.users(id) VALUES(2);");
assertThrows(AssertionFailedError.class, () -> connection.assertCountsEquals(1, "cassandra.users"));
}
@Test
- void assertCountsExactWhenEquals(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertCountsExactWhenEquals(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
assertDoesNotThrow(() -> connection.assertCountsEquals(1, "cassandra.users"));
}
@Test
- void assertQueriesNoneWhenMore(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertQueriesNoneWhenMore(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
assertThrows(AssertionFailedError.class, () -> connection.assertQueriesNone("SELECT * FROM cassandra.users;"));
}
@Test
- void assertQueriesNoneWhenZero(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertQueriesNoneWhenZero(@ConnectionCassandra CassandraConnection connection) {
assertDoesNotThrow(() -> connection.assertQueriesNone("SELECT * FROM cassandra.users;"));
}
@Test
- void assertQueriesAtLeastWhenZero(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertQueriesAtLeastWhenZero(@ConnectionCassandra CassandraConnection connection) {
assertThrows(AssertionFailedError.class, () -> connection.assertQueriesAtLeast(1, "SELECT * FROM cassandra.users;"));
}
@Test
- void assertQueriesAtLeastWhenMore(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertQueriesAtLeastWhenMore(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
connection.execute("INSERT INTO cassandra.users(id) VALUES(2);");
assertDoesNotThrow(() -> connection.assertQueriesAtLeast(1, "SELECT * FROM cassandra.users;"));
}
@Test
- void assertQueriesAtLeastWhenEquals(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertQueriesAtLeastWhenEquals(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
assertDoesNotThrow(() -> connection.assertQueriesAtLeast(1, "SELECT * FROM cassandra.users;"));
}
@Test
- void assertQueriesExactWhenZero(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertQueriesExactWhenZero(@ConnectionCassandra CassandraConnection connection) {
assertThrows(AssertionFailedError.class, () -> connection.assertQueriesEquals(1, "SELECT * FROM cassandra.users;"));
}
@Test
- void assertQueriesExactWhenMore(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertQueriesExactWhenMore(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
connection.execute("INSERT INTO cassandra.users(id) VALUES(2);");
assertThrows(AssertionFailedError.class, () -> connection.assertQueriesEquals(1, "SELECT * FROM cassandra.users;"));
}
@Test
- void assertQueriesExactWhenEquals(@ContainerCassandraConnection CassandraConnection connection) {
+ void assertQueriesExactWhenEquals(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
assertDoesNotThrow(() -> connection.assertQueriesEquals(1, "SELECT * FROM cassandra.users;"));
}
@Test
- void checkQueriesNoneWhenMore(@ContainerCassandraConnection CassandraConnection connection) {
+ void checkQueriesNoneWhenMore(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
assertFalse(connection.checkQueriesNone("SELECT * FROM cassandra.users;"));
}
@Test
- void checkQueriesNoneWhenZero(@ContainerCassandraConnection CassandraConnection connection) {
+ void checkQueriesNoneWhenZero(@ConnectionCassandra CassandraConnection connection) {
assertTrue(connection.checkQueriesNone("SELECT * FROM cassandra.users;"));
}
@Test
- void checkQueriesAtLeastWhenZero(@ContainerCassandraConnection CassandraConnection connection) {
+ void checkQueriesAtLeastWhenZero(@ConnectionCassandra CassandraConnection connection) {
assertFalse(connection.checkQueriesAtLeast(1, "SELECT * FROM cassandra.users;"));
}
@Test
- void checkQueriesAtLeastWhenMore(@ContainerCassandraConnection CassandraConnection connection) {
+ void checkQueriesAtLeastWhenMore(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
connection.execute("INSERT INTO cassandra.users(id) VALUES(2);");
assertTrue(connection.checkQueriesAtLeast(1, "SELECT * FROM cassandra.users;"));
}
@Test
- void checkQueriesAtLeastWhenEquals(@ContainerCassandraConnection CassandraConnection connection) {
+ void checkQueriesAtLeastWhenEquals(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
assertTrue(connection.checkQueriesAtLeast(1, "SELECT * FROM cassandra.users;"));
}
@Test
- void checkQueriesExactWhenZero(@ContainerCassandraConnection CassandraConnection connection) {
+ void checkQueriesExactWhenZero(@ConnectionCassandra CassandraConnection connection) {
assertFalse(connection.checkQueriesEquals(1, "SELECT * FROM cassandra.users;"));
}
@Test
- void checkQueriesExactWhenMore(@ContainerCassandraConnection CassandraConnection connection) {
+ void checkQueriesExactWhenMore(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
connection.execute("INSERT INTO cassandra.users(id) VALUES(2);");
assertFalse(connection.checkQueriesEquals(1, "SELECT * FROM cassandra.users;"));
}
@Test
- void checkQueriesExactWhenEquals(@ContainerCassandraConnection CassandraConnection connection) {
+ void checkQueriesExactWhenEquals(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
assertTrue(connection.checkQueriesEquals(1, "SELECT * FROM cassandra.users;"));
}
diff --git a/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraExtraMigrationTests.java b/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraExtraMigrationTests.java
deleted file mode 100644
index 292bb41..0000000
--- a/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraExtraMigrationTests.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package io.goodforgod.testcontainers.extensions.cassandra;
-
-import java.util.List;
-import org.junit.jupiter.api.Test;
-import org.testcontainers.utility.DockerImageName;
-
-class CassandraExtraMigrationTests {
-
- @Test
- void script() {
- try (var container = new CassandraContainerExtra<>(DockerImageName.parse("cassandra:4.1"))) {
- container.start();
- ScriptCassandraMigrationEngine scriptCassandraMigrationEngine = new ScriptCassandraMigrationEngine(
- container.connection());
- scriptCassandraMigrationEngine.migrate(List.of("migration"));
- container.connection().assertQueriesNone("SELECT * FROM cassandra.users;");
- scriptCassandraMigrationEngine.drop(List.of("migration"));
- }
- }
-}
diff --git a/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraSimplePerClassMigrationTests.java b/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraSimplePerClassMigrationTests.java
index a3eeb69..02a677d 100644
--- a/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraSimplePerClassMigrationTests.java
+++ b/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraSimplePerClassMigrationTests.java
@@ -11,31 +11,31 @@
engine = Migration.Engines.SCRIPTS,
apply = Migration.Mode.PER_CLASS,
drop = Migration.Mode.PER_CLASS,
- migrations = { "migration" }))
+ locations = { "migration" }))
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class CassandraSimplePerClassMigrationTests {
@BeforeAll
- public static void setupAll(@ContainerCassandraConnection CassandraConnection paramConnection) {
+ public static void setupAll(@ConnectionCassandra CassandraConnection paramConnection) {
paramConnection.queryOne("SELECT * FROM cassandra.users;", r -> r.getInt(0));
assertNotNull(paramConnection);
}
@BeforeEach
- public void setupEach(@ContainerCassandraConnection CassandraConnection paramConnection) {
+ public void setupEach(@ConnectionCassandra CassandraConnection paramConnection) {
paramConnection.queryOne("SELECT * FROM cassandra.users;", r -> r.getInt(0));
assertNotNull(paramConnection);
}
@Order(1)
@Test
- void firstRun(@ContainerCassandraConnection CassandraConnection connection) {
+ void firstRun(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
}
@Order(2)
@Test
- void secondRun(@ContainerCassandraConnection CassandraConnection connection) {
+ void secondRun(@ConnectionCassandra CassandraConnection connection) {
var usersFound = connection.queryOne("SELECT * FROM cassandra.users;", r -> r.getInt(0)).orElse(null);
assertEquals(1, usersFound);
}
diff --git a/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraSimplePerMethodMigrationTests.java b/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraSimplePerMethodMigrationTests.java
index c195c2d..30d450c 100644
--- a/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraSimplePerMethodMigrationTests.java
+++ b/cassandra/src/test/java/io/goodforgod/testcontainers/extensions/cassandra/CassandraSimplePerMethodMigrationTests.java
@@ -11,25 +11,25 @@
engine = Migration.Engines.SCRIPTS,
apply = Migration.Mode.PER_METHOD,
drop = Migration.Mode.PER_METHOD,
- migrations = { "migration" }))
+ locations = { "migration" }))
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class CassandraSimplePerMethodMigrationTests {
@BeforeEach
- public void setupEach(@ContainerCassandraConnection CassandraConnection paramConnection) {
+ public void setupEach(@ConnectionCassandra CassandraConnection paramConnection) {
paramConnection.queryOne("SELECT * FROM cassandra.users;", r -> r.getInt(0));
assertNotNull(paramConnection);
}
@Order(1)
@Test
- void firstRun(@ContainerCassandraConnection CassandraConnection connection) {
+ void firstRun(@ConnectionCassandra CassandraConnection connection) {
connection.execute("INSERT INTO cassandra.users(id) VALUES(1);");
}
@Order(2)
@Test
- void secondRun(@ContainerCassandraConnection CassandraConnection connection) {
+ void secondRun(@ConnectionCassandra CassandraConnection connection) {
var usersFound = connection.queryOne("SELECT * FROM cassandra.users;", r -> r.getInt(1));
assertTrue(usersFound.isEmpty());
}
diff --git a/cockroachdb/README.md b/cockroachdb/README.md
index d7b5d92..f1a67ed 100644
--- a/cockroachdb/README.md
+++ b/cockroachdb/README.md
@@ -18,7 +18,7 @@ Features:
**Gradle**
```groovy
-testImplementation "io.goodforgod:testcontainers-extensions-cockroachdb:0.9.6"
+testImplementation "io.goodforgod:testcontainers-extensions-cockroachdb:0.10.0"
```
**Maven**
@@ -26,7 +26,7 @@ testImplementation "io.goodforgod:testcontainers-extensions-cockroachdb:0.9.6"
io.goodforgod
testcontainers-extensions-cockroachdb
- 0.9.6
+ 0.10.0
test
```
@@ -52,9 +52,8 @@ testRuntimeOnly "org.postgresql:postgresql:42.6.0"
## Content
- [Usage](#usage)
-- [Container](#container)
- - [Connection](#container-connection)
- - [Migration](#container-migration)
+- [Connection](#connection)
+ - [Migration](#connection-migration)
- [Annotation](#annotation)
- [Manual Container](#manual-container)
- [Connection](#annotation-connection)
@@ -66,15 +65,18 @@ testRuntimeOnly "org.postgresql:postgresql:42.6.0"
Test with container start in `PER_RUN` mode and migration per method will look like:
```java
-@TestcontainersCockroachdb(mode = ContainerMode.PER_RUN,
+@TestcontainersCockroach(mode = ContainerMode.PER_RUN,
migration = @Migration(
engine = Migration.Engines.FLYWAY,
apply = Migration.Mode.PER_METHOD,
drop = Migration.Mode.PER_METHOD))
class ExampleTests {
+ @ConnectionCockroach
+ private JdbcConnection connection;
+
@Test
- void test(@ContainerCockroachdbConnection JdbcConnection connection) {
+ void test() {
connection.execute("INSERT INTO users VALUES(1);");
var usersFound = connection.queryMany("SELECT * FROM users;", r -> r.getInt(1));
assertEquals(1, usersFound.size());
@@ -82,56 +84,50 @@ class ExampleTests {
}
```
-## Container
+## Connection
-Library provides special `CockorackContainerExtra` with ability for migration and connection.
-It can be used with [Testcontainers JUnit Extension](https://java.testcontainers.org/test_framework_integration/junit_5/).
+`JdbcConnection` is an abstraction with asserting data in database container and easily manipulate container connection settings.
+You can inject connection via `@ConnectionCockroach` as field or method argument or manually create it from container or manual settings.
```java
class ExampleTests {
+ private static final CockroachContainer container = new CockroachContainer();
+
@Test
void test() {
- try (var container = new CockorackContainerExtra(DockerImageName.parse("cockroachdb/cockroach:latest-v23.1"))) {
- container.start();
- }
+ container.start();
+ JdbcConnection connection = JdbcConnection.forContainer(container);
+ connection.execute("INSERT INTO users VALUES(1);");
}
}
```
-### Container Connection
+### Connection Migration
-`JdbcConnection` provides connection parameters, useful asserts, checks, etc. for easier testing.
+`Migrations` allow easily migrate database between test executions and drop after tests.
+You can migrate container via `@TestcontainersCockroach#migration` annotation parameter or manually using `JdbcConnection`.
```java
+@TestcontainersCockroach
class ExampleTests {
- @Test
- void test() {
- try (var container = new CockorackContainerExtra(DockerImageName.parse("cockroachdb/cockroach:latest-v23.1"))) {
- container.start();
- container.connection().assertQueriesNone("SELECT * FROM users;");
+ @Test
+ void test(@ConnectionCockroach JdbcConnection connection) {
+ connection.migrationEngine(Migration.Engines.FLYWAY).apply("db/migration");
+ connection.execute("INSERT INTO users VALUES(1);");
+ connection.migrationEngine(Migration.Engines.FLYWAY).drop("db/migration");
}
- }
}
```
-### Container Migration
-
-`Migrations` allow easily migrate database between test executions and drop after tests.
-
-Annotation parameters:
-- `engine` - to use for migration.
-- `apply` - parameter configures migration mode.
-- `drop` - configures when to reset/drop/clear database.
-
Available migration engines:
- [Flyway](https://documentation.red-gate.com/fd/cockroachdb-184127591.html)
- [Liquibase](https://www.liquibase.com/databases/cockroachdb-2)
## Annotation
-`@TestcontainersCockroachdb` - allow **automatically start container** with specified image in different modes without the need to configure it.
+`@TestcontainersCockroach` - allow **automatically start container** with specified image in different modes without the need to configure it.
Available containers modes:
@@ -141,11 +137,11 @@ Available containers modes:
Simple example on how to start container per class, **no need to configure** container:
```java
-@TestcontainersCockroachdb(mode = ContainerMode.PER_CLASS)
+@TestcontainersCockroach(mode = ContainerMode.PER_CLASS)
class ExampleTests {
@Test
- void test(@ContainerCockroachdbConnection JdbcConnection connection) {
+ void test(@ConnectionCockroach JdbcConnection connection) {
assertNotNull(connection);
}
}
@@ -157,7 +153,7 @@ It is possible to customize image with annotation `image` parameter.
Image also can be provided from environment variable:
```java
-@TestcontainersCockroachdb(image = "${MY_IMAGE_ENV|cockroachdb/cockroach:latest-v23.1}")
+@TestcontainersCockroach(image = "${MY_IMAGE_ENV|cockroachdb/cockroach:latest-v23.1}")
class ExampleTests {
@Test
@@ -175,19 +171,19 @@ Image syntax:
### Manual Container
-When you need to **manually configure container** with specific options, you can provide such container as instance that will be used by `@TestcontainersCockroachdb`,
-this can be done using `@ContainerCockroachdb` annotation for container.
+When you need to **manually configure container** with specific options, you can provide such container as instance that will be used by `@TestcontainersCockroach`,
+this can be done using `@ContainerCockroach` annotation for container.
Example:
```java
-@TestcontainersCockroachdb(mode = ContainerMode.PER_CLASS)
+@TestcontainersCockroach(mode = ContainerMode.PER_CLASS)
class ExampleTests {
- @ContainerCockroachdb
- private static final CockroachContainer container = new CockroachContainer(dockerImage);
+ @ContainerCockroach
+ private static final CockroachContainer container = new CockroachContainer();
@Test
- void test(@ContainerCockroachdbConnection JdbcConnection connection) {
+ void test(@ConnectionCockroach JdbcConnection connection) {
// do something
}
}
@@ -197,7 +193,7 @@ class ExampleTests {
In case you want to enable [Network.SHARED](https://java.testcontainers.org/features/networking/) for containers you can do this using `network` & `shared` parameter in annotation:
```java
-@TestcontainersCockroachdb(network = @Network(shared = true))
+@TestcontainersCockroach(network = @Network(shared = true))
class ExampleTests {
@Test
@@ -214,7 +210,7 @@ Alias can be extracted from environment variable also or default value can be pr
In case specified environment variable is missing `default alias` will be created:
```java
-@TestcontainersCockroachdb(network = @Network(alias = "${MY_ALIAS_ENV|my_default_alias}"))
+@TestcontainersCockroach(network = @Network(alias = "${MY_ALIAS_ENV|my_default_alias}"))
class ExampleTests {
@Test
@@ -232,19 +228,19 @@ Image syntax:
### Annotation Connection
-`JdbcConnection` - can be injected to field or method parameter and used to communicate with running container via `@ContainerCockroachdbConnection` annotation.
+`JdbcConnection` - can be injected to field or method parameter and used to communicate with running container via `@ConnectionCockroach` annotation.
`JdbcConnection` provides connection parameters, useful asserts, checks, etc. for easier testing.
Example:
```java
-@TestcontainersCockroachdb(mode = ContainerMode.PER_CLASS, image = "cockroachdb/cockroach:latest-v23.1")
+@TestcontainersCockroach(mode = ContainerMode.PER_CLASS, image = "cockroachdb/cockroach:latest-v23.1")
class ExampleTests {
- @ContainerCockroachdbConnection
- private JdbcConnection connectionInField;
+ @ConnectionCockroach
+ private JdbcConnection connection;
@Test
- void test(@ContainerCockroachdbConnection JdbcConnection connection) {
+ void test() {
connection.execute("CREATE TABLE users (id INT NOT NULL PRIMARY KEY);");
connection.execute("INSERT INTO users VALUES(1);");
connection.assertInserted("INSERT INTO users VALUES(2);");
@@ -261,17 +257,17 @@ In case you want to use some external Cockroachdb instance that is running in CI
you can use special *environment variables* and extension will use them to propagate connection and no Cockroachdb containers will be running in such case.
Special environment variables:
-- `EXTERNAL_TEST_COCKROACHDB_JDBC_URL` - Cockroachdb instance JDBC url.
-- `EXTERNAL_TEST_COCKROACHDB_USERNAME` - Cockroachdb instance username (optional).
-- `EXTERNAL_TEST_COCKROACHDB_PASSWORD` - Cockroachdb instance password (optional).
-- `EXTERNAL_TEST_COCKROACHDB_HOST` - Cockroachdb instance host (optional if JDBC url specified).
-- `EXTERNAL_TEST_COCKROACHDB_PORT` - Cockroachdb instance port (optional if JDBC url specified).
-- `EXTERNAL_TEST_COCKROACHDB_DATABASE` - Cockroachdb instance database (`cockroachdb` by default) (optional if JDBC url specified)
+- `EXTERNAL_TEST_COCKROACH_JDBC_URL` - Cockroachdb instance JDBC url.
+- `EXTERNAL_TEST_COCKROACH_USERNAME` - Cockroachdb instance username (optional).
+- `EXTERNAL_TEST_COCKROACH_PASSWORD` - Cockroachdb instance password (optional).
+- `EXTERNAL_TEST_COCKROACH_HOST` - Cockroachdb instance host (optional if JDBC url specified).
+- `EXTERNAL_TEST_COCKROACH_PORT` - Cockroachdb instance port (optional if JDBC url specified).
+- `EXTERNAL_TEST_COCKROACH_DATABASE` - Cockroachdb instance database (`cockroachdb` by default) (optional if JDBC url specified)
-Use can use either `EXTERNAL_TEST_COCKROACHDB_JDBC_URL` to specify connection with username & password combination
-or use combination of `EXTERNAL_TEST_COCKROACHDB_HOST` & `EXTERNAL_TEST_COCKROACHDB_PORT` & `EXTERNAL_TEST_COCKROACHDB_DATABASE`.
+Use can use either `EXTERNAL_TEST_COCKROACH_JDBC_URL` to specify connection with username & password combination
+or use combination of `EXTERNAL_TEST_COCKROACH_HOST` & `EXTERNAL_TEST_COCKROACH_PORT` & `EXTERNAL_TEST_COCKROACH_DATABASE`.
-`EXTERNAL_TEST_COCKROACHDB_JDBC_URL` env have higher priority over host & port & database.
+`EXTERNAL_TEST_COCKROACH_JDBC_URL` env have higher priority over host & port & database.
### Annotation Migration
@@ -281,6 +277,7 @@ Annotation parameters:
- `engine` - to use for migration.
- `apply` - parameter configures migration mode.
- `drop` - configures when to reset/drop/clear database.
+- `locations` - configures locations where migrations are placed.
Available migration engines:
- [Flyway](https://documentation.red-gate.com/fd/cockroachdb-184127591.html)
@@ -296,7 +293,7 @@ CREATE TABLE IF NOT EXISTS users
Test with container and migration per method will look like:
```java
-@TestcontainersCockroachdb(mode = ContainerMode.PER_CLASS,
+@TestcontainersCockroach(mode = ContainerMode.PER_CLASS,
migration = @Migration(
engine = Migration.Engines.FLYWAY,
apply = Migration.Mode.PER_METHOD,
@@ -304,7 +301,7 @@ Test with container and migration per method will look like:
class ExampleTests {
@Test
- void test(@ContainerCockroachdbConnection JdbcConnection connection) {
+ void test(@ConnectionCockroach JdbcConnection connection) {
connection.execute("INSERT INTO users VALUES(1);");
var usersFound = connection.queryMany("SELECT * FROM users;", r -> r.getInt(1));
assertEquals(1, usersFound.size());
diff --git a/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachContainerExtra.java b/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachContainerExtra.java
deleted file mode 100644
index 19be85e..0000000
--- a/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachContainerExtra.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package io.goodforgod.testcontainers.extensions.jdbc;
-
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import org.jetbrains.annotations.ApiStatus.Internal;
-import org.jetbrains.annotations.NotNull;
-import org.slf4j.LoggerFactory;
-import org.testcontainers.containers.CockroachContainer;
-import org.testcontainers.containers.output.Slf4jLogConsumer;
-import org.testcontainers.utility.DockerImageName;
-
-public class CockroachContainerExtra extends CockroachContainer {
-
- private static final String PROTOCOL = "postgresql";
- private static final int PORT = 26257;
-
- private static final String EXTERNAL_TEST_COCKROACHDB_JDBC_URL = "EXTERNAL_TEST_COCKROACHDB_JDBC_URL";
- private static final String EXTERNAL_TEST_COCKROACHDB_USERNAME = "EXTERNAL_TEST_COCKROACHDB_USERNAME";
- private static final String EXTERNAL_TEST_COCKROACHDB_PASSWORD = "EXTERNAL_TEST_COCKROACHDB_PASSWORD";
- private static final String EXTERNAL_TEST_COCKROACHDB_HOST = "EXTERNAL_TEST_COCKROACHDB_HOST";
- private static final String EXTERNAL_TEST_COCKROACHDB_PORT = "EXTERNAL_TEST_COCKROACHDB_PORT";
- private static final String EXTERNAL_TEST_COCKROACHDB_DATABASE = "EXTERNAL_TEST_COCKROACHDB_DATABASE";
-
- private volatile JdbcConnectionImpl connection;
- private volatile FlywayJdbcMigrationEngine flywayJdbcMigrationEngine;
- private volatile LiquibaseJdbcMigrationEngine liquibaseJdbcMigrationEngine;
-
- public CockroachContainerExtra(String dockerImageName) {
- this(DockerImageName.parse(dockerImageName));
- }
-
- public CockroachContainerExtra(DockerImageName dockerImageName) {
- super(dockerImageName);
-
- final String alias = "cockroachdb-" + System.currentTimeMillis();
- this.withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger(CockroachContainerExtra.class))
- .withMdc("image", dockerImageName.asCanonicalNameString())
- .withMdc("alias", alias));
- this.withStartupTimeout(Duration.ofMinutes(5));
-
- this.setNetworkAliases(new ArrayList<>(List.of(alias)));
- }
-
- @Internal
- JdbcMigrationEngine getMigrationEngine(@NotNull Migration.Engines engine) {
- if (engine == Migration.Engines.FLYWAY) {
- if (flywayJdbcMigrationEngine == null) {
- this.flywayJdbcMigrationEngine = new FlywayJdbcMigrationEngine(connection());
- }
- return this.flywayJdbcMigrationEngine;
- } else if (engine == Migration.Engines.LIQUIBASE) {
- if (liquibaseJdbcMigrationEngine == null) {
- this.liquibaseJdbcMigrationEngine = new LiquibaseJdbcMigrationEngine(connection());
- }
- return this.liquibaseJdbcMigrationEngine;
- } else {
- throw new UnsupportedOperationException("Unsupported engine: " + engine);
- }
- }
-
- @NotNull
- public JdbcConnection connection() {
- if (connection == null) {
- final Optional connectionExternal = getConnectionExternal();
- if (connectionExternal.isEmpty() && !isRunning()) {
- throw new IllegalStateException("MariadbConnection can't be create for container that is not running");
- }
-
- final JdbcConnection jdbcConnection = connectionExternal.orElseGet(() -> {
- final String alias = getNetworkAliases().get(getNetworkAliases().size() - 1);
- return JdbcConnectionImpl.forJDBC(getJdbcUrl(),
- getHost(),
- getMappedPort(PORT),
- alias,
- PORT,
- getDatabaseName(),
- getUsername(),
- getPassword());
- });
-
- this.connection = (JdbcConnectionImpl) jdbcConnection;
- }
-
- return connection;
- }
-
- @Override
- public void start() {
- final Optional connectionExternal = getConnectionExternal();
- if (connectionExternal.isEmpty()) {
- super.start();
- }
- }
-
- @Override
- public void stop() {
- if (flywayJdbcMigrationEngine != null) {
- flywayJdbcMigrationEngine.close();
- flywayJdbcMigrationEngine = null;
- }
- if (liquibaseJdbcMigrationEngine != null) {
- liquibaseJdbcMigrationEngine.close();
- liquibaseJdbcMigrationEngine = null;
- }
- if (connection != null) {
- connection.close();
- connection = null;
- }
- super.stop();
- }
-
- @NotNull
- private static Optional getConnectionExternal() {
- var url = System.getenv(EXTERNAL_TEST_COCKROACHDB_JDBC_URL);
- var host = System.getenv(EXTERNAL_TEST_COCKROACHDB_HOST);
- var port = System.getenv(EXTERNAL_TEST_COCKROACHDB_PORT);
- var user = System.getenv(EXTERNAL_TEST_COCKROACHDB_USERNAME);
- var password = System.getenv(EXTERNAL_TEST_COCKROACHDB_PASSWORD);
-
- var db = Optional.ofNullable(System.getenv(EXTERNAL_TEST_COCKROACHDB_DATABASE)).orElse("cockroachdb");
- if (url != null) {
- if (host != null && port != null) {
- return Optional.of(JdbcConnectionImpl.forJDBC(url, host, Integer.parseInt(port), null, null, db, user, password));
- } else {
- return Optional.of(JdbcConnectionImpl.forExternal(url, user, password));
- }
- } else if (host != null && port != null) {
- return Optional.of(JdbcConnectionImpl.forProtocol(PROTOCOL, host, Integer.parseInt(port), db, user, password));
- } else {
- return Optional.empty();
- }
- }
-}
diff --git a/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachContext.java b/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachContext.java
new file mode 100644
index 0000000..8530115
--- /dev/null
+++ b/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachContext.java
@@ -0,0 +1,99 @@
+package io.goodforgod.testcontainers.extensions.jdbc;
+
+import io.goodforgod.testcontainers.extensions.ContainerContext;
+import java.util.Optional;
+import org.jetbrains.annotations.ApiStatus.Internal;
+import org.jetbrains.annotations.NotNull;
+import org.testcontainers.containers.CockroachContainer;
+
+@Internal
+final class CockroachContext implements ContainerContext {
+
+ private static final String PROTOCOL = "postgresql";
+ private static final int PORT = 26257;
+
+ private static final String EXTERNAL_TEST_COCKROACH_JDBC_URL = "EXTERNAL_TEST_COCKROACH_JDBC_URL";
+ private static final String EXTERNAL_TEST_COCKROACH_USERNAME = "EXTERNAL_TEST_COCKROACH_USERNAME";
+ private static final String EXTERNAL_TEST_COCKROACH_PASSWORD = "EXTERNAL_TEST_COCKROACH_PASSWORD";
+ private static final String EXTERNAL_TEST_COCKROACH_HOST = "EXTERNAL_TEST_COCKROACH_HOST";
+ private static final String EXTERNAL_TEST_COCKROACH_PORT = "EXTERNAL_TEST_COCKROACH_PORT";
+ private static final String EXTERNAL_TEST_COCKROACH_DATABASE = "EXTERNAL_TEST_COCKROACH_DATABASE";
+
+ private volatile JdbcConnectionImpl connection;
+
+ private final CockroachContainer container;
+
+ CockroachContext(CockroachContainer container) {
+ this.container = container;
+ }
+
+ @NotNull
+ public JdbcConnection connection() {
+ if (connection == null) {
+ final Optional connectionExternal = getConnectionExternal();
+ if (connectionExternal.isEmpty() && !container.isRunning()) {
+ throw new IllegalStateException("CockroachConnection can't be create for container that is not running");
+ }
+
+ final JdbcConnection containerConnection = connectionExternal.orElseGet(() -> {
+ final String alias = container.getNetworkAliases().get(container.getNetworkAliases().size() - 1);
+ return JdbcConnectionImpl.forJDBC(container.getJdbcUrl(),
+ container.getHost(),
+ container.getMappedPort(PORT),
+ alias,
+ PORT,
+ container.getDatabaseName(),
+ container.getUsername(),
+ container.getPassword());
+ });
+
+ this.connection = (JdbcConnectionImpl) containerConnection;
+ }
+
+ return connection;
+ }
+
+ @Override
+ public void start() {
+ final Optional connectionExternal = getConnectionExternal();
+ if (connectionExternal.isEmpty()) {
+ container.start();
+ }
+ }
+
+ @Override
+ public void stop() {
+ if (connection != null) {
+ connection.stop();
+ connection = null;
+ }
+ container.stop();
+ }
+
+ @NotNull
+ private static Optional getConnectionExternal() {
+ var url = System.getenv(EXTERNAL_TEST_COCKROACH_JDBC_URL);
+ var host = System.getenv(EXTERNAL_TEST_COCKROACH_HOST);
+ var port = System.getenv(EXTERNAL_TEST_COCKROACH_PORT);
+ var user = System.getenv(EXTERNAL_TEST_COCKROACH_USERNAME);
+ var password = System.getenv(EXTERNAL_TEST_COCKROACH_PASSWORD);
+
+ var db = Optional.ofNullable(System.getenv(EXTERNAL_TEST_COCKROACH_DATABASE)).orElse("postgres");
+ if (url != null) {
+ if (host != null && port != null) {
+ return Optional.of(JdbcConnectionImpl.forJDBC(url, host, Integer.parseInt(port), null, null, db, user, password));
+ } else {
+ return Optional.of(JdbcConnectionImpl.forExternal(url, user, password));
+ }
+ } else if (host != null && port != null) {
+ return Optional.of(JdbcConnectionImpl.forProtocol(PROTOCOL, host, Integer.parseInt(port), db, user, password));
+ } else {
+ return Optional.empty();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return container.getDockerImageName();
+ }
+}
diff --git a/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachMetadata.java b/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachMetadata.java
deleted file mode 100644
index 8eb1dfe..0000000
--- a/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachMetadata.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package io.goodforgod.testcontainers.extensions.jdbc;
-
-import io.goodforgod.testcontainers.extensions.ContainerMode;
-import org.jetbrains.annotations.ApiStatus.Internal;
-import org.jetbrains.annotations.NotNull;
-
-@Internal
-final class CockroachMetadata extends JdbcMetadata {
-
- CockroachMetadata(boolean network, String alias, String image, ContainerMode runMode, Migration migration) {
- super(network, alias, image, runMode, migration);
- }
-
- @Override
- public @NotNull String networkAliasDefault() {
- return "cockroachdb-" + System.currentTimeMillis();
- }
-}
diff --git a/mysql/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ContainerMysqlConnection.java b/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ConnectionCockroach.java
similarity index 87%
rename from mysql/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ContainerMysqlConnection.java
rename to cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ConnectionCockroach.java
index 010f8e9..c82e586 100644
--- a/mysql/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ContainerMysqlConnection.java
+++ b/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ConnectionCockroach.java
@@ -9,4 +9,4 @@
@Documented
@Target({ ElementType.FIELD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
-public @interface ContainerMysqlConnection {}
+public @interface ConnectionCockroach {}
diff --git a/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ContainerCockroachdb.java b/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ContainerCockroach.java
similarity index 52%
rename from cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ContainerCockroachdb.java
rename to cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ContainerCockroach.java
index 7a667f6..c9572ce 100644
--- a/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ContainerCockroachdb.java
+++ b/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ContainerCockroach.java
@@ -1,12 +1,15 @@
package io.goodforgod.testcontainers.extensions.jdbc;
import java.lang.annotation.*;
+import org.testcontainers.containers.CockroachContainer;
/**
- * Indicates that annotated field containers {@link CockroachContainerExtra} instance
- * that should be used by {@link TestcontainersCockroachdb} rather than creating default container
+ * Indicates that annotated field containers {@link CockroachContainer} instance
+ * that should be used by {@link TestcontainersCockroach} rather than creating default container
*/
@Documented
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
-public @interface ContainerCockroachdb {}
+public @interface ContainerCockroach {
+
+}
diff --git a/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ContainerCockroachdbConnection.java b/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ContainerCockroachdbConnection.java
deleted file mode 100644
index cd4b618..0000000
--- a/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/ContainerCockroachdbConnection.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.goodforgod.testcontainers.extensions.jdbc;
-
-import java.lang.annotation.*;
-
-/**
- * Indicates that annotated field or parameter should be injected with {@link JdbcConnection} value
- * of current active container
- */
-@Documented
-@Target({ ElementType.FIELD, ElementType.PARAMETER })
-@Retention(RetentionPolicy.RUNTIME)
-public @interface ContainerCockroachdbConnection {}
diff --git a/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/TestcontainersCockroachdb.java b/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/TestcontainersCockroach.java
similarity index 82%
rename from cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/TestcontainersCockroachdb.java
rename to cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/TestcontainersCockroach.java
index 1383b1f..f444ad0 100644
--- a/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/TestcontainersCockroachdb.java
+++ b/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/TestcontainersCockroach.java
@@ -5,18 +5,19 @@
import java.lang.annotation.*;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.testcontainers.containers.CockroachContainer;
/**
- * Extension that is running {@link CockroachContainerExtra} for tests in different modes with
+ * Extension that is running {@link CockroachContainer} for tests in different modes with
* database
* schema migration support between test executions
*/
@Order(Order.DEFAULT - 100) // Run before other extensions
-@ExtendWith(TestcontainersCockroachdbExtension.class)
+@ExtendWith(TestcontainersCockroachExtension.class)
@Documented
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
-public @interface TestcontainersCockroachdb {
+@interface TestcontainersCockroach {
/**
* @return Cockroachdb image
@@ -25,8 +26,6 @@
* 2) Image can be provided via environment variable using syntax: "${MY_IMAGE_ENV}"
* 3) Image environment variable can have default value if empty using syntax:
* "${MY_IMAGE_ENV|cockroachdb/cockroach:latest-v23.1}"
- *
- * @see TestcontainersCockroachdbExtension#getContainerDefault(CockroachMetadata)
*/
String image() default "cockroachdb/cockroach:latest-v23.1";
diff --git a/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/TestcontainersCockroachExtension.java b/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/TestcontainersCockroachExtension.java
new file mode 100644
index 0000000..db52826
--- /dev/null
+++ b/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/TestcontainersCockroachExtension.java
@@ -0,0 +1,73 @@
+package io.goodforgod.testcontainers.extensions.jdbc;
+
+import io.goodforgod.testcontainers.extensions.ContainerContext;
+import java.lang.annotation.Annotation;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.CockroachContainer;
+import org.testcontainers.containers.Network;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+import org.testcontainers.utility.DockerImageName;
+
+final class TestcontainersCockroachExtension extends
+ AbstractTestcontainersJdbcExtension {
+
+ private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace
+ .create(TestcontainersCockroachExtension.class);
+
+ @Override
+ protected Class getContainerType() {
+ return CockroachContainer.class;
+ }
+
+ @Override
+ protected Class extends Annotation> getContainerAnnotation() {
+ return ContainerCockroach.class;
+ }
+
+ @Override
+ protected Class extends Annotation> getConnectionAnnotation() {
+ return ConnectionCockroach.class;
+ }
+
+ @Override
+ protected ExtensionContext.Namespace getNamespace() {
+ return NAMESPACE;
+ }
+
+ @Override
+ protected CockroachContainer createContainerDefault(JdbcMetadata metadata) {
+ var image = DockerImageName.parse(metadata.image())
+ .asCompatibleSubstituteFor(DockerImageName.parse("cockroachdb/cockroach"));
+
+ final CockroachContainer container = new CockroachContainer(image);
+ final String alias = Optional.ofNullable(metadata.networkAlias())
+ .orElseGet(() -> "cockroach-" + System.currentTimeMillis());
+ container.withLogConsumer(new Slf4jLogConsumer(LoggerFactory.getLogger(CockroachContainer.class))
+ .withMdc("image", image.asCanonicalNameString())
+ .withMdc("alias", alias));
+ container.withStartupTimeout(Duration.ofMinutes(5));
+ container.setNetworkAliases(new ArrayList<>(List.of(alias)));
+ if (metadata.networkShared()) {
+ container.withNetwork(Network.SHARED);
+ }
+
+ return container;
+ }
+
+ @Override
+ protected ContainerContext createContainerContext(CockroachContainer container) {
+ return new CockroachContext(container);
+ }
+
+ @NotNull
+ protected Optional findMetadata(@NotNull ExtensionContext context) {
+ return findAnnotation(TestcontainersCockroach.class, context)
+ .map(a -> new JdbcMetadata(a.network().shared(), a.network().alias(), a.image(), a.mode(), a.migration()));
+ }
+}
diff --git a/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/TestcontainersCockroachdbExtension.java b/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/TestcontainersCockroachdbExtension.java
deleted file mode 100644
index 7a231a2..0000000
--- a/cockroachdb/src/main/java/io/goodforgod/testcontainers/extensions/jdbc/TestcontainersCockroachdbExtension.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package io.goodforgod.testcontainers.extensions.jdbc;
-
-import java.lang.annotation.Annotation;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import org.jetbrains.annotations.NotNull;
-import org.junit.jupiter.api.extension.ExtensionContext;
-import org.testcontainers.containers.Network;
-import org.testcontainers.utility.DockerImageName;
-
-final class TestcontainersCockroachdbExtension extends
- AbstractTestcontainersJdbcExtension {
-
- private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace
- .create(TestcontainersCockroachdbExtension.class);
-
- @Override
- protected Class getContainerType() {
- return CockroachContainerExtra.class;
- }
-
- @Override
- protected Class extends Annotation> getContainerAnnotation() {
- return ContainerCockroachdb.class;
- }
-
- @Override
- protected Class extends Annotation> getConnectionAnnotation() {
- return ContainerCockroachdbConnection.class;
- }
-
- @Override
- protected CockroachContainerExtra getContainerDefault(CockroachMetadata metadata) {
- var dockerImage = DockerImageName.parse(metadata.image())
- .asCompatibleSubstituteFor(DockerImageName.parse("cockroachdb/cockroach"));
-
- var container = new CockroachContainerExtra(dockerImage);
- container.setNetworkAliases(new ArrayList<>(List.of(metadata.networkAliasOrDefault())));
- if (metadata.networkShared()) {
- container.withNetwork(Network.SHARED);
- }
-
- return container;
- }
-
- @Override
- protected JdbcMigrationEngine getMigrationEngine(Migration.Engines engine, ExtensionContext context) {
- var containerCurrent = getContainerCurrent(context);
- return containerCurrent.getMigrationEngine(engine);
- }
-
- @Override
- protected ExtensionContext.Namespace getNamespace() {
- return NAMESPACE;
- }
-
- @NotNull
- protected Optional findMetadata(@NotNull ExtensionContext context) {
- return findAnnotation(TestcontainersCockroachdb.class, context)
- .map(a -> new CockroachMetadata(a.network().shared(), a.network().alias(), a.image(), a.mode(), a.migration()));
- }
-
- @NotNull
- protected JdbcConnection getConnectionForContainer(CockroachMetadata metadata, @NotNull CockroachContainerExtra container) {
- return container.connection();
- }
-}
diff --git a/cockroachdb/src/test/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachdbFlywayPerMethodMigrationTests.java b/cockroachdb/src/test/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachdbFlywayPerMethodMigrationTests.java
index 1d5d069..bb11ba3 100644
--- a/cockroachdb/src/test/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachdbFlywayPerMethodMigrationTests.java
+++ b/cockroachdb/src/test/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachdbFlywayPerMethodMigrationTests.java
@@ -8,7 +8,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
-@TestcontainersCockroachdb(mode = ContainerMode.PER_CLASS,
+@TestcontainersCockroach(mode = ContainerMode.PER_CLASS,
image = "cockroachdb/cockroach:latest-v23.1",
migration = @Migration(
engine = Migration.Engines.FLYWAY,
@@ -19,13 +19,13 @@ class CockroachdbFlywayPerMethodMigrationTests {
@Order(1)
@Test
- void firstRun(@ContainerCockroachdbConnection JdbcConnection connection) {
+ void firstRun(@ConnectionCockroach JdbcConnection connection) {
connection.execute("INSERT INTO users VALUES(1);");
}
@Order(2)
@Test
- void secondRun(@ContainerCockroachdbConnection JdbcConnection connection) {
+ void secondRun(@ConnectionCockroach JdbcConnection connection) {
var usersFound = connection.queryOne("SELECT * FROM users;", r -> r.getInt(1));
assertTrue(usersFound.isEmpty());
}
diff --git a/cockroachdb/src/test/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachdbLiquibaseMigrationPerMethodTests.java b/cockroachdb/src/test/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachdbLiquibaseMigrationPerMethodTests.java
index 9d5d788..1a4234d 100644
--- a/cockroachdb/src/test/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachdbLiquibaseMigrationPerMethodTests.java
+++ b/cockroachdb/src/test/java/io/goodforgod/testcontainers/extensions/jdbc/CockroachdbLiquibaseMigrationPerMethodTests.java
@@ -8,7 +8,7 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
-@TestcontainersCockroachdb(mode = ContainerMode.PER_CLASS,
+@TestcontainersCockroach(mode = ContainerMode.PER_CLASS,
image = "cockroachdb/cockroach:latest-v23.1",
migration = @Migration(
engine = Migration.Engines.LIQUIBASE,
@@ -19,13 +19,13 @@ class CockroachdbLiquibaseMigrationPerMethodTests {
@Order(1)
@Test
- void firstRun(@ContainerCockroachdbConnection JdbcConnection connection) {
+ void firstRun(@ConnectionCockroach JdbcConnection connection) {
connection.execute("INSERT INTO users VALUES(1);");
}
@Order(2)
@Test
- void secondRun(@ContainerCockroachdbConnection JdbcConnection connection) {
+ void secondRun(@ConnectionCockroach JdbcConnection connection) {
var usersFound = connection.queryOne("SELECT * FROM users;", r -> r.getInt(1));
assertTrue(usersFound.isEmpty());
}
diff --git a/common/src/main/java/io/goodforgod/testcontainers/extensions/AbstractContainerMetadata.java b/common/src/main/java/io/goodforgod/testcontainers/extensions/AbstractContainerMetadata.java
index 9eeb61c..eb57f18 100644
--- a/common/src/main/java/io/goodforgod/testcontainers/extensions/AbstractContainerMetadata.java
+++ b/common/src/main/java/io/goodforgod/testcontainers/extensions/AbstractContainerMetadata.java
@@ -10,7 +10,6 @@ public abstract class AbstractContainerMetadata implements ContainerMetadata {
private final boolean network;
private final String alias;
- private final String aliasOrDefault;
private final String image;
private final ContainerMode runMode;
@@ -20,7 +19,6 @@ protected AbstractContainerMetadata(boolean network, String alias, String image,
this.alias = Optional.ofNullable(getEnvValue("Alias", alias))
.filter(a -> !a.isBlank())
.orElse(null);
- this.aliasOrDefault = Optional.ofNullable(this.alias).orElse(networkAliasDefault());
this.image = Optional.ofNullable(getEnvValue("Image", image))
.filter(a -> !a.isBlank())
.orElseThrow(() -> new IllegalArgumentException(
@@ -66,11 +64,6 @@ public boolean networkShared() {
return alias;
}
- @Override
- public @NotNull String networkAliasOrDefault() {
- return aliasOrDefault;
- }
-
@Override
public @NotNull String image() {
return image;
diff --git a/common/src/main/java/io/goodforgod/testcontainers/extensions/AbstractTestcontainersExtension.java b/common/src/main/java/io/goodforgod/testcontainers/extensions/AbstractTestcontainersExtension.java
index 2dab74a..78017ed 100644
--- a/common/src/main/java/io/goodforgod/testcontainers/extensions/AbstractTestcontainersExtension.java
+++ b/common/src/main/java/io/goodforgod/testcontainers/extensions/AbstractTestcontainersExtension.java
@@ -3,14 +3,12 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
+import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import org.jetbrains.annotations.ApiStatus.Internal;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.*;
import org.junit.platform.commons.support.AnnotationSupport;
@@ -73,10 +71,6 @@ static final class SharedContainerKey implements SharedKey {
this.alias = alias;
}
- public String image() {
- return image;
- }
-
@Override
public boolean equals(Object o) {
if (this == o)
@@ -101,7 +95,7 @@ public String toString() {
}
}
- static final Map>> CLASS_TO_SHARED_CONTAINERS = new ConcurrentHashMap<>();
+ static final Map>> CLASS_TO_SHARED_CONTAINERS = new ConcurrentHashMap<>();
protected final Logger logger = LoggerFactory.getLogger(getClass());
@@ -115,15 +109,15 @@ public String toString() {
protected abstract Optional findMetadata(ExtensionContext context);
- protected abstract Container getContainerDefault(Metadata metadata);
-
- protected abstract Connection getConnectionForContainer(Metadata metadata, Container container);
+ protected final Metadata getMetadata(ExtensionContext context) {
+ return findMetadata(context).orElseThrow(() -> new ExtensionConfigurationException("Extension annotation not found"));
+ }
protected abstract ExtensionContext.Namespace getNamespace();
- protected ExtensionContainer getExtensionContainer(Container container, Connection connection) {
- return new ExtensionContainerImpl<>(container, connection);
- }
+ protected abstract Container createContainerDefault(Metadata metadata);
+
+ protected abstract ContainerContext createContainerContext(Container container);
protected final ExtensionContext.Store getStorage(ExtensionContext context) {
if (context.getParent().isPresent() && context.getParent().get().getParent().isPresent()) {
@@ -135,20 +129,9 @@ protected final ExtensionContext.Store getStorage(ExtensionContext context) {
}
}
- protected final Metadata getMetadata(ExtensionContext context) {
- return findMetadata(context)
- .orElseThrow(() -> new ExtensionConfigurationException("Extension annotation not found"));
- }
-
- protected final Connection getConnectionCurrent(ExtensionContext context) {
- return getStorage(context).get(getConnectionType(), getConnectionType());
- }
-
- protected final Container getContainerCurrent(ExtensionContext context) {
+ protected ContainerContext getContainerContext(ExtensionContext context) {
Metadata metadata = getMetadata(context);
- ExtensionContainer extensionContainer = getStorage(context).get(metadata.runMode(),
- ExtensionContainer.class);
- return extensionContainer.container();
+ return getStorage(context).get(metadata.runMode(), ContainerContext.class);
}
protected Optional findAnnotation(Class annotationType, ExtensionContext context) {
@@ -170,63 +153,109 @@ protected Optional findAnnotation(Class annotationT
return Optional.empty();
}
- @SuppressWarnings("unchecked")
- protected Optional getContainerFromField(ExtensionContext context) {
+ protected Optional findContainerFromField(ExtensionContext context) {
logger.debug("Looking for {} Container...", getContainerType().getSimpleName());
- final Optional> testClass = context.getTestClass();
- if (testClass.isEmpty()) {
+ if (context.getTestClass().isEmpty() || context.getTestInstance().isEmpty()) {
+ return Optional.empty();
+ }
+
+ final Optional container = findContainerInClassField(context.getTestInstance().get());
+ if (container.isPresent()) {
+ return container;
+ } else if (context.getTestClass().filter(c -> c.isAnnotationPresent(Nested.class)).isPresent()) {
+ return findParentTestClassIfNested(context).flatMap(this::findContainerInClassField);
+ } else {
return Optional.empty();
}
+ }
+
+ private static Optional