diff --git a/testcontainers2/README.md b/testcontainers2/README.md new file mode 100644 index 0000000..472d329 --- /dev/null +++ b/testcontainers2/README.md @@ -0,0 +1,64 @@ +# testcontainers2 + +Companion module for [Migrating to Testcontainers 2.0: Artifact Renames, Package Moves and JUnit 6](https://ankurm.com/) on ankurm.com. + +## What this is + +Testcontainers 2.0 shipped on 2025-10-14 as a deliberately disruptive release: 61 artifacts +renamed, JUnit 4 support dropped from the type hierarchy itself (not deprecated — removed), and +a default Docker API version bump that quietly fixes a real compatibility break with current +Docker Engine releases. This module verifies each of those claims against a real jar, a real +Maven Central artifact history, or a real compiler run — never against a changelog's prose alone +— and runs the result against real JUnit 6.1.3. No `docs/NN-topic.md` chapters; everything beyond +what fits in the post itself is in the Javadoc on the two committed test classes and in the +captured transcripts below. + +**This module was built and tested in a sandbox with no Docker daemon available.** Both test +classes run (or cleanly skip) without one; nothing here asserts on a real container's output. + +**Self-correction made before this module was finished:** the first draft of +`NewPostgresContainerSkipsCleanlyTest` put `@EnabledIfDockerAvailable` on the test *method*. That +compiles, and it is wrong — see the Javadoc on that class and +`docs/output/01-guard-on-method-still-fails.txt` for the real failure it produced before the fix. + +## Versions + +| Dependency | Version | Verified against | +|---|---|---| +| Testcontainers | 2.0.5 | `testcontainers-bom-2.0.5.pom`; same version `data-jpa-testcontainers` verified Spring Boot 4.1.1's own BOM pins | +| JUnit Jupiter | 6.1.3 | `maven-metadata.xml`, `` | +| AssertJ | 3.27.7 | `maven-metadata.xml`, `` | +| JUnit 4 (test-scope only, for the reflective check) | 4.13.2 | pinned deliberately — see `GenericContainerNoLongerImplementsTestRuleTest` | +| JDK | 25 (Temurin) | `java -version`, this module's own build | + +## Quickstart + +```bash +mvn test # 3 tests run; 1 skips cleanly, 0 failures +``` + +## Test classes + +| Class | What it proves | Needs Docker | Outcome here | +|---|---|---|---| +| `GenericContainerNoLongerImplementsTestRuleTest` | `GenericContainer` implemented `org.junit.rules.TestRule` by inheritance in 1.21.4; zero classes anywhere in the 2.0.5 core jar implement it | No | Pass | +| `NewPostgresContainerSkipsCleanlyTest` | The relocated, non-generic `org.testcontainers.postgresql.PostgreSQLContainer` compiles and runs under JUnit 6, guarded correctly (class-level) by `@EnabledIfDockerAvailable` | Yes (guarded) | Skipped | + +## Captured output + +| File | Contents | +|---|---| +| `docs/output/00-full-test-run.txt` | `mvn clean test` — 3 tests, 1 clean skip, build green, with the guard on the class | +| `docs/output/01-guard-on-method-still-fails.txt` | The same class with `@EnabledIfDockerAvailable` on the method instead — a real `IllegalStateException` from `GenericContainer.start()`, because `TestcontainersExtension.beforeAll` starts every `@Container` field before any method-level condition runs | +| `docs/output/02-genericcontainer-testrule-removed-javap.txt` | `javap` proof of the `TestRule` removal: present via inheritance in 1.21.4, absent — exhaustively, jar-wide — in 2.0.5 | +| `docs/output/03-docker-api-version-bump-javap.txt` | `javap` proof that the hardcoded default Docker API version moved from 1.32 to 1.44 between 1.21.4 and 2.0.5, tied to the real GitHub issue where Docker Engine 29 rejects API 1.32 outright | +| `docs/output/04-legacy-pom-compiles-under-1.21.4.txt` | A classic `@ClassRule public static PostgreSQLContainer` JUnit 4 test, compiling clean against 1.21.4 with no extra dependency | +| `docs/output/05-legacy-pom-fails-to-resolve-under-2.0.5.txt` | The identical source file; only the version property changed to 2.0.5. The build fails before it even reaches the `TestRule` question, because `org.testcontainers:postgresql` has no 2.0.5 release at all | +| `docs/output/06-maven-central-artifact-history.txt` | The real `maven-metadata.xml` for both `org.testcontainers:junit-jupiter` (frozen at 1.21.4) and `org.testcontainers:testcontainers-junit-jupiter` (starts at 2.0.0) — the permanent fork point behind the rename | + +## What's sourced from documentation, not run here + +The full 61-artifact rename list and the composite `Testcontainers2Migration` OpenRewrite recipe +are quoted from OpenRewrite's own published recipe catalog, not executed in this sandbox — see +the post for the exact quotes and the link. Everything else above was compiled, run, or pulled +directly from a real jar or a real Maven Central response in this sitting. diff --git a/testcontainers2/docs/output/00-full-test-run.txt b/testcontainers2/docs/output/00-full-test-run.txt new file mode 100644 index 0000000..e9f55c4 --- /dev/null +++ b/testcontainers2/docs/output/00-full-test-run.txt @@ -0,0 +1,48 @@ +[INFO] Scanning for projects... +[INFO] +[INFO] ---------------------< com.ankurm:testcontainers2 >--------------------- +[INFO] Building testcontainers2 1.0.0 +[INFO] from pom.xml +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] +[INFO] --- clean:3.2.0:clean (default-clean) @ testcontainers2 --- +[INFO] Deleting /home/claude/JUnit_Tutorials/testcontainers2/target +[INFO] +[INFO] --- resources:3.3.1:resources (default-resources) @ testcontainers2 --- +[INFO] skip non existing resourceDirectory /home/claude/JUnit_Tutorials/testcontainers2/src/main/resources +[INFO] +[INFO] --- compiler:3.13.0:compile (default-compile) @ testcontainers2 --- +[INFO] No sources to compile +[INFO] +[INFO] --- resources:3.3.1:testResources (default-testResources) @ testcontainers2 --- +[INFO] skip non existing resourceDirectory /home/claude/JUnit_Tutorials/testcontainers2/src/test/resources +[INFO] +[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ testcontainers2 --- +[INFO] Recompiling the module because of changed source code. +[INFO] Compiling 2 source files with javac [debug release 25] to target/test-classes +[INFO] +[INFO] --- surefire:3.6.0:test (default-test) @ testcontainers2 --- +[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider +[INFO] +[INFO] ------------------------------------------------------- +[INFO] T E S T S +[INFO] ------------------------------------------------------- +SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". +SLF4J: Defaulting to no-operation (NOP) logger implementation +SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. + +[INFO] Running com.ankurm.tutorials.junit.testcontainers2.NewPostgresContainerSkipsCleanlyTest +[WARNING] Tests run: 1, Failures: 0, Errors: 0, Skipped: 1, Time elapsed: 0.037 s -- in com.ankurm.tutorials.junit.testcontainers2.NewPostgresContainerSkipsCleanlyTest +[INFO] Running com.ankurm.tutorials.junit.testcontainers2.GenericContainerNoLongerImplementsTestRuleTest +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.166 s -- in com.ankurm.tutorials.junit.testcontainers2.GenericContainerNoLongerImplementsTestRuleTest +[INFO] +[INFO] Results: +[INFO] +[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 1 +[INFO] +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 5.007 s +[INFO] Finished at: 2026-10-08T18:47:18+05:30 +[INFO] ------------------------------------------------------------------------ diff --git a/testcontainers2/docs/output/01-guard-on-method-still-fails.txt b/testcontainers2/docs/output/01-guard-on-method-still-fails.txt new file mode 100644 index 0000000..f2a8904 --- /dev/null +++ b/testcontainers2/docs/output/01-guard-on-method-still-fails.txt @@ -0,0 +1,107 @@ +[INFO] Scanning for projects... +[INFO] +[INFO] ---------------------< com.ankurm:testcontainers2 >--------------------- +[INFO] Building testcontainers2 1.0.0 +[INFO] from pom.xml +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] +[INFO] --- clean:3.2.0:clean (default-clean) @ testcontainers2 --- +[INFO] +[INFO] --- resources:3.3.1:resources (default-resources) @ testcontainers2 --- +[INFO] skip non existing resourceDirectory /home/claude/JUnit_Tutorials/testcontainers2/src/main/resources +[INFO] +[INFO] --- compiler:3.13.0:compile (default-compile) @ testcontainers2 --- +[INFO] No sources to compile +[INFO] +[INFO] --- resources:3.3.1:testResources (default-testResources) @ testcontainers2 --- +[INFO] skip non existing resourceDirectory /home/claude/JUnit_Tutorials/testcontainers2/src/test/resources +[INFO] +[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ testcontainers2 --- +[INFO] Recompiling the module because of changed source code. +[INFO] Compiling 2 source files with javac [debug release 25] to target/test-classes +[INFO] +[INFO] --- surefire:3.6.0:test (default-test) @ testcontainers2 --- +[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider +Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-junit-platform/3.6.0/surefire-junit-platform-3.6.0.pom +Progress (1): 833 B Progress (1): 3.9 kB Progress (1): 4.6 kB Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-junit-platform/3.6.0/surefire-junit-platform-3.6.0.pom (4.6 kB at 9.3 kB/s) +Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-providers/3.6.0/surefire-providers-3.6.0.pom +Progress (1): 872 B Progress (1): 1.8 kB Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-providers/3.6.0/surefire-providers-3.6.0.pom (1.8 kB at 26 kB/s) +Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/common-java5/3.6.0/common-java5-3.6.0.pom +Progress (1): 844 B Progress (1): 2.4 kB Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/common-java5/3.6.0/common-java5-3.6.0.pom (2.4 kB at 49 kB/s) +Downloading from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-engine/1.14.4/junit-platform-engine-1.14.4.pom +Progress (1): 953 B Progress (1): 3.2 kB Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-engine/1.14.4/junit-platform-engine-1.14.4.pom (3.2 kB at 37 kB/s) +Downloading from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-commons/1.14.4/junit-platform-commons-1.14.4.pom +Progress (1): 967 B Progress (1): 2.9 kB Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-commons/1.14.4/junit-platform-commons-1.14.4.pom (2.9 kB at 63 kB/s) +Downloading from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-launcher/1.14.4/junit-platform-launcher-1.14.4.pom +Progress (1): 968 B Progress (1): 3.0 kB Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-launcher/1.14.4/junit-platform-launcher-1.14.4.pom (3.0 kB at 73 kB/s) +Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-junit-platform/3.6.0/surefire-junit-platform-3.6.0.jar +Progress (1): 7.7/57 kB Progress (1): 16/57 kB Progress (1): 32/57 kB Progress (1): 33/57 kB Progress (1): 49/57 kB Progress (1): 57 kB Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/surefire-junit-platform/3.6.0/surefire-junit-platform-3.6.0.jar (57 kB at 1.1 MB/s) +Downloading from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/common-java5/3.6.0/common-java5-3.6.0.jar +Downloading from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-engine/1.14.4/junit-platform-engine-1.14.4.jar +Downloading from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-commons/1.14.4/junit-platform-commons-1.14.4.jar +Downloading from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-launcher/1.14.4/junit-platform-launcher-1.14.4.jar +Progress (1): 7.7/272 kB Progress (1): 8.2/272 kB Progress (1): 25/272 kB Progress (1): 36/272 kB Progress (1): 52/272 kB Progress (1): 69/272 kB Progress (1): 85/272 kB Progress (1): 101/272 kB Progress (1): 118/272 kB Progress (1): 134/272 kB Progress (1): 151/272 kB Progress (1): 159/272 kB Progress (1): 175/272 kB Progress (1): 192/272 kB Progress (1): 200/272 kB Progress (1): 216/272 kB Progress (1): 233/272 kB Progress (1): 249/272 kB Progress (1): 265/272 kB Progress (1): 272 kB Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-engine/1.14.4/junit-platform-engine-1.14.4.jar (272 kB at 2.6 MB/s) +Progress (1): 7.7/16 kB Progress (1): 11/16 kB Progress (1): 16 kB Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/maven/surefire/common-java5/3.6.0/common-java5-3.6.0.jar (16 kB at 102 kB/s) +Progress (1): 7.7/164 kB Progress (1): 16/164 kB Progress (2): 16/164 kB | 7.7/223 kB Progress (2): 16/164 kB | 16/223 kB Progress (2): 16/164 kB | 16/223 kB Progress (2): 16/164 kB | 25/223 kB Progress (2): 16/164 kB | 33/223 kB Progress (2): 16/164 kB | 41/223 kB Progress (2): 32/164 kB | 41/223 kB Progress (2): 49/164 kB | 41/223 kB Progress (2): 57/164 kB | 41/223 kB Progress (2): 65/164 kB | 41/223 kB Progress (2): 73/164 kB | 41/223 kB Progress (2): 73/164 kB | 49/223 kB Progress (2): 73/164 kB | 57/223 kB Progress (2): 73/164 kB | 66/223 kB Progress (2): 73/164 kB | 74/223 kB Progress (2): 81/164 kB | 74/223 kB Progress (2): 98/164 kB | 74/223 kB Progress (2): 98/164 kB | 90/223 kB Progress (2): 114/164 kB | 90/223 kB Progress (2): 114/164 kB | 98/223 kB Progress (2): 114/164 kB | 106/223 kB Progress (2): 131/164 kB | 106/223 kB Progress (2): 147/164 kB | 106/223 kB Progress (2): 163/164 kB | 106/223 kB Progress (2): 164 kB | 106/223 kB Progress (2): 164 kB | 115/223 kB Progress (2): 164 kB | 131/223 kB Progress (2): 164 kB | 147/223 kB Progress (2): 164 kB | 163/223 kB Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-commons/1.14.4/junit-platform-commons-1.14.4.jar (164 kB at 918 kB/s) +Progress (1): 171/223 kB Progress (1): 180/223 kB Progress (1): 196/223 kB Progress (1): 212/223 kB Progress (1): 223 kB Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/platform/junit-platform-launcher/1.14.4/junit-platform-launcher-1.14.4.jar (223 kB at 1.2 MB/s) +Downloading from central: https://repo.maven.apache.org/maven2/org/junit/vintage/junit-vintage-engine/6.1.3/junit-vintage-engine-6.1.3.pom +Progress (1): 956 B Progress (1): 3.3 kB Progress (1): 3.5 kB Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/vintage/junit-vintage-engine/6.1.3/junit-vintage-engine-6.1.3.pom (3.5 kB at 90 kB/s) +Downloading from central: https://repo.maven.apache.org/maven2/org/junit/vintage/junit-vintage-engine/6.1.3/junit-vintage-engine-6.1.3.jar +Progress (1): 7.7/81 kB Progress (1): 16/81 kB Progress (1): 24/81 kB Progress (1): 32/81 kB Progress (1): 49/81 kB Progress (1): 65/81 kB Progress (1): 81/81 kB Progress (1): 81 kB Downloaded from central: https://repo.maven.apache.org/maven2/org/junit/vintage/junit-vintage-engine/6.1.3/junit-vintage-engine-6.1.3.jar (81 kB at 1.6 MB/s) +[INFO] +[INFO] ------------------------------------------------------- +[INFO] T E S T S +[INFO] ------------------------------------------------------- +[INFO] Running com.ankurm.tutorials.junit.testcontainers2.NewPostgresContainerSkipsCleanlyTest +SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". +SLF4J: Defaulting to no-operation (NOP) logger implementation +SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. + +[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 1.676 s <<< FAILURE! -- in com.ankurm.tutorials.junit.testcontainers2.NewPostgresContainerSkipsCleanlyTest +[ERROR] com.ankurm.tutorials.junit.testcontainers2.NewPostgresContainerSkipsCleanlyTest.initializationError -- Time elapsed: 1.676 s <<< ERROR! +java.lang.IllegalStateException: Could not find a valid Docker environment. Please see logs and check configuration + at org.testcontainers.dockerclient.DockerClientProviderStrategy.lambda$getFirstValidStrategy$7(DockerClientProviderStrategy.java:274) + at java.base/java.util.Optional.orElseThrow(Optional.java:403) + at org.testcontainers.dockerclient.DockerClientProviderStrategy.getFirstValidStrategy(DockerClientProviderStrategy.java:265) + at org.testcontainers.DockerClientFactory.getOrInitializeStrategy(DockerClientFactory.java:154) + at org.testcontainers.DockerClientFactory.client(DockerClientFactory.java:196) + at org.testcontainers.DockerClientFactory$1.getDockerClient(DockerClientFactory.java:108) + at com.github.dockerjava.api.DockerClientDelegate.authConfig(DockerClientDelegate.java:111) + at org.testcontainers.containers.GenericContainer.start(GenericContainer.java:316) + at org.testcontainers.junit.jupiter.TestcontainersExtension$StoreAdapter.start(TestcontainersExtension.java:276) + at org.testcontainers.junit.jupiter.TestcontainersExtension$StoreAdapter.access$200(TestcontainersExtension.java:263) + at org.testcontainers.junit.jupiter.TestcontainersExtension.lambda$startContainers$4(TestcontainersExtension.java:83) + at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:328) + at org.testcontainers.junit.jupiter.TestcontainersExtension.lambda$startContainers$5(TestcontainersExtension.java:83) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1604) + at org.testcontainers.junit.jupiter.TestcontainersExtension.startContainers(TestcontainersExtension.java:83) + at org.testcontainers.junit.jupiter.TestcontainersExtension.beforeAll(TestcontainersExtension.java:57) + at java.base/java.util.ArrayList.forEach(ArrayList.java:1604) + +[INFO] Running com.ankurm.tutorials.junit.testcontainers2.GenericContainerNoLongerImplementsTestRuleTest +[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.197 s -- in com.ankurm.tutorials.junit.testcontainers2.GenericContainerNoLongerImplementsTestRuleTest +[INFO] +[INFO] Results: +[INFO] +[ERROR] Errors: +[ERROR] NewPostgresContainerSkipsCleanlyTest.initializationError ? IllegalState Could not find a valid Docker environment. Please see logs and check configuration +[INFO] +[ERROR] Tests run: 3, Failures: 0, Errors: 1, Skipped: 0 +[INFO] +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD FAILURE +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 10.778 s +[INFO] Finished at: 2026-10-08T18:46:46+05:30 +[INFO] ------------------------------------------------------------------------ +[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.6.0:test (default-test) on project testcontainers2: +[ERROR] +[ERROR] See /home/claude/JUnit_Tutorials/testcontainers2/target/surefire-reports for the individual test results. +[ERROR] See dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream. +[ERROR] -> [Help 1] +[ERROR] +[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. +[ERROR] Re-run Maven using the -X switch to enable full debug logging. +[ERROR] +[ERROR] For more information about the errors and possible solutions, please read the following articles: +[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException diff --git a/testcontainers2/docs/output/02-genericcontainer-testrule-removed-javap.txt b/testcontainers2/docs/output/02-genericcontainer-testrule-removed-javap.txt new file mode 100644 index 0000000..9502901 --- /dev/null +++ b/testcontainers2/docs/output/02-genericcontainer-testrule-removed-javap.txt @@ -0,0 +1,48 @@ +# unzipped from testcontainers-1.21.4.jar +$ javap -p org/testcontainers/containers/GenericContainer.class +public class org.testcontainers.containers.GenericContainer> + extends org.testcontainers.containers.FailureDetectingExternalResource + implements org.testcontainers.containers.Container, java.lang.AutoCloseable, + org.testcontainers.containers.wait.strategy.WaitStrategyTarget, + org.testcontainers.lifecycle.Startable { + ... +} + +$ javap -p org/testcontainers/containers/FailureDetectingExternalResource.class +public class org.testcontainers.containers.FailureDetectingExternalResource + implements org.junit.rules.TestRule { + public org.testcontainers.containers.FailureDetectingExternalResource(); + ... +} + +# So in 1.21.4: GenericContainer -> FailureDetectingExternalResource -> implements TestRule. +# Every container class is a JUnit 4 TestRule by inheritance, with no extra dependency. + +# unzipped from testcontainers-2.0.5.jar instead +$ javap -p org/testcontainers/containers/GenericContainer.class +public class org.testcontainers.containers.GenericContainer> + implements org.testcontainers.containers.Container, java.lang.AutoCloseable, + org.testcontainers.containers.wait.strategy.WaitStrategyTarget, + org.testcontainers.lifecycle.Startable { + ... +} + +# No "extends FailureDetectingExternalResource" at all - that class and the TestRule contract +# it carried are both gone from the 2.0.5 jar. Confirmed exhaustively, not just for this one +# class: + +$ mkdir ext2 && cd ext2 && unzip -oq ../testcontainers-2.0.5.jar +$ grep -rl "org/junit/rules/TestRule" . --include="*.class" | wc -l +0 + +# Compare: the same search against the 1.21.4 jar +$ mkdir ext1 && cd ext1 && unzip -oq ../testcontainers-1.21.4.jar +$ grep -rl "org/junit/rules/TestRule" . --include="*.class" | wc -l +2 + +# Zero classes anywhere in the 2.0.5 core jar reference org.junit.rules.TestRule. This is not a +# deprecation - the interface implementation is physically absent from the compiled jar. It is +# also why the fix is not "add the testcontainers-junit-jupiter dependency": that artifact is a +# JUnit 5 extension (@Testcontainers/@Container), not a JUnit 4 rule shim. There is no JUnit 4 +# path forward in 2.0 - see GitHub release notes, testcontainers-java#10805 "Remove JUnit 4 +# support" and #10808 "Fix missing junit4 leftovers", https://github.com/testcontainers/testcontainers-java/releases/tag/2.0.0 diff --git a/testcontainers2/docs/output/03-docker-api-version-bump-javap.txt b/testcontainers2/docs/output/03-docker-api-version-bump-javap.txt new file mode 100644 index 0000000..1f1502d --- /dev/null +++ b/testcontainers2/docs/output/03-docker-api-version-bump-javap.txt @@ -0,0 +1,37 @@ +# unzipped from testcontainers-1.21.4.jar +$ javap -v -p org/testcontainers/dockerclient/DockerClientProviderStrategy.class + ... + #773 = Utf8 Fallback to Docker API version 1.32. + #774 = String #773 // Fallback to Docker API version 1.32. + #775 = Utf8 VERSION_1_32 + #777 = Fieldref org/testcontainers/shaded/com/github/dockerjava/core/RemoteApiVersion.VERSION_1_32:... + ... + 273: ldc_w #774 // String Fallback to Docker API version 1.32. + 286: getstatic #777 // Field ...RemoteApiVersion.VERSION_1_32:... + +# unzipped from testcontainers-2.0.5.jar instead +$ javap -v -p org/testcontainers/dockerclient/DockerClientProviderStrategy.class + ... + #742 = Utf8 VERSION_1_44 + #744 = Fieldref org/testcontainers/shaded/com/github/dockerjava/core/RemoteApiVersion.VERSION_1_44:... + #764 = Utf8 Pinging Docker API version 1.44. + #765 = String #764 // Pinging Docker API version 1.44. + ... + 208: getstatic #744 // Field ...RemoteApiVersion.VERSION_1_44:... + 244: ldc_w #765 // String Pinging Docker API version 1.44. + +# The hardcoded default Docker Engine API version this client falls back to moved from 1.32 to +# 1.44 somewhere between 1.21.4 and 2.0.5. The release notes for 2.0.2 say exactly that: +# "Set default docker API version to 1.44 (#11216) @eddumelendez" - +# https://github.com/testcontainers/testcontainers-java/releases/tag/2.0.2 +# +# This is not a cosmetic bump. Docker Engine 29 (shipped inside Docker Desktop 4.52) raises its +# own *minimum accepted* client API version to 1.44, and rejects anything older outright: +# "client version 1.32 is too old. Minimum supported API version is 1.44, please upgrade +# your client to a newer version." +# reported against Testcontainers 1.21.3 in +# https://github.com/testcontainers/testcontainers-java/issues/11235 - closed as a duplicate, +# with multiple commenters confirming Testcontainers 2.0.2 works against the same Docker Desktop +# version where 1.21.x fails outright. A project pinned to the 1.x line has three options: set +# api.version=1.44 by hand in a ~/.docker-java.properties file, keep Docker Engine below 29, or move +# to 2.0.2+, where this is just the default. diff --git a/testcontainers2/docs/output/04-legacy-pom-compiles-under-1.21.4.txt b/testcontainers2/docs/output/04-legacy-pom-compiles-under-1.21.4.txt new file mode 100644 index 0000000..aa6a180 --- /dev/null +++ b/testcontainers2/docs/output/04-legacy-pom-compiles-under-1.21.4.txt @@ -0,0 +1,43 @@ +Module: /tmp/legacy-check (a throwaway Maven project, not part of this repo - built only to +capture these two transcripts; see the post for why). + +pom.xml dependencies at this point: + junit:junit:4.13.2 + org.testcontainers:testcontainers:1.21.4 + org.testcontainers:postgresql:1.21.4 + +src/test/java/com/ankurm/legacy/ClassicJUnit4RuleTest.java: + @ClassRule + public static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:17"); + +[INFO] Scanning for projects... +[INFO] +[INFO] ----------------------< com.ankurm:legacy-check >----------------------- +[INFO] Building legacy-check 1.0.0 +[INFO] from pom.xml +[INFO] --------------------------------[ jar ]--------------------------------- +[INFO] +[INFO] --- clean:3.2.0:clean (default-clean) @ legacy-check --- +[INFO] Deleting /tmp/post46/legacy-check/target +[INFO] +[INFO] --- resources:3.3.1:resources (default-resources) @ legacy-check --- +[INFO] skip non existing resourceDirectory /tmp/post46/legacy-check/src/main/resources +[INFO] +[INFO] --- compiler:3.13.0:compile (default-compile) @ legacy-check --- +[INFO] No sources to compile +[INFO] +[INFO] --- resources:3.3.1:testResources (default-testResources) @ legacy-check --- +[INFO] skip non existing resourceDirectory /tmp/post46/legacy-check/src/test/resources +[INFO] +[INFO] --- compiler:3.13.0:testCompile (default-testCompile) @ legacy-check --- +[INFO] Recompiling the module because of changed source code. +[INFO] Compiling 1 source file with javac [debug target 21] to target/test-classes +[WARNING] location of system modules is not set in conjunction with -source 21 + not setting the location of system modules may lead to class files that cannot run on JDK 21 + --release 21 is recommended instead of -source 21 -target 21 because it sets the location of system modules automatically +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD SUCCESS +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 2.016 s +[INFO] Finished at: 2026-10-08T18:40:55+05:30 +[INFO] ------------------------------------------------------------------------ diff --git a/testcontainers2/docs/output/05-legacy-pom-fails-to-resolve-under-2.0.5.txt b/testcontainers2/docs/output/05-legacy-pom-fails-to-resolve-under-2.0.5.txt new file mode 100644 index 0000000..5175a46 --- /dev/null +++ b/testcontainers2/docs/output/05-legacy-pom-fails-to-resolve-under-2.0.5.txt @@ -0,0 +1,36 @@ +Same module, same source file, zero code changes. The ONLY edit between this run and +04-legacy-pom-compiles-under-1.21.4.txt is the version property: + + - 1.21.4 + + 2.0.5 + +[INFO] Scanning for projects... +[INFO] +[INFO] ----------------------< com.ankurm:legacy-check >----------------------- +[INFO] Building legacy-check 1.0.0 +[INFO] from pom.xml +[INFO] --------------------------------[ jar ]--------------------------------- +Downloading from central: https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.20/jackson-annotations-2.20.pom +Progress (1): 952 B Progress (1): 2.3 kB Progress (1): 3.8 kB Progress (1): 6.4 kB Progress (1): 7.0 kB Downloaded from central: https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.20/jackson-annotations-2.20.pom (7.0 kB at 15 kB/s) +Downloading from central: https://repo.maven.apache.org/maven2/org/testcontainers/postgresql/2.0.5/postgresql-2.0.5.pom +[WARNING] The POM for org.testcontainers:postgresql:jar:2.0.5 is missing, no dependency information available +Downloading from central: https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.20/jackson-annotations-2.20.jar +Progress (1): 7.7/79 kB Progress (1): 8.2/79 kB Progress (1): 25/79 kB Progress (1): 41/79 kB Progress (1): 49/79 kB Progress (1): 57/79 kB Progress (1): 66/79 kB Progress (1): 74/79 kB Progress (1): 79 kB Downloaded from central: https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.20/jackson-annotations-2.20.jar (79 kB at 990 kB/s) +Downloading from central: https://repo.maven.apache.org/maven2/org/testcontainers/postgresql/2.0.5/postgresql-2.0.5.jar +[INFO] ------------------------------------------------------------------------ +[INFO] BUILD FAILURE +[INFO] ------------------------------------------------------------------------ +[INFO] Total time: 1.299 s +[INFO] Finished at: 2026-10-08T18:41:04+05:30 +[INFO] ------------------------------------------------------------------------ +[ERROR] Failed to execute goal on project legacy-check: Could not resolve dependencies for project com.ankurm:legacy-check:jar:1.0.0 +[ERROR] dependency: org.testcontainers:postgresql:jar:2.0.5 (compile) +[ERROR] Could not find artifact org.testcontainers:postgresql:jar:2.0.5 in central (https://repo.maven.apache.org/maven2) +[ERROR] +[ERROR] -> [Help 1] +[ERROR] +[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch. +[ERROR] Re-run Maven using the -X switch to enable full debug logging. +[ERROR] +[ERROR] For more information about the errors and possible solutions, please read the following articles: +[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/DependencyResolutionException diff --git a/testcontainers2/docs/output/06-maven-central-artifact-history.txt b/testcontainers2/docs/output/06-maven-central-artifact-history.txt new file mode 100644 index 0000000..5fd1dc1 --- /dev/null +++ b/testcontainers2/docs/output/06-maven-central-artifact-history.txt @@ -0,0 +1,47 @@ +$ curl -sS https://repo1.maven.org/maven2/org/testcontainers/junit-jupiter/maven-metadata.xml + + org.testcontainers + junit-jupiter + + 1.21.4 + 1.21.4 + + ... (1.10.0 through 1.21.4, 56 releases total) ... + 1.21.4 + + 20251216004330 + + + +$ curl -sS https://repo1.maven.org/maven2/org/testcontainers/testcontainers-junit-jupiter/maven-metadata.xml + + org.testcontainers + testcontainers-junit-jupiter + + 2.0.5 + 2.0.5 + + 2.0.0 + 2.0.1 + 2.0.2 + 2.0.3 + 2.0.4 + 2.0.5 + + 20260420182027 + + + +# The old artifactId's release history simply stops at 1.21.4 - no 2.x version was ever +# published under org.testcontainers:junit-jupiter. The new artifactId's history starts fresh +# at 2.0.0. This is the real, permanent fork point on Maven Central: "upgrade the version +# number" on your existing junit-jupiter dependency has no 2.x version +# to resolve to - it will stay on 1.21.4 forever, or fail outright for a module whose own +# artifactId was retired rather than just renamed (see 05-legacy-pom-fails-to-resolve-under-2.0.5.txt, +# where this happens to org.testcontainers:postgresql). +# +# This is one rename out of 61: OpenRewrite's own migration recipe documents the full list at +# https://docs.openrewrite.org/recipes/java/testing/testcontainers/testcontainers2dependencies - +# every org.testcontainers: artifact gets a testcontainers- artifactId, same +# groupId, same Maven Central repository. The core artifact, plain org.testcontainers:testcontainers, +# is the one name on the list that did NOT change. diff --git a/testcontainers2/pom.xml b/testcontainers2/pom.xml new file mode 100644 index 0000000..10e1f1e --- /dev/null +++ b/testcontainers2/pom.xml @@ -0,0 +1,83 @@ + + + 4.0.0 + + com.ankurm + testcontainers2 + 1.0.0 + jar + testcontainers2 + Migrating to Testcontainers 2.0: the artifact rename, the package move, the dropped + JUnit 4 support, and the Docker API version bump that quietly ships alongside all of it. + + + 25 + UTF-8 + 6.1.3 + 2.0.5 + 3.27.7 + + + + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + + + + + org.testcontainers + testcontainers + ${testcontainers.version} + test + + + + + org.testcontainers + testcontainers-junit-jupiter + ${testcontainers.version} + test + + + + + org.testcontainers + testcontainers-postgresql + ${testcontainers.version} + test + + + + + junit + junit + 4.13.2 + test + + + + org.assertj + assertj-core + ${assertj.version} + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.6.0 + + + + diff --git a/testcontainers2/src/test/java/com/ankurm/tutorials/junit/testcontainers2/GenericContainerNoLongerImplementsTestRuleTest.java b/testcontainers2/src/test/java/com/ankurm/tutorials/junit/testcontainers2/GenericContainerNoLongerImplementsTestRuleTest.java new file mode 100644 index 0000000..b45cc16 --- /dev/null +++ b/testcontainers2/src/test/java/com/ankurm/tutorials/junit/testcontainers2/GenericContainerNoLongerImplementsTestRuleTest.java @@ -0,0 +1,44 @@ +package com.ankurm.tutorials.junit.testcontainers2; + +import org.junit.jupiter.api.Test; +import org.junit.rules.TestRule; +import org.testcontainers.containers.GenericContainer; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Testcontainers 1.x's JUnit 4 integration was never a separate opt-in extension - it was built + * into the container classes themselves. {@code GenericContainer} extended + * {@code FailureDetectingExternalResource}, which implemented {@code org.junit.rules.TestRule} + * directly, confirmed on the real 1.21.4 jar with: + * + *
+ * $ javap -p org/testcontainers/containers/FailureDetectingExternalResource.class
+ * public class org.testcontainers.containers.FailureDetectingExternalResource
+ *     implements org.junit.rules.TestRule
+ * 
+ * + * That is why a plain {@code @ClassRule public static PostgreSQLContainer<?> postgres = ...} + * compiled with zero extra dependency under 1.21.4 - see + * docs/output/04-legacy-pom-compiles-under-1.21.4.txt. Testcontainers 2.0's release notes say + * "Remove JUnit 4 support" (testcontainers-java#10805); this test checks what that actually means + * for the type hierarchy, on the real 2.0.5 jar, rather than taking the changelog's word for it. + */ +class GenericContainerNoLongerImplementsTestRuleTest { + + @Test + void genericContainerDoesNotImplementTestRule() { + assertThat(TestRule.class.isAssignableFrom(GenericContainer.class)).isFalse(); + } + + @Test + void noSuperclassOfGenericContainerImplementsTestRuleEither() { + Class walk = GenericContainer.class; + while (walk != null) { + assertThat(TestRule.class.isAssignableFrom(walk)) + .describedAs("%s should not implement TestRule in Testcontainers 2.0", walk.getName()) + .isFalse(); + walk = walk.getSuperclass(); + } + } +} diff --git a/testcontainers2/src/test/java/com/ankurm/tutorials/junit/testcontainers2/NewPostgresContainerSkipsCleanlyTest.java b/testcontainers2/src/test/java/com/ankurm/tutorials/junit/testcontainers2/NewPostgresContainerSkipsCleanlyTest.java new file mode 100644 index 0000000..47a42e3 --- /dev/null +++ b/testcontainers2/src/test/java/com/ankurm/tutorials/junit/testcontainers2/NewPostgresContainerSkipsCleanlyTest.java @@ -0,0 +1,40 @@ +package com.ankurm.tutorials.junit.testcontainers2; + +import org.junit.jupiter.api.Test; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.EnabledIfDockerAvailable; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.postgresql.PostgreSQLContainer; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * The relocated class: {@code org.testcontainers.postgresql.PostgreSQLContainer}, confirmed on the + * real 2.0.5 jar in docs/output/02 of the companion {@code data-jpa-testcontainers} module from the + * previous post. It dropped its self-referential generic - {@code PostgreSQLContainer}, not + * {@code PostgreSQLContainer} - which is a real compile-time change, not a cosmetic one. + * + *

{@code @EnabledIfDockerAvailable} is new in Testcontainers 2.0's JUnit 5 extension + * ({@code testcontainers-junit-jupiter}); it did not exist in the 1.x {@code junit-jupiter} + * artifact. The first draft of this class put the annotation on the test method, which + * compiles but does nothing useful: {@code TestcontainersExtension.beforeAll} starts every + * {@code @Container} field before any method-level condition is even evaluated, so the real + * failure in docs/output/01-guard-on-method-still-fails.txt happened before the guard had a + * chance to run. The annotation has to sit on the class, which is what gates container + * startup itself. With it there, this sandbox's missing Docker daemon produces a clean + * {@code Skipped: 1} instead of an error - see docs/output/00-full-test-run.txt.

+ */ +@Testcontainers +@EnabledIfDockerAvailable +class NewPostgresContainerSkipsCleanlyTest { + + @Container + static GenericContainer postgres = new PostgreSQLContainer("postgres:17"); + + @Test + void containerIsConfiguredWithTheRelocatedNonGenericClass() { + assertThat(postgres.getDockerImageName()).isEqualTo("postgres:17"); + assertThat(postgres).isInstanceOf(PostgreSQLContainer.class); + } +}