Add data-jpa-testcontainers module: @DataJpaTest's default substitution, the Flyway-never-runs trap, and @ServiceConnection on Testcontainers 2.0.5 (post #45)
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# data-jpa-testcontainers
|
||||
|
||||
Companion module for [`@DataJpaTest` with Testcontainers `@ServiceConnection` on Spring Boot 4.1](https://ankurm.com/) on ankurm.com.
|
||||
|
||||
## What this is
|
||||
|
||||
Six JUnit 5 test classes against one JPA repository (`Product`), each isolating one fact about
|
||||
what `@DataJpaTest`'s default embedded-database substitution actually does, what
|
||||
`@ServiceConnection` wires in its place, and what the defaults do not do (Flyway migrations are
|
||||
not one of them). No `docs/NN-topic.md` chapters — everything beyond what fits in the post itself
|
||||
is in the Javadoc on these six test classes and in the captured transcripts below.
|
||||
|
||||
**This module was built and tested in a sandbox with no Docker daemon available.** Five of the six
|
||||
test classes run and pass (or cleanly skip) without one. The sixth demonstrates, on purpose, the
|
||||
real failure you get from the one case that genuinely needs a container. See the versions table and
|
||||
the test table below for exactly which is which.
|
||||
|
||||
## Versions
|
||||
|
||||
| Dependency | Version | Verified against |
|
||||
|---|---|---|
|
||||
| Spring Boot | 4.1.1 | `spring-boot-dependencies-4.1.1.pom` |
|
||||
| Testcontainers | 2.0.5 | same BOM; `testcontainers-bom-2.0.5.pom` |
|
||||
| Flyway | 12.4.0 | same BOM |
|
||||
| Hibernate ORM | 7.4.5.Final | runtime log, this module's own test run |
|
||||
| H2 | 2.4.240 | runtime log, this module's own test run |
|
||||
| JDK | 25 (Temurin) | `java -version`, this module's own build |
|
||||
|
||||
## Quickstart
|
||||
|
||||
```bash
|
||||
mvn test # 6 of 7 run; 1 skips cleanly
|
||||
mvn test -Dtest=ServiceConnectionWithoutGuardFailsToStartTest # the one deliberate failure
|
||||
```
|
||||
|
||||
## Test classes
|
||||
|
||||
| Class | What it proves | Needs Docker | Outcome here |
|
||||
|---|---|---|---|
|
||||
| `DefaultReplacementTest` | Plain `@DataJpaTest` substitutes an embedded H2 DataSource, and each test method is rolled back independently of execution order | No | Pass |
|
||||
| `FlywayDoesNotRunUnderPlainDataJpaTestTest` | `@DataJpaTest`'s own auto-configuration import list never includes `FlywayAutoConfiguration` or `LiquibaseAutoConfiguration` — your migrations never run, substitution or not | No | Pass |
|
||||
| `FlywayRunsWhenExplicitlyImportedTest` | The one-line fix: `@ImportAutoConfiguration(FlywayAutoConfiguration.class)` | No | Pass |
|
||||
| `NoSubstitutionStillSilentlyUsesH2Test` | `@AutoConfigureTestDatabase(replace = Replace.NONE)` alone is not a guarantee of a real connection — with nothing else configured, ordinary `DataSourceAutoConfiguration` still silently hands you embedded H2 | No | Pass |
|
||||
| `ServiceConnectionSkipsCleanlyTest` | The intended shape: `@ServiceConnection` + `@Container` + `replace = Replace.NONE`, guarded by Testcontainers 2.0's new `@EnabledIfDockerAvailable` | Yes (guarded) | Skipped |
|
||||
| `ServiceConnectionWithoutGuardFailsToStartTest` | The same class, minus the guard | Yes (unguarded) | **Fails — on purpose.** Excluded from `mvn test` by name in `pom.xml`; run it explicitly |
|
||||
|
||||
## Captured output
|
||||
|
||||
| File | Contents |
|
||||
|---|---|
|
||||
| `docs/output/00-full-test-run.txt` | `mvn clean test` — 7 tests, 1 skip, build green |
|
||||
| `docs/output/01-postgresqlcontainer-relocation-javap.txt` | `javap` proof that `org.testcontainers.postgresql.PostgreSQLContainer` (2.0.5's new home) and the deprecated `org.testcontainers.containers.PostgreSQLContainer` shim live in the *same* jar, and that the old class alone keeps the self-referential `<SELF extends ...>` generic |
|
||||
| `docs/output/02-serviceconnection-unaffected-javap.txt` | `javap` proof that `JdbcContainerConnectionDetailsFactory` is typed against `org.testcontainers.containers.JdbcDatabaseContainer<?>` — unmoved by the 2.0 package split, which is why `@ServiceConnection` needed no changes |
|
||||
| `docs/output/04-service-connection-without-guard-fails.txt` | The real `ContainerFetchException` / `IllegalStateException` from trying to start a Postgres container with no Docker daemon present, and no guard against that |
|
||||
| `docs/output/05-service-connection-skips-cleanly.txt` | The same absence of Docker, this time behind `@EnabledIfDockerAvailable` — one line, `Skipped: 1`, no failure |
|
||||
|
||||
## What's sourced from code, not run here
|
||||
|
||||
Two things this article discusses are backed by reading Spring Boot's and Testcontainers' own
|
||||
class files and import manifests rather than by a run in this sandbox, and are called out as such
|
||||
in the post itself: what a *successful* real-Postgres run under `@ServiceConnection` would actually
|
||||
return once a Docker daemon is present (the wiring is verified; the live round trip is not), and
|
||||
Testcontainers' reusable-container feature (`.withReuse(true)` plus `~/.testcontainers.properties`),
|
||||
which has nothing to do with Docker availability but was out of scope for a module built in one
|
||||
sitting.
|
||||
@@ -0,0 +1,184 @@
|
||||
Picked up JAVA_TOOL_OPTIONS: -Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts -Djavax.net.ssl.trustStoreType=JKS -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=34689 -Dhttp.nonProxyHosts=localhost|127.0.0.1|::1|127.*|0.*|::|169.254.*|api.anthropic.com|api-staging.anthropic.com|api-pr-preview.anthropic.com|mcp-proxy.anthropic.com|mcp-proxy-staging.anthropic.com|registry.npmjs.org|jsr.io|npm.jsr.io|pypi.org|files.pythonhosted.org|index.crates.io|proxy.golang.org|host.docker.internal|10.*|172.16.*|172.17.*|172.18.*|172.19.*|172.20.*|172.21.*|172.22.*|172.23.*|172.24.*|172.25.*|172.26.*|172.27.*|172.28.*|172.29.*|172.30.*|172.31.*|192.168.*|100.64.0.0/10|*.svc.cluster.local|*.svc.cluster.local -Djdk.http.auth.tunneling.disabledSchemes= -Djdk.http.auth.proxying.disabledSchemes=
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/opt/maven/lib/guice-5.1.0-classes.jar)
|
||||
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
|
||||
[INFO] Scanning for projects...
|
||||
[INFO]
|
||||
[INFO] -----------------< com.ankurm:data-jpa-testcontainers >-----------------
|
||||
[INFO] Building data-jpa-testcontainers 1.0.0
|
||||
[INFO] from pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- clean:3.5.0:clean (default-clean) @ data-jpa-testcontainers ---
|
||||
[INFO] Deleting /home/claude/spring-boot-demo/data-jpa-testcontainers/target
|
||||
[INFO]
|
||||
[INFO] --- resources:3.5.0:resources (default-resources) @ data-jpa-testcontainers ---
|
||||
[INFO] Copying 0 resource from src/main/resources to target/classes
|
||||
[INFO] Copying 1 resource from src/main/resources to target/classes
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.15.0:compile (default-compile) @ data-jpa-testcontainers ---
|
||||
[INFO] Recompiling the module because of changed source code.
|
||||
[INFO] Compiling 3 source files with javac [debug parameters release 25] to target/classes
|
||||
[INFO]
|
||||
[INFO] --- resources:3.5.0:testResources (default-testResources) @ data-jpa-testcontainers ---
|
||||
[INFO] skip non existing resourceDirectory /home/claude/spring-boot-demo/data-jpa-testcontainers/src/test/resources
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.15.0:testCompile (default-testCompile) @ data-jpa-testcontainers ---
|
||||
[INFO] Recompiling the module because of changed dependency.
|
||||
[INFO] Compiling 6 source files with javac [debug parameters release 25] to target/test-classes
|
||||
[INFO]
|
||||
[INFO] --- surefire:3.5.6:test (default-test) @ data-jpa-testcontainers ---
|
||||
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
|
||||
[INFO]
|
||||
[INFO] -------------------------------------------------------
|
||||
[INFO] T E S T S
|
||||
[INFO] -------------------------------------------------------
|
||||
Picked up JAVA_TOOL_OPTIONS: -Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts -Djavax.net.ssl.trustStoreType=JKS -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=34689 -Dhttp.nonProxyHosts=localhost|127.0.0.1|::1|127.*|0.*|::|169.254.*|api.anthropic.com|api-staging.anthropic.com|api-pr-preview.anthropic.com|mcp-proxy.anthropic.com|mcp-proxy-staging.anthropic.com|registry.npmjs.org|jsr.io|npm.jsr.io|pypi.org|files.pythonhosted.org|index.crates.io|proxy.golang.org|host.docker.internal|10.*|172.16.*|172.17.*|172.18.*|172.19.*|172.20.*|172.21.*|172.22.*|172.23.*|172.24.*|172.25.*|172.26.*|172.27.*|172.28.*|172.29.*|172.30.*|172.31.*|192.168.*|100.64.0.0/10|*.svc.cluster.local|*.svc.cluster.local -Djdk.http.auth.tunneling.disabledSchemes= -Djdk.http.auth.proxying.disabledSchemes=
|
||||
[INFO] Running com.ankurm.datajpa.DefaultReplacementTest
|
||||
17:19:49.092 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.ankurm.datajpa.DefaultReplacementTest]: DefaultReplacementTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
17:19:49.365 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.ankurm.datajpa.DataJpaTestcontainersApplication for test class com.ankurm.datajpa.DefaultReplacementTest
|
||||
17:19:49.370 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.ankurm.datajpa.DefaultReplacementTest]: DefaultReplacementTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
17:19:49.405 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.ankurm.datajpa.DataJpaTestcontainersApplication for test class com.ankurm.datajpa.DefaultReplacementTest
|
||||
|
||||
. ____ _ __ _ _
|
||||
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
|
||||
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
|
||||
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
|
||||
' |____| .__|_| |_|_| |_\__, | / / / /
|
||||
=========|_|==============|___/=/_/_/_/
|
||||
|
||||
:: Spring Boot :: (v4.1.1)
|
||||
|
||||
2026-10-08T17:19:50.032+05:30 INFO 2231 --- [ main] c.ankurm.datajpa.DefaultReplacementTest : Starting DefaultReplacementTest using Java 25.0.4.1 with PID 2231 (started by root in /home/claude/spring-boot-demo/data-jpa-testcontainers)
|
||||
2026-10-08T17:19:50.034+05:30 INFO 2231 --- [ main] c.ankurm.datajpa.DefaultReplacementTest : No active profile set, falling back to 1 default profile: "default"
|
||||
2026-10-08T17:19:50.614+05:30 INFO 2231 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
|
||||
2026-10-08T17:19:50.751+05:30 INFO 2231 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 126 ms. Found 1 JPA repository interface.
|
||||
2026-10-08T17:19:50.849+05:30 INFO 2231 --- [ main] beddedDataSourceBeanFactoryPostProcessor : Replacing 'dataSource' DataSource bean with embedded version
|
||||
2026-10-08T17:19:51.122+05:30 INFO 2231 --- [ main] o.s.j.d.e.EmbeddedDatabaseFactory : Starting embedded database: url='jdbc:h2:mem:27737b58-793d-4017-ae78-1a78ebfc5b27;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=false', username='sa'
|
||||
2026-10-08T17:19:51.815+05:30 INFO 2231 --- [ main] org.flywaydb.core.FlywayExecutor : Database: jdbc:h2:mem:27737b58-793d-4017-ae78-1a78ebfc5b27 (H2 2.4)
|
||||
2026-10-08T17:19:51.888+05:30 WARN 2231 --- [ main] o.f.c.internal.database.base.Database : Using H2 2.4.240 which is newer than the version Flyway has been verified with. The latest verified version of H2 is 2.3.232.
|
||||
2026-10-08T17:19:51.949+05:30 INFO 2231 --- [ main] o.f.c.i.s.JdbcTableSchemaHistory : Schema history table "PUBLIC"."flyway_schema_history" does not exist yet
|
||||
2026-10-08T17:19:51.952+05:30 INFO 2231 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 1 migration (execution time 00:00.040s)
|
||||
2026-10-08T17:19:51.960+05:30 INFO 2231 --- [ main] o.f.c.i.s.JdbcTableSchemaHistory : Creating Schema History table "PUBLIC"."flyway_schema_history" ...
|
||||
2026-10-08T17:19:52.002+05:30 INFO 2231 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema "PUBLIC": << Empty Schema >>
|
||||
2026-10-08T17:19:52.015+05:30 INFO 2231 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema "PUBLIC" to version "1 - create product"
|
||||
2026-10-08T17:19:52.034+05:30 INFO 2231 --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 1 migration to schema "PUBLIC", now at version v1 (execution time 00:00.008s)
|
||||
2026-10-08T17:19:52.268+05:30 INFO 2231 --- [ main] org.hibernate.orm.jpa : HHH008540: Processing PersistenceUnitInfo [name: default]
|
||||
2026-10-08T17:19:52.332+05:30 INFO 2231 --- [ main] org.hibernate.orm.core : HHH000001: Hibernate ORM core version 7.4.5.Final
|
||||
2026-10-08T17:19:52.886+05:30 INFO 2231 --- [ main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer
|
||||
2026-10-08T17:19:53.006+05:30 INFO 2231 --- [ main] org.hibernate.orm.connections.pooling : HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:h2:mem:27737b58-793d-4017-ae78-1a78ebfc5b27]
|
||||
Database driver: H2 JDBC Driver
|
||||
Database dialect: H2Dialect
|
||||
Database version: 2.4.240
|
||||
Default catalog/schema: 27737B58-793D-4017-AE78-1A78EBFC5B27/PUBLIC
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: READ_COMMITTED [default READ_COMMITTED]
|
||||
JDBC fetch size: 100
|
||||
Pool: DataSourceConnectionProvider
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-10-08T17:19:54.129+05:30 INFO 2231 --- [ main] org.hibernate.orm.core : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
2026-10-08T17:19:54.145+05:30 INFO 2231 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
|
||||
2026-10-08T17:19:54.332+05:30 INFO 2231 --- [ main] o.s.d.j.r.query.QueryEnhancerFactories : Hibernate is in classpath; If applicable, HQL parser will be used.
|
||||
2026-10-08T17:19:54.604+05:30 INFO 2231 --- [ main] c.ankurm.datajpa.DefaultReplacementTest : Started DefaultReplacementTest in 5.076 seconds (process running for 7.153)
|
||||
Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK. Please add Mockito as an agent to your build as described in Mockito's documentation: https://javadoc.io/doc/org.mockito/mockito-core/latest/org.mockito/org/mockito/Mockito.html#0.3
|
||||
OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
|
||||
WARNING: A Java agent has been loaded dynamically (/root/.m2/repository/net/bytebuddy/byte-buddy-agent/1.18.11/byte-buddy-agent-1.18.11.jar)
|
||||
WARNING: If a serviceability tool is in use, please run with -XX:+EnableDynamicAgentLoading to hide this warning
|
||||
WARNING: If a serviceability tool is not in use, please run with -Djdk.instrument.traceUsage for more information
|
||||
WARNING: Dynamic loading of agents will be disallowed by default in a future release
|
||||
Hibernate: select count(*) from product p1_0
|
||||
Hibernate: select p1_0.id,p1_0.name,p1_0.sku from product p1_0 where p1_0.sku=?
|
||||
JDBC reports database product name: H2
|
||||
Hibernate: insert into product (name,sku,id) values (?,?,default)
|
||||
Hibernate: select p1_0.id,p1_0.name,p1_0.sku from product p1_0 where p1_0.sku=?
|
||||
Hibernate: select count(*) from product p1_0
|
||||
[INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 7.329 s -- in com.ankurm.datajpa.DefaultReplacementTest
|
||||
[INFO] Running com.ankurm.datajpa.NoSubstitutionStillSilentlyUsesH2Test
|
||||
2026-10-08T17:19:56.108+05:30 INFO 2231 --- [ main] t.c.s.AnnotationConfigContextLoaderUtils : Could not detect default configuration classes for test class [com.ankurm.datajpa.NoSubstitutionStillSilentlyUsesH2Test]: NoSubstitutionStillSilentlyUsesH2Test does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
2026-10-08T17:19:56.189+05:30 INFO 2231 --- [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.datajpa.DataJpaTestcontainersApplication for test class com.ankurm.datajpa.NoSubstitutionStillSilentlyUsesH2Test
|
||||
2026-10-08T17:19:56.197+05:30 INFO 2231 --- [ main] t.c.s.AnnotationConfigContextLoaderUtils : Could not detect default configuration classes for test class [com.ankurm.datajpa.NoSubstitutionStillSilentlyUsesH2Test]: NoSubstitutionStillSilentlyUsesH2Test does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
2026-10-08T17:19:56.238+05:30 INFO 2231 --- [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.datajpa.DataJpaTestcontainersApplication for test class com.ankurm.datajpa.NoSubstitutionStillSilentlyUsesH2Test
|
||||
|
||||
. ____ _ __ _ _
|
||||
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
|
||||
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
|
||||
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
|
||||
' |____| .__|_| |_|_| |_\__, | / / / /
|
||||
=========|_|==============|___/=/_/_/_/
|
||||
|
||||
:: Spring Boot :: (v4.1.1)
|
||||
|
||||
2026-10-08T17:19:56.294+05:30 INFO 2231 --- [ main] .d.NoSubstitutionStillSilentlyUsesH2Test : Starting NoSubstitutionStillSilentlyUsesH2Test using Java 25.0.4.1 with PID 2231 (started by root in /home/claude/spring-boot-demo/data-jpa-testcontainers)
|
||||
2026-10-08T17:19:56.295+05:30 INFO 2231 --- [ main] .d.NoSubstitutionStillSilentlyUsesH2Test : No active profile set, falling back to 1 default profile: "default"
|
||||
2026-10-08T17:19:56.452+05:30 INFO 2231 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
|
||||
2026-10-08T17:19:56.469+05:30 INFO 2231 --- [ main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 13 ms. Found 1 JPA repository interface.
|
||||
2026-10-08T17:19:56.642+05:30 INFO 2231 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
|
||||
2026-10-08T17:19:56.665+05:30 INFO 2231 --- [ main] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Added connection conn9: url=jdbc:h2:mem:fb5a3fcb-6cc0-4a37-baff-7dbd0bfb51fd user=SA
|
||||
2026-10-08T17:19:56.667+05:30 INFO 2231 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
|
||||
2026-10-08T17:19:56.673+05:30 INFO 2231 --- [ main] org.flywaydb.core.FlywayExecutor : Database: jdbc:h2:mem:fb5a3fcb-6cc0-4a37-baff-7dbd0bfb51fd (H2 2.4)
|
||||
2026-10-08T17:19:56.686+05:30 WARN 2231 --- [ main] o.f.c.internal.database.base.Database : Using H2 2.4.240 which is newer than the version Flyway has been verified with. The latest verified version of H2 is 2.3.232.
|
||||
2026-10-08T17:19:56.690+05:30 INFO 2231 --- [ main] o.f.c.i.s.JdbcTableSchemaHistory : Schema history table "PUBLIC"."flyway_schema_history" does not exist yet
|
||||
2026-10-08T17:19:56.691+05:30 INFO 2231 --- [ main] o.f.core.internal.command.DbValidate : Successfully validated 1 migration (execution time 00:00.002s)
|
||||
2026-10-08T17:19:56.693+05:30 INFO 2231 --- [ main] o.f.c.i.s.JdbcTableSchemaHistory : Creating Schema History table "PUBLIC"."flyway_schema_history" ...
|
||||
2026-10-08T17:19:56.703+05:30 INFO 2231 --- [ main] o.f.core.internal.command.DbMigrate : Current version of schema "PUBLIC": << Empty Schema >>
|
||||
2026-10-08T17:19:56.707+05:30 INFO 2231 --- [ main] o.f.core.internal.command.DbMigrate : Migrating schema "PUBLIC" to version "1 - create product"
|
||||
2026-10-08T17:19:56.715+05:30 INFO 2231 --- [ main] o.f.core.internal.command.DbMigrate : Successfully applied 1 migration to schema "PUBLIC", now at version v1 (execution time 00:00.004s)
|
||||
2026-10-08T17:19:56.752+05:30 INFO 2231 --- [ main] org.hibernate.orm.jpa : HHH008540: Processing PersistenceUnitInfo [name: default]
|
||||
2026-10-08T17:19:56.808+05:30 INFO 2231 --- [ main] o.s.o.j.p.SpringPersistenceUnitInfo : No LoadTimeWeaver setup: ignoring JPA class transformer
|
||||
2026-10-08T17:19:56.814+05:30 INFO 2231 --- [ main] org.hibernate.orm.connections.pooling : HHH10001005: Database info:
|
||||
Database JDBC URL [jdbc:h2:mem:fb5a3fcb-6cc0-4a37-baff-7dbd0bfb51fd]
|
||||
Database driver: H2 JDBC Driver
|
||||
Database dialect: H2Dialect
|
||||
Database version: 2.4.240
|
||||
Default catalog/schema: FB5A3FCB-6CC0-4A37-BAFF-7DBD0BFB51FD/PUBLIC
|
||||
Autocommit mode: undefined/unknown
|
||||
Isolation level: READ_COMMITTED [default READ_COMMITTED]
|
||||
JDBC fetch size: 100
|
||||
Pool: DataSourceConnectionProvider
|
||||
Minimum pool size: undefined/unknown
|
||||
Maximum pool size: undefined/unknown
|
||||
2026-10-08T17:19:56.850+05:30 INFO 2231 --- [ main] org.hibernate.orm.core : HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
|
||||
2026-10-08T17:19:56.851+05:30 INFO 2231 --- [ main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
|
||||
2026-10-08T17:19:56.915+05:30 INFO 2231 --- [ main] .d.NoSubstitutionStillSilentlyUsesH2Test : Started NoSubstitutionStillSilentlyUsesH2Test in 0.668 seconds (process running for 9.464)
|
||||
JDBC reports database product name: H2 (even with replace = Replace.NONE and no @ServiceConnection anywhere)
|
||||
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.852 s -- in com.ankurm.datajpa.NoSubstitutionStillSilentlyUsesH2Test
|
||||
[INFO] Running com.ankurm.datajpa.FlywayDoesNotRunUnderPlainDataJpaTestTest
|
||||
2026-10-08T17:19:56.952+05:30 INFO 2231 --- [ main] t.c.s.AnnotationConfigContextLoaderUtils : Could not detect default configuration classes for test class [com.ankurm.datajpa.FlywayDoesNotRunUnderPlainDataJpaTestTest]: FlywayDoesNotRunUnderPlainDataJpaTestTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
2026-10-08T17:19:57.008+05:30 INFO 2231 --- [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.datajpa.DataJpaTestcontainersApplication for test class com.ankurm.datajpa.FlywayDoesNotRunUnderPlainDataJpaTestTest
|
||||
2026-10-08T17:19:57.008+05:30 INFO 2231 --- [ main] t.c.s.AnnotationConfigContextLoaderUtils : Could not detect default configuration classes for test class [com.ankurm.datajpa.FlywayDoesNotRunUnderPlainDataJpaTestTest]: FlywayDoesNotRunUnderPlainDataJpaTestTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
2026-10-08T17:19:57.064+05:30 INFO 2231 --- [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.datajpa.DataJpaTestcontainersApplication for test class com.ankurm.datajpa.FlywayDoesNotRunUnderPlainDataJpaTestTest
|
||||
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.137 s -- in com.ankurm.datajpa.FlywayDoesNotRunUnderPlainDataJpaTestTest
|
||||
[INFO] Running com.ankurm.datajpa.FlywayRunsWhenExplicitlyImportedTest
|
||||
2026-10-08T17:19:57.091+05:30 INFO 2231 --- [ main] t.c.s.AnnotationConfigContextLoaderUtils : Could not detect default configuration classes for test class [com.ankurm.datajpa.FlywayRunsWhenExplicitlyImportedTest]: FlywayRunsWhenExplicitlyImportedTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
2026-10-08T17:19:57.107+05:30 INFO 2231 --- [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.datajpa.DataJpaTestcontainersApplication for test class com.ankurm.datajpa.FlywayRunsWhenExplicitlyImportedTest
|
||||
2026-10-08T17:19:57.107+05:30 INFO 2231 --- [ main] t.c.s.AnnotationConfigContextLoaderUtils : Could not detect default configuration classes for test class [com.ankurm.datajpa.FlywayRunsWhenExplicitlyImportedTest]: FlywayRunsWhenExplicitlyImportedTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
2026-10-08T17:19:57.132+05:30 INFO 2231 --- [ main] .b.t.c.SpringBootTestContextBootstrapper : Found @SpringBootConfiguration com.ankurm.datajpa.DataJpaTestcontainersApplication for test class com.ankurm.datajpa.FlywayRunsWhenExplicitlyImportedTest
|
||||
flyway_schema_history row: version=1 description=create product success=true
|
||||
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.085 s -- in com.ankurm.datajpa.FlywayRunsWhenExplicitlyImportedTest
|
||||
2026-10-08T17:19:57.218+05:30 INFO 2231 --- [ main] org.testcontainers.DockerClientFactory : Testcontainers version: 2.0.5
|
||||
WARNING: A restricted method in java.lang.System has been called
|
||||
WARNING: java.lang.System::load has been called by com.sun.jna.Native in an unnamed module (file:/root/.m2/repository/net/java/dev/jna/jna/5.18.1/jna-5.18.1.jar)
|
||||
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module
|
||||
WARNING: Restricted methods will be blocked in a future release unless native access is enabled
|
||||
|
||||
2026-10-08T17:19:57.537+05:30 INFO 2231 --- [ main] .t.d.DockerMachineClientProviderStrategy : docker-machine executable was not found on PATH ([/opt/jdk-25/bin, /home/claude/.npm-global/bin, /nix/var/nix/profiles/default/bin, /root/.local/bin, /root/.cargo/bin, /usr/local/go/bin, /opt/node22/bin, /opt/maven/bin, /opt/gradle/bin, /opt/rbenv/bin, /root/.bun/bin, /usr/local/sbin, /usr/local/bin, /usr/sbin, /usr/bin, /sbin, /bin])
|
||||
2026-10-08T17:19:57.538+05:30 ERROR 2231 --- [ main] o.t.d.DockerClientProviderStrategy : Could not find a valid Docker environment. Please check configuration. Attempted configurations were:
|
||||
UnixSocketClientProviderStrategy: failed with exception InvalidConfigurationException (Could not find unix domain socket). Root cause NoSuchFileException (/var/run/docker.sock)
|
||||
DockerDesktopClientProviderStrategy: failed with exception NullPointerException (Cannot invoke "java.nio.file.Path.toString()" because the return value of "org.testcontainers.dockerclient.DockerDesktopClientProviderStrategy.getSocketPath()" is null)As no valid configuration was found, execution cannot continue.
|
||||
See https://java.testcontainers.org/on_failure.html for more details.
|
||||
[INFO] Running com.ankurm.datajpa.ServiceConnectionSkipsCleanlyTest
|
||||
[WARNING] Tests run: 1, Failures: 0, Errors: 0, Skipped: 1, Time elapsed: 0.001 s -- in com.ankurm.datajpa.ServiceConnectionSkipsCleanlyTest
|
||||
[INFO]
|
||||
[INFO] Results:
|
||||
[INFO]
|
||||
[INFO] Tests run: 7, Failures: 0, Errors: 0, Skipped: 1
|
||||
[INFO]
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD SUCCESS
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 15.580 s
|
||||
[INFO] Finished at: 2026-10-08T17:19:57+05:30
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
@@ -0,0 +1,77 @@
|
||||
$ javap -p org/testcontainers/postgresql/PostgreSQLContainer.class # testcontainers-postgresql-2.0.5.jar
|
||||
Compiled from "PostgreSQLContainer.java"
|
||||
public class org.testcontainers.postgresql.PostgreSQLContainer extends org.testcontainers.containers.JdbcDatabaseContainer<org.testcontainers.postgresql.PostgreSQLContainer> {
|
||||
public static final java.lang.String NAME;
|
||||
public static final java.lang.String IMAGE;
|
||||
public static final java.lang.String DEFAULT_TAG;
|
||||
private static final org.testcontainers.utility.DockerImageName DEFAULT_IMAGE_NAME;
|
||||
private static final org.testcontainers.utility.DockerImageName PGVECTOR_IMAGE_NAME;
|
||||
public static final java.lang.Integer POSTGRESQL_PORT;
|
||||
static final java.lang.String DEFAULT_USER;
|
||||
static final java.lang.String DEFAULT_PASSWORD;
|
||||
private java.lang.String databaseName;
|
||||
private java.lang.String username;
|
||||
private java.lang.String password;
|
||||
private static final java.lang.String FSYNC_OFF_OPTION;
|
||||
public org.testcontainers.postgresql.PostgreSQLContainer(java.lang.String);
|
||||
public org.testcontainers.postgresql.PostgreSQLContainer(org.testcontainers.utility.DockerImageName);
|
||||
protected java.util.Set<java.lang.Integer> getLivenessCheckPorts();
|
||||
protected void configure();
|
||||
public java.lang.String getDriverClassName();
|
||||
public java.lang.String getJdbcUrl();
|
||||
public java.lang.String getDatabaseName();
|
||||
public java.lang.String getUsername();
|
||||
public java.lang.String getPassword();
|
||||
public java.lang.String getTestQueryString();
|
||||
public org.testcontainers.postgresql.PostgreSQLContainer withDatabaseName(java.lang.String);
|
||||
public org.testcontainers.postgresql.PostgreSQLContainer withUsername(java.lang.String);
|
||||
public org.testcontainers.postgresql.PostgreSQLContainer withPassword(java.lang.String);
|
||||
protected void waitUntilContainerStarted();
|
||||
public org.testcontainers.containers.JdbcDatabaseContainer withDatabaseName(java.lang.String);
|
||||
public org.testcontainers.containers.JdbcDatabaseContainer withPassword(java.lang.String);
|
||||
public org.testcontainers.containers.JdbcDatabaseContainer withUsername(java.lang.String);
|
||||
static {};
|
||||
}
|
||||
|
||||
$ javap -p org/testcontainers/containers/PostgreSQLContainer.class # SAME jar, deprecated shim
|
||||
Compiled from "PostgreSQLContainer.java"
|
||||
public class org.testcontainers.containers.PostgreSQLContainer<SELF extends org.testcontainers.containers.PostgreSQLContainer<SELF>> extends org.testcontainers.containers.JdbcDatabaseContainer<SELF> {
|
||||
public static final java.lang.String NAME;
|
||||
public static final java.lang.String IMAGE;
|
||||
public static final java.lang.String DEFAULT_TAG;
|
||||
private static final org.testcontainers.utility.DockerImageName DEFAULT_IMAGE_NAME;
|
||||
private static final org.testcontainers.utility.DockerImageName PGVECTOR_IMAGE_NAME;
|
||||
public static final java.lang.Integer POSTGRESQL_PORT;
|
||||
static final java.lang.String DEFAULT_USER;
|
||||
static final java.lang.String DEFAULT_PASSWORD;
|
||||
private java.lang.String databaseName;
|
||||
private java.lang.String username;
|
||||
private java.lang.String password;
|
||||
private static final java.lang.String FSYNC_OFF_OPTION;
|
||||
public org.testcontainers.containers.PostgreSQLContainer();
|
||||
public org.testcontainers.containers.PostgreSQLContainer(java.lang.String);
|
||||
public org.testcontainers.containers.PostgreSQLContainer(org.testcontainers.utility.DockerImageName);
|
||||
protected java.util.Set<java.lang.Integer> getLivenessCheckPorts();
|
||||
protected void configure();
|
||||
public java.lang.String getDriverClassName();
|
||||
public java.lang.String getJdbcUrl();
|
||||
public java.lang.String getDatabaseName();
|
||||
public java.lang.String getUsername();
|
||||
public java.lang.String getPassword();
|
||||
public java.lang.String getTestQueryString();
|
||||
public SELF withDatabaseName(java.lang.String);
|
||||
public SELF withUsername(java.lang.String);
|
||||
public SELF withPassword(java.lang.String);
|
||||
protected void waitUntilContainerStarted();
|
||||
public org.testcontainers.containers.JdbcDatabaseContainer withDatabaseName(java.lang.String);
|
||||
public org.testcontainers.containers.JdbcDatabaseContainer withPassword(java.lang.String);
|
||||
public org.testcontainers.containers.JdbcDatabaseContainer withUsername(java.lang.String);
|
||||
static {};
|
||||
}
|
||||
|
||||
$ javap -v org/testcontainers/containers/PostgreSQLContainer.class | grep -i deprecated
|
||||
#7 = Utf8 Ljava/lang/Deprecated;
|
||||
#232 = Utf8 Deprecated
|
||||
Deprecated: true
|
||||
java.lang.Deprecated
|
||||
Deprecated: true
|
||||
@@ -0,0 +1,15 @@
|
||||
$ javap -p org/springframework/boot/jdbc/testcontainers/JdbcContainerConnectionDetailsFactory.class # spring-boot-jdbc-4.1.1.jar
|
||||
Compiled from "JdbcContainerConnectionDetailsFactory.java"
|
||||
class org.springframework.boot.jdbc.testcontainers.JdbcContainerConnectionDetailsFactory extends org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory<org.testcontainers.containers.JdbcDatabaseContainer<?>, org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails> {
|
||||
org.springframework.boot.jdbc.testcontainers.JdbcContainerConnectionDetailsFactory();
|
||||
protected org.springframework.boot.jdbc.autoconfigure.JdbcConnectionDetails getContainerConnectionDetails(org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource<org.testcontainers.containers.JdbcDatabaseContainer<?>>);
|
||||
protected org.springframework.boot.autoconfigure.service.connection.ConnectionDetails getContainerConnectionDetails(org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource);
|
||||
}
|
||||
|
||||
$ javap -p org/springframework/boot/testcontainers/service/connection/ServiceConnection.class # spring-boot-testcontainers-4.1.1.jar
|
||||
Compiled from "ServiceConnection.java"
|
||||
public interface org.springframework.boot.testcontainers.service.connection.ServiceConnection extends java.lang.annotation.Annotation {
|
||||
public abstract java.lang.String value();
|
||||
public abstract java.lang.String name();
|
||||
public abstract java.lang.Class<? extends org.springframework.boot.autoconfigure.service.connection.ConnectionDetails>[] type();
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
Picked up JAVA_TOOL_OPTIONS: -Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts -Djavax.net.ssl.trustStoreType=JKS -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=34689 -Dhttp.nonProxyHosts=localhost|127.0.0.1|::1|127.*|0.*|::|169.254.*|api.anthropic.com|api-staging.anthropic.com|api-pr-preview.anthropic.com|mcp-proxy.anthropic.com|mcp-proxy-staging.anthropic.com|registry.npmjs.org|jsr.io|npm.jsr.io|pypi.org|files.pythonhosted.org|index.crates.io|proxy.golang.org|host.docker.internal|10.*|172.16.*|172.17.*|172.18.*|172.19.*|172.20.*|172.21.*|172.22.*|172.23.*|172.24.*|172.25.*|172.26.*|172.27.*|172.28.*|172.29.*|172.30.*|172.31.*|192.168.*|100.64.0.0/10|*.svc.cluster.local|*.svc.cluster.local -Djdk.http.auth.tunneling.disabledSchemes= -Djdk.http.auth.proxying.disabledSchemes=
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/opt/maven/lib/guice-5.1.0-classes.jar)
|
||||
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
|
||||
[INFO] Scanning for projects...
|
||||
[INFO]
|
||||
[INFO] -----------------< com.ankurm:data-jpa-testcontainers >-----------------
|
||||
[INFO] Building data-jpa-testcontainers 1.0.0
|
||||
[INFO] from pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- resources:3.5.0:resources (default-resources) @ data-jpa-testcontainers ---
|
||||
[INFO] Copying 0 resource from src/main/resources to target/classes
|
||||
[INFO] Copying 1 resource from src/main/resources to target/classes
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.15.0:compile (default-compile) @ data-jpa-testcontainers ---
|
||||
[INFO] Nothing to compile - all classes are up to date.
|
||||
[INFO]
|
||||
[INFO] --- resources:3.5.0:testResources (default-testResources) @ data-jpa-testcontainers ---
|
||||
[INFO] skip non existing resourceDirectory /home/claude/spring-boot-demo/data-jpa-testcontainers/src/test/resources
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.15.0:testCompile (default-testCompile) @ data-jpa-testcontainers ---
|
||||
[INFO] Nothing to compile - all classes are up to date.
|
||||
[INFO]
|
||||
[INFO] --- surefire:3.5.6:test (default-test) @ data-jpa-testcontainers ---
|
||||
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
|
||||
[INFO]
|
||||
[INFO] -------------------------------------------------------
|
||||
[INFO] T E S T S
|
||||
[INFO] -------------------------------------------------------
|
||||
Picked up JAVA_TOOL_OPTIONS: -Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts -Djavax.net.ssl.trustStoreType=JKS -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=34689 -Dhttp.nonProxyHosts=localhost|127.0.0.1|::1|127.*|0.*|::|169.254.*|api.anthropic.com|api-staging.anthropic.com|api-pr-preview.anthropic.com|mcp-proxy.anthropic.com|mcp-proxy-staging.anthropic.com|registry.npmjs.org|jsr.io|npm.jsr.io|pypi.org|files.pythonhosted.org|index.crates.io|proxy.golang.org|host.docker.internal|10.*|172.16.*|172.17.*|172.18.*|172.19.*|172.20.*|172.21.*|172.22.*|172.23.*|172.24.*|172.25.*|172.26.*|172.27.*|172.28.*|172.29.*|172.30.*|172.31.*|192.168.*|100.64.0.0/10|*.svc.cluster.local|*.svc.cluster.local -Djdk.http.auth.tunneling.disabledSchemes= -Djdk.http.auth.proxying.disabledSchemes=
|
||||
[INFO] Running com.ankurm.datajpa.ServiceConnectionWithoutGuardFailsToStartTest
|
||||
17:20:10.044 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.ankurm.datajpa.ServiceConnectionWithoutGuardFailsToStartTest]: ServiceConnectionWithoutGuardFailsToStartTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
17:20:10.211 [main] INFO org.testcontainers.images.PullPolicy -- Image pull policy will be performed by: DefaultPullPolicy()
|
||||
17:20:10.213 [main] INFO org.testcontainers.utility.ImageNameSubstitutor -- Image name substitution will be performed by: DefaultImageNameSubstitutor (composite of 'ConfigurationFileImageNameSubstitutor' and 'PrefixingImageNameSubstitutor')
|
||||
17:20:10.253 [main] INFO org.testcontainers.DockerClientFactory -- Testcontainers version: 2.0.5
|
||||
WARNING: A restricted method in java.lang.System has been called
|
||||
WARNING: java.lang.System::load has been called by com.sun.jna.Native in an unnamed module (file:/root/.m2/repository/net/java/dev/jna/jna/5.18.1/jna-5.18.1.jar)
|
||||
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module
|
||||
WARNING: Restricted methods will be blocked in a future release unless native access is enabled
|
||||
|
||||
17:20:10.569 [main] INFO org.testcontainers.dockerclient.DockerMachineClientProviderStrategy -- docker-machine executable was not found on PATH ([/opt/jdk-25/bin, /home/claude/.npm-global/bin, /nix/var/nix/profiles/default/bin, /root/.local/bin, /root/.cargo/bin, /usr/local/go/bin, /opt/node22/bin, /opt/maven/bin, /opt/gradle/bin, /opt/rbenv/bin, /root/.bun/bin, /usr/local/sbin, /usr/local/bin, /usr/sbin, /usr/bin, /sbin, /bin])
|
||||
17:20:10.570 [main] ERROR org.testcontainers.dockerclient.DockerClientProviderStrategy -- Could not find a valid Docker environment. Please check configuration. Attempted configurations were:
|
||||
UnixSocketClientProviderStrategy: failed with exception InvalidConfigurationException (Could not find unix domain socket). Root cause NoSuchFileException (/var/run/docker.sock)
|
||||
DockerDesktopClientProviderStrategy: failed with exception NullPointerException (Cannot invoke "java.nio.file.Path.toString()" because the return value of "org.testcontainers.dockerclient.DockerDesktopClientProviderStrategy.getSocketPath()" is null)As no valid configuration was found, execution cannot continue.
|
||||
See https://java.testcontainers.org/on_failure.html for more details.
|
||||
17:20:10.586 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.ankurm.datajpa.ServiceConnectionWithoutGuardFailsToStartTest]: ServiceConnectionWithoutGuardFailsToStartTest does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
|
||||
17:20:10.617 [main] INFO org.testcontainers.DockerClientFactory -- Testcontainers version: 2.0.5
|
||||
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.877 s <<< FAILURE! -- in com.ankurm.datajpa.ServiceConnectionWithoutGuardFailsToStartTest
|
||||
[ERROR] com.ankurm.datajpa.ServiceConnectionWithoutGuardFailsToStartTest -- Time elapsed: 0.877 s <<< ERROR!
|
||||
org.testcontainers.containers.ContainerFetchException: Can't get Docker image: RemoteDockerImage(imageName=postgres:17, imagePullPolicy=DefaultPullPolicy(), imageNameSubstitutor=org.testcontainers.utility.ImageNameSubstitutor$LogWrappedImageNameSubstitutor@27f1bbe0)
|
||||
at org.testcontainers.containers.GenericContainer.getDockerImageName(GenericContainer.java:1308)
|
||||
at org.springframework.boot.testcontainers.service.connection.ServiceConnectionContextCustomizerFactory.createSource(ServiceConnectionContextCustomizerFactory.java:90)
|
||||
at org.springframework.boot.testcontainers.service.connection.ServiceConnectionContextCustomizerFactory.lambda$collectSources$1(ServiceConnectionContextCustomizerFactory.java:65)
|
||||
at org.springframework.core.annotation.TypeMappedAnnotations$AggregatesSpliterator.tryAdvance(TypeMappedAnnotations.java:591)
|
||||
at org.springframework.core.annotation.TypeMappedAnnotations$AggregatesSpliterator.tryAdvance(TypeMappedAnnotations.java:558)
|
||||
at java.base/java.util.Spliterator.forEachRemaining(Spliterator.java:332)
|
||||
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:803)
|
||||
at org.springframework.boot.testcontainers.service.connection.ServiceConnectionContextCustomizerFactory.lambda$collectSources$0(ServiceConnectionContextCustomizerFactory.java:65)
|
||||
at org.springframework.util.ReflectionUtils.doWithLocalFields(ReflectionUtils.java:691)
|
||||
at org.springframework.boot.testcontainers.service.connection.ServiceConnectionContextCustomizerFactory.collectSources(ServiceConnectionContextCustomizerFactory.java:62)
|
||||
at org.springframework.boot.testcontainers.service.connection.ServiceConnectionContextCustomizerFactory.createContextCustomizer(ServiceConnectionContextCustomizerFactory.java:54)
|
||||
at org.springframework.test.context.support.AbstractTestContextBootstrapper.getContextCustomizers(AbstractTestContextBootstrapper.java:420)
|
||||
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:393)
|
||||
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildDefaultMergedContextConfiguration(AbstractTestContextBootstrapper.java:268)
|
||||
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:226)
|
||||
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildTestContext(AbstractTestContextBootstrapper.java:117)
|
||||
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.buildTestContext(SpringBootTestContextBootstrapper.java:102)
|
||||
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:142)
|
||||
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:126)
|
||||
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:328)
|
||||
at org.springframework.test.context.junit.jupiter.SpringExtension.getTestContextManager(SpringExtension.java:466)
|
||||
at org.springframework.test.context.junit.jupiter.SpringExtension.beforeAll(SpringExtension.java:209)
|
||||
at java.base/java.util.ArrayList.forEach(ArrayList.java:1604)
|
||||
Suppressed: org.testcontainers.containers.ContainerFetchException: Can't get Docker image: RemoteDockerImage(imageName=postgres:17, imagePullPolicy=DefaultPullPolicy(), imageNameSubstitutor=org.testcontainers.utility.ImageNameSubstitutor$LogWrappedImageNameSubstitutor@27f1bbe0)
|
||||
at org.testcontainers.containers.GenericContainer.getDockerImageName(GenericContainer.java:1308)
|
||||
at org.springframework.boot.testcontainers.service.connection.ServiceConnectionContextCustomizerFactory.createSource(ServiceConnectionContextCustomizerFactory.java:90)
|
||||
at org.springframework.boot.testcontainers.service.connection.ServiceConnectionContextCustomizerFactory.lambda$collectSources$1(ServiceConnectionContextCustomizerFactory.java:65)
|
||||
at org.springframework.core.annotation.TypeMappedAnnotations$AggregatesSpliterator.tryAdvance(TypeMappedAnnotations.java:591)
|
||||
at org.springframework.core.annotation.TypeMappedAnnotations$AggregatesSpliterator.tryAdvance(TypeMappedAnnotations.java:558)
|
||||
at java.base/java.util.Spliterator.forEachRemaining(Spliterator.java:332)
|
||||
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:803)
|
||||
at org.springframework.boot.testcontainers.service.connection.ServiceConnectionContextCustomizerFactory.lambda$collectSources$0(ServiceConnectionContextCustomizerFactory.java:65)
|
||||
at org.springframework.util.ReflectionUtils.doWithLocalFields(ReflectionUtils.java:691)
|
||||
at org.springframework.boot.testcontainers.service.connection.ServiceConnectionContextCustomizerFactory.collectSources(ServiceConnectionContextCustomizerFactory.java:62)
|
||||
at org.springframework.boot.testcontainers.service.connection.ServiceConnectionContextCustomizerFactory.createContextCustomizer(ServiceConnectionContextCustomizerFactory.java:54)
|
||||
at org.springframework.test.context.support.AbstractTestContextBootstrapper.getContextCustomizers(AbstractTestContextBootstrapper.java:420)
|
||||
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:393)
|
||||
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildDefaultMergedContextConfiguration(AbstractTestContextBootstrapper.java:268)
|
||||
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:226)
|
||||
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildTestContext(AbstractTestContextBootstrapper.java:117)
|
||||
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.buildTestContext(SpringBootTestContextBootstrapper.java:102)
|
||||
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:142)
|
||||
at org.springframework.test.context.TestContextManager.<init>(TestContextManager.java:126)
|
||||
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:328)
|
||||
at org.springframework.test.context.junit.jupiter.SpringExtension.getTestContextManager(SpringExtension.java:466)
|
||||
at org.springframework.test.context.junit.jupiter.SpringExtension.afterAll(SpringExtension.java:220)
|
||||
... 1 more
|
||||
Caused by: java.lang.IllegalStateException: Previous attempts to find a Docker environment failed. Will not retry. Please see logs and check configuration
|
||||
at org.testcontainers.dockerclient.DockerClientProviderStrategy.getFirstValidStrategy(DockerClientProviderStrategy.java:229)
|
||||
at org.testcontainers.DockerClientFactory.getOrInitializeStrategy(DockerClientFactory.java:154)
|
||||
at org.testcontainers.DockerClientFactory.client(DockerClientFactory.java:196)
|
||||
at org.testcontainers.images.LocalImagesCache.get(LocalImagesCache.java:31)
|
||||
at org.testcontainers.images.AbstractImagePullPolicy.shouldPull(AbstractImagePullPolicy.java:18)
|
||||
at org.testcontainers.images.RemoteDockerImage.resolve(RemoteDockerImage.java:79)
|
||||
at org.testcontainers.images.RemoteDockerImage.resolve(RemoteDockerImage.java:35)
|
||||
at org.testcontainers.utility.LazyFuture.getResolvedValue(LazyFuture.java:20)
|
||||
at org.testcontainers.utility.LazyFuture.get(LazyFuture.java:41)
|
||||
at org.testcontainers.containers.GenericContainer.getDockerImageName(GenericContainer.java:1306)
|
||||
... 22 more
|
||||
Caused by: 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.images.LocalImagesCache.get(LocalImagesCache.java:31)
|
||||
at org.testcontainers.images.AbstractImagePullPolicy.shouldPull(AbstractImagePullPolicy.java:18)
|
||||
at org.testcontainers.images.RemoteDockerImage.resolve(RemoteDockerImage.java:79)
|
||||
at org.testcontainers.images.RemoteDockerImage.resolve(RemoteDockerImage.java:35)
|
||||
at org.testcontainers.utility.LazyFuture.getResolvedValue(LazyFuture.java:20)
|
||||
at org.testcontainers.utility.LazyFuture.get(LazyFuture.java:41)
|
||||
at org.testcontainers.containers.GenericContainer.getDockerImageName(GenericContainer.java:1306)
|
||||
... 22 more
|
||||
|
||||
[INFO]
|
||||
[INFO] Results:
|
||||
[INFO]
|
||||
[ERROR] Errors:
|
||||
[ERROR] ServiceConnectionWithoutGuardFailsToStartTest ? ContainerFetch Can't get Docker image: RemoteDockerImage(imageName=postgres:17, imagePullPolicy=DefaultPullPolicy(), imageNameSubstitutor=org.testcontainers.utility.ImageNameSubstitutor$LogWrappedImageNameSubstitutor@27f1bbe0)
|
||||
[INFO]
|
||||
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0
|
||||
[INFO]
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD FAILURE
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 4.242 s
|
||||
[INFO] Finished at: 2026-10-08T17:20:10+05:30
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.5.6:test (default-test) on project data-jpa-testcontainers:
|
||||
[ERROR]
|
||||
[ERROR] See /home/claude/spring-boot-demo/data-jpa-testcontainers/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
|
||||
@@ -0,0 +1,56 @@
|
||||
Picked up JAVA_TOOL_OPTIONS: -Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts -Djavax.net.ssl.trustStoreType=JKS -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=34689 -Dhttp.nonProxyHosts=localhost|127.0.0.1|::1|127.*|0.*|::|169.254.*|api.anthropic.com|api-staging.anthropic.com|api-pr-preview.anthropic.com|mcp-proxy.anthropic.com|mcp-proxy-staging.anthropic.com|registry.npmjs.org|jsr.io|npm.jsr.io|pypi.org|files.pythonhosted.org|index.crates.io|proxy.golang.org|host.docker.internal|10.*|172.16.*|172.17.*|172.18.*|172.19.*|172.20.*|172.21.*|172.22.*|172.23.*|172.24.*|172.25.*|172.26.*|172.27.*|172.28.*|172.29.*|172.30.*|172.31.*|192.168.*|100.64.0.0/10|*.svc.cluster.local|*.svc.cluster.local -Djdk.http.auth.tunneling.disabledSchemes= -Djdk.http.auth.proxying.disabledSchemes=
|
||||
WARNING: A terminally deprecated method in sun.misc.Unsafe has been called
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase has been called by com.google.inject.internal.aop.HiddenClassDefiner (file:/opt/maven/lib/guice-5.1.0-classes.jar)
|
||||
WARNING: Please consider reporting this to the maintainers of class com.google.inject.internal.aop.HiddenClassDefiner
|
||||
WARNING: sun.misc.Unsafe::staticFieldBase will be removed in a future release
|
||||
[INFO] Scanning for projects...
|
||||
[INFO]
|
||||
[INFO] -----------------< com.ankurm:data-jpa-testcontainers >-----------------
|
||||
[INFO] Building data-jpa-testcontainers 1.0.0
|
||||
[INFO] from pom.xml
|
||||
[INFO] --------------------------------[ jar ]---------------------------------
|
||||
[INFO]
|
||||
[INFO] --- resources:3.5.0:resources (default-resources) @ data-jpa-testcontainers ---
|
||||
[INFO] Copying 0 resource from src/main/resources to target/classes
|
||||
[INFO] Copying 1 resource from src/main/resources to target/classes
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.15.0:compile (default-compile) @ data-jpa-testcontainers ---
|
||||
[INFO] Nothing to compile - all classes are up to date.
|
||||
[INFO]
|
||||
[INFO] --- resources:3.5.0:testResources (default-testResources) @ data-jpa-testcontainers ---
|
||||
[INFO] skip non existing resourceDirectory /home/claude/spring-boot-demo/data-jpa-testcontainers/src/test/resources
|
||||
[INFO]
|
||||
[INFO] --- compiler:3.15.0:testCompile (default-testCompile) @ data-jpa-testcontainers ---
|
||||
[INFO] Nothing to compile - all classes are up to date.
|
||||
[INFO]
|
||||
[INFO] --- surefire:3.5.6:test (default-test) @ data-jpa-testcontainers ---
|
||||
[INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider
|
||||
[INFO]
|
||||
[INFO] -------------------------------------------------------
|
||||
[INFO] T E S T S
|
||||
[INFO] -------------------------------------------------------
|
||||
Picked up JAVA_TOOL_OPTIONS: -Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts -Djavax.net.ssl.trustStoreType=JKS -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=34689 -Dhttp.nonProxyHosts=localhost|127.0.0.1|::1|127.*|0.*|::|169.254.*|api.anthropic.com|api-staging.anthropic.com|api-pr-preview.anthropic.com|mcp-proxy.anthropic.com|mcp-proxy-staging.anthropic.com|registry.npmjs.org|jsr.io|npm.jsr.io|pypi.org|files.pythonhosted.org|index.crates.io|proxy.golang.org|host.docker.internal|10.*|172.16.*|172.17.*|172.18.*|172.19.*|172.20.*|172.21.*|172.22.*|172.23.*|172.24.*|172.25.*|172.26.*|172.27.*|172.28.*|172.29.*|172.30.*|172.31.*|192.168.*|100.64.0.0/10|*.svc.cluster.local|*.svc.cluster.local -Djdk.http.auth.tunneling.disabledSchemes= -Djdk.http.auth.proxying.disabledSchemes=
|
||||
17:20:33.981 [main] INFO org.testcontainers.DockerClientFactory -- Testcontainers version: 2.0.5
|
||||
WARNING: A restricted method in java.lang.System has been called
|
||||
WARNING: java.lang.System::load has been called by com.sun.jna.Native in an unnamed module (file:/root/.m2/repository/net/java/dev/jna/jna/5.18.1/jna-5.18.1.jar)
|
||||
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module
|
||||
WARNING: Restricted methods will be blocked in a future release unless native access is enabled
|
||||
|
||||
17:20:34.343 [main] INFO org.testcontainers.dockerclient.DockerMachineClientProviderStrategy -- docker-machine executable was not found on PATH ([/opt/jdk-25/bin, /home/claude/.npm-global/bin, /nix/var/nix/profiles/default/bin, /root/.local/bin, /root/.cargo/bin, /usr/local/go/bin, /opt/node22/bin, /opt/maven/bin, /opt/gradle/bin, /opt/rbenv/bin, /root/.bun/bin, /usr/local/sbin, /usr/local/bin, /usr/sbin, /usr/bin, /sbin, /bin])
|
||||
17:20:34.345 [main] ERROR org.testcontainers.dockerclient.DockerClientProviderStrategy -- Could not find a valid Docker environment. Please check configuration. Attempted configurations were:
|
||||
UnixSocketClientProviderStrategy: failed with exception InvalidConfigurationException (Could not find unix domain socket). Root cause NoSuchFileException (/var/run/docker.sock)
|
||||
DockerDesktopClientProviderStrategy: failed with exception NullPointerException (Cannot invoke "java.nio.file.Path.toString()" because the return value of "org.testcontainers.dockerclient.DockerDesktopClientProviderStrategy.getSocketPath()" is null)As no valid configuration was found, execution cannot continue.
|
||||
See https://java.testcontainers.org/on_failure.html for more details.
|
||||
[INFO] Running com.ankurm.datajpa.ServiceConnectionSkipsCleanlyTest
|
||||
[WARNING] Tests run: 1, Failures: 0, Errors: 0, Skipped: 1, Time elapsed: 0.059 s -- in com.ankurm.datajpa.ServiceConnectionSkipsCleanlyTest
|
||||
[INFO]
|
||||
[INFO] Results:
|
||||
[INFO]
|
||||
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 1
|
||||
[INFO]
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] BUILD SUCCESS
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
[INFO] Total time: 3.721 s
|
||||
[INFO] Finished at: 2026-10-08T17:20:34+05:30
|
||||
[INFO] ------------------------------------------------------------------------
|
||||
@@ -0,0 +1,146 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>4.1.1</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>com.ankurm</groupId>
|
||||
<artifactId>data-jpa-testcontainers</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<name>data-jpa-testcontainers</name>
|
||||
<description>@DataJpaTest with Testcontainers @ServiceConnection on Spring Boot 4.1.1 / Testcontainers 2.0.5:
|
||||
what the default embedded-database substitution actually does, what @ServiceConnection wires in its
|
||||
place, and what each one looks like when something is missing.</description>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<java.version>25</java.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-core</artifactId>
|
||||
</dependency>
|
||||
<!-- Flyway 12 split its database-specific parsers out of flyway-core (confirmed in the
|
||||
db-migrations-flyway-liquibase module's findings). This repo's migration is run twice in
|
||||
this article: once for real against H2 (no extra dependency needed, H2 support is built
|
||||
into flyway-core) and once, in the real-Postgres test classes, against whatever
|
||||
PostgreSQLContainer provides — which needs this dialect module on the classpath even
|
||||
though that test class cannot start a container in this sandbox. -->
|
||||
<dependency>
|
||||
<groupId>org.flywaydb</groupId>
|
||||
<artifactId>flyway-database-postgresql</artifactId>
|
||||
</dependency>
|
||||
<!-- flyway-core on the classpath is NOT enough to get FlywayAutoConfiguration — that class
|
||||
lives in its own starter, a further instance of Boot 4's per-technology module split
|
||||
(confirmed by comparing against the db-migrations-flyway-liquibase module, which needs the
|
||||
exact same starter). Test scope only: this article's main app never runs Flyway itself, the
|
||||
two test classes that explicitly re-import FlywayAutoConfiguration are what need the class
|
||||
on the classpath at all. -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-flyway</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- @DataJpaTest itself: relocated out of spring-boot-test-autoconfigure in Boot 4.1 into its
|
||||
own module. Confirmed by unzipping this jar: the only class in it is DataJpaTest plus its
|
||||
bootstrapper and type-exclude filter — TestEntityManager and AutoConfigureTestDatabase are
|
||||
NOT in here, they come in transitively from the two dependencies below. -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-data-jpa-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Pulled in transitively by spring-boot-data-jpa-test above (spring-boot-jpa-test for
|
||||
TestEntityManager, spring-boot-jdbc-test for AutoConfigureTestDatabase/TestDatabaseAutoConfiguration)
|
||||
— listed explicitly here only so the module table in the README has something to point at;
|
||||
removing these two lines changes nothing on the classpath. -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-jpa-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-jdbc-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- @ServiceConnection itself — unaffected by the Testcontainers 2.0 package moves below,
|
||||
because it is typed against org.testcontainers.containers.JdbcDatabaseContainer, which did
|
||||
not move. -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-testcontainers</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- Testcontainers 2.0.5. PostgreSQLContainer lives at org.testcontainers.postgresql in this
|
||||
version; org.testcontainers.containers.PostgreSQLContainer still exists as a working
|
||||
@Deprecated subclass, in this SAME jar (confirmed with `unzip -l`: both classes are inside
|
||||
testcontainers-postgresql-2.0.5.jar, not split across two artifacts). -->
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers-postgresql</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- The JUnit 5 extension's artifact was renamed from junit-jupiter to
|
||||
testcontainers-junit-jupiter in 2.0; its package, org.testcontainers.junit.jupiter, did not
|
||||
change. This version also ships a new @EnabledIfDockerAvailable condition, used below. -->
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>testcontainers-junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>data-jpa-testcontainers</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- This class exists to demonstrate a real startup FAILURE on purpose: a container with
|
||||
no guard against a missing Docker daemon. It is run individually with
|
||||
`mvn test -Dtest=ServiceConnectionWithoutGuardFailsToStartTest` to capture that
|
||||
failure for docs/output — excluded here so the module's default `mvn test` build
|
||||
stays green. -->
|
||||
<excludes>
|
||||
<exclude>**/ServiceConnectionWithoutGuardFailsToStartTest.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package com.ankurm.datajpa;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class DataJpaTestcontainersApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(DataJpaTestcontainersApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.ankurm.datajpa;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
|
||||
/**
|
||||
* A deliberately boring entity. The point of this module is not the domain model -- it is what
|
||||
* backs the DataSource underneath it, which is why every field here is the simplest type that
|
||||
* will do the job.
|
||||
*
|
||||
* See the "@DataJpaTest with Testcontainers @ServiceConnection" article on ankurm.com for the
|
||||
* chapter this entity supports.
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "product")
|
||||
public class Product {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
private String sku;
|
||||
|
||||
private String name;
|
||||
|
||||
protected Product() {
|
||||
// JPA
|
||||
}
|
||||
|
||||
public Product(String sku, String name) {
|
||||
this.sku = sku;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getSku() {
|
||||
return sku;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.ankurm.datajpa;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface ProductRepository extends JpaRepository<Product, Long> {
|
||||
|
||||
Optional<Product> findBySku(String sku);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
create table product (
|
||||
id bigint generated by default as identity primary key,
|
||||
sku varchar(64) not null unique,
|
||||
name varchar(255) not null
|
||||
);
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.ankurm.datajpa;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
|
||||
import org.springframework.boot.jpa.test.autoconfigure.TestEntityManager;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* No @ServiceConnection, no Testcontainers import anywhere in this file. Plain @DataJpaTest,
|
||||
* exactly as most tutorials show it.
|
||||
*
|
||||
* What it actually runs against, and why the two tests below pass or fail in isolation from each
|
||||
* other, is the subject of the article's second and third sections.
|
||||
*/
|
||||
@DataJpaTest
|
||||
class DefaultReplacementTest {
|
||||
|
||||
@Autowired
|
||||
private TestEntityManager entityManager;
|
||||
|
||||
@Autowired
|
||||
private ProductRepository productRepository;
|
||||
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
@Test
|
||||
void whateverIsBehindThisDataSourceIsNotPostgres() throws Exception {
|
||||
String productName;
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
productName = connection.getMetaData().getDatabaseProductName();
|
||||
}
|
||||
System.out.println("JDBC reports database product name: " + productName);
|
||||
assertThat(productName).isNotEqualTo("PostgreSQL");
|
||||
}
|
||||
|
||||
@Test
|
||||
void insertedRowIsVisibleWithinThisTest() {
|
||||
entityManager.persistAndFlush(new Product("SKU-1", "Widget"));
|
||||
|
||||
assertThat(productRepository.findBySku("SKU-1")).isPresent();
|
||||
assertThat(productRepository.count()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void previousTestsRowIsGoneInThisOne() {
|
||||
// If @DataJpaTest did not roll each test back, this would see the row the previous test
|
||||
// method inserted. It does not -- each test method gets its own transaction, rolled back
|
||||
// when the method returns, regardless of test execution order.
|
||||
assertThat(productRepository.count()).isZero();
|
||||
assertThat(productRepository.findBySku("SKU-1")).isEmpty();
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package com.ankurm.datajpa;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* This module has a real Flyway migration, {@code V1__create_product.sql}, and flyway-core is a
|
||||
* main-scope dependency. A plain @DataJpaTest never runs it anyway -- not because of the
|
||||
* embedded-database substitution, but because @DataJpaTest's own curated set of auto-configuration
|
||||
* imports simply does not include FlywayAutoConfiguration or LiquibaseAutoConfiguration at all.
|
||||
* Confirmed by reading the actual import manifests Boot ships inside spring-boot-jdbc-test.jar and
|
||||
* spring-boot-data-jpa-test.jar -- neither file mentions Flyway or Liquibase, in any form, under
|
||||
* any replace setting.
|
||||
*
|
||||
* The {@code product} table exists in this test for a completely different reason: Hibernate's own
|
||||
* {@code ddl-auto}, defaulted on because Boot never detects a schema-management tool in this
|
||||
* slice's context. See {@link FlywayRunsWhenExplicitlyImportedTest} for the one-line fix.
|
||||
*/
|
||||
@DataJpaTest
|
||||
class FlywayDoesNotRunUnderPlainDataJpaTestTest {
|
||||
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
@Test
|
||||
void productTableExistsButFlywayNeverRan() throws Exception {
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
try (ResultSet flywayTable = connection.getMetaData()
|
||||
.getTables(null, null, "FLYWAY_SCHEMA_HISTORY", null)) {
|
||||
assertThat(flywayTable.next())
|
||||
.as("flyway_schema_history should not exist -- Flyway never ran")
|
||||
.isFalse();
|
||||
}
|
||||
try (ResultSet productTable = connection.getMetaData()
|
||||
.getTables(null, null, "PRODUCT", null)) {
|
||||
assertThat(productTable.next())
|
||||
.as("product table should exist anyway -- Hibernate's ddl-auto made it")
|
||||
.isTrue();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.ankurm.datajpa;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
|
||||
import org.springframework.boot.flyway.autoconfigure.FlywayAutoConfiguration;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Statement;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* The one-line fix for {@link FlywayDoesNotRunUnderPlainDataJpaTestTest}: pull
|
||||
* FlywayAutoConfiguration into the slice yourself. Once it is in the context, Boot's own
|
||||
* schema-management detection sees it, flips Hibernate's ddl-auto back to {@code none}, and the
|
||||
* real migration runs against the same substituted (here, H2) DataSource.
|
||||
*/
|
||||
@DataJpaTest
|
||||
@ImportAutoConfiguration(FlywayAutoConfiguration.class)
|
||||
class FlywayRunsWhenExplicitlyImportedTest {
|
||||
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
@Test
|
||||
void flywayHistoryTableProvesTheMigrationRanThisTime() throws Exception {
|
||||
// Flyway's own history table always carries a bookkeeping row at installed_rank = -1
|
||||
// ("<< Flyway Schema History table created >>") ahead of the real migration rows --
|
||||
// easy to miss if a query only reads the first row back, which is what an earlier draft
|
||||
// of this test did. The real V1 migration is installed_rank = 1.
|
||||
try (Connection connection = dataSource.getConnection();
|
||||
Statement statement = connection.createStatement();
|
||||
ResultSet rs = statement.executeQuery(
|
||||
"select \"installed_rank\", \"version\", \"description\", \"success\" "
|
||||
+ "from \"flyway_schema_history\" where \"installed_rank\" = 1")) {
|
||||
assertThat(rs.next()).isTrue();
|
||||
String version = rs.getString(2);
|
||||
String description = rs.getString(3);
|
||||
boolean success = rs.getBoolean(4);
|
||||
System.out.println("flyway_schema_history row: version=" + version
|
||||
+ " description=" + description + " success=" + success);
|
||||
assertThat(version).isEqualTo("1");
|
||||
assertThat(description).isEqualTo("create product");
|
||||
assertThat(success).isTrue();
|
||||
assertThat(rs.next()).isFalse();
|
||||
}
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.ankurm.datajpa;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
|
||||
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase.Replace;
|
||||
|
||||
/**
|
||||
* The actually-surprising half of this trap. The intuition is that
|
||||
* {@code @AutoConfigureTestDatabase(replace = Replace.NONE)} turns off the embedded substitution,
|
||||
* so without a real connection configured anywhere this test should fail to start -- that was this
|
||||
* class's original name and premise, until running it against this sandbox's lack of Docker proved
|
||||
* that assumption wrong.
|
||||
*
|
||||
* What {@code replace = Replace.NONE} actually turns off is narrower: only
|
||||
* {@code TestDatabaseAutoConfiguration}'s own bean-post-processing step, the one that replaces an
|
||||
* already-configured production DataSource bean. It does nothing to the ordinary
|
||||
* {@code DataSourceAutoConfiguration}, which auto-provisions an embedded database whenever no
|
||||
* {@code spring.datasource.url} is set and an embedded driver is on the classpath -- completely
|
||||
* independent machinery, with no awareness of the test slice at all. There is no
|
||||
* {@code @ServiceConnection} in this class, and no connection properties anywhere. Replace.NONE is
|
||||
* set. It still silently gets H2, with no warning that anything was substituted, because nothing
|
||||
* Replace.NONE knows about was. The real log line is in
|
||||
* {@code docs/output/00-full-test-run.txt}: a HikariDataSource backed by {@code jdbc:h2:mem:...},
|
||||
* never the "Replacing 'dataSource' DataSource bean with embedded version" line that
|
||||
* {@link DefaultReplacementTest} produces.
|
||||
*/
|
||||
@DataJpaTest
|
||||
@AutoConfigureTestDatabase(replace = Replace.NONE)
|
||||
class NoSubstitutionStillSilentlyUsesH2Test {
|
||||
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
@Test
|
||||
void replaceNoneIsNotTheSameAsARealConnection() throws Exception {
|
||||
String productName;
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
productName = connection.getMetaData().getDatabaseProductName();
|
||||
}
|
||||
System.out.println("JDBC reports database product name: " + productName
|
||||
+ " (even with replace = Replace.NONE and no @ServiceConnection anywhere)");
|
||||
assertThat(productName).isEqualTo("H2");
|
||||
}
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package com.ankurm.datajpa;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
|
||||
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.EnabledIfDockerAvailable;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.postgresql.PostgreSQLContainer;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase.Replace;
|
||||
|
||||
/**
|
||||
* This is the article's intended, finished shape: a real Postgres container wired in as the
|
||||
* DataSource for a @DataJpaTest slice, with the default embedded substitution turned off so the
|
||||
* real connection is actually used.
|
||||
*
|
||||
* {@code @EnabledIfDockerAvailable} is new in Testcontainers 2.0's JUnit 5 extension (confirmed by
|
||||
* `unzip -l` against the 2.0.5 artifact; it does not exist in 1.x). Without it, this class would
|
||||
* try to start the container and fail loudly the moment Docker is not reachable -- see
|
||||
* {@link ServiceConnectionWithoutGuardFailsToStartTest} for exactly what that looks like. With it,
|
||||
* JUnit reports the whole class as cleanly SKIPPED instead, which is what actually happened the one
|
||||
* time this class ran for this article: no Docker daemon in the build sandbox, captured in
|
||||
* {@code docs/output/05-service-connection-skips-cleanly.txt}.
|
||||
*/
|
||||
@DataJpaTest
|
||||
@Testcontainers
|
||||
@AutoConfigureTestDatabase(replace = Replace.NONE)
|
||||
@EnabledIfDockerAvailable
|
||||
class ServiceConnectionSkipsCleanlyTest {
|
||||
|
||||
// Unlike the deprecated org.testcontainers.containers.PostgreSQLContainer<SELF extends ...>,
|
||||
// this new org.testcontainers.postgresql.PostgreSQLContainer is not itself generic (confirmed
|
||||
// with javap) -- it extends JdbcDatabaseContainer<PostgreSQLContainer> directly. Code ported
|
||||
// from the old import that wrote `PostgreSQLContainer<?>` needs that type parameter dropped.
|
||||
@Container
|
||||
@ServiceConnection
|
||||
static PostgreSQLContainer postgres = new PostgreSQLContainer("postgres:17");
|
||||
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
@Test
|
||||
void realDatabaseProductNameIsPostgres() throws Exception {
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
String productName = connection.getMetaData().getDatabaseProductName();
|
||||
System.out.println("JDBC reports database product name: " + productName);
|
||||
assertThat(productName).isEqualTo("PostgreSQL");
|
||||
}
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.ankurm.datajpa;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.data.jpa.test.autoconfigure.DataJpaTest;
|
||||
import org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase;
|
||||
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
|
||||
import org.testcontainers.junit.jupiter.Container;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
import org.testcontainers.postgresql.PostgreSQLContainer;
|
||||
|
||||
import static org.springframework.boot.jdbc.test.autoconfigure.AutoConfigureTestDatabase.Replace;
|
||||
|
||||
/**
|
||||
* Identical to {@link ServiceConnectionSkipsCleanlyTest} except for one missing annotation:
|
||||
* no {@code @EnabledIfDockerAvailable}. NOT part of this module's default `mvn test` run -- see
|
||||
* the surefire exclude in pom.xml. Run it on its own with:
|
||||
*
|
||||
* <pre>mvn test -Dtest=ServiceConnectionWithoutGuardFailsToStartTest</pre>
|
||||
*
|
||||
* Without the guard, the Testcontainers JUnit extension tries to start the container regardless of
|
||||
* what @AutoConfigureTestDatabase says, and that start call is what actually fails. The captured
|
||||
* failure -- including whichever of Spring Boot's own
|
||||
* {@code DockerEnvironmentNotFoundFailureAnalyzer} or the raw Testcontainers exception came through
|
||||
* -- is in {@code docs/output/04-service-connection-without-guard-fails.txt}.
|
||||
*/
|
||||
@DataJpaTest
|
||||
@Testcontainers
|
||||
@AutoConfigureTestDatabase(replace = Replace.NONE)
|
||||
class ServiceConnectionWithoutGuardFailsToStartTest {
|
||||
|
||||
@Container
|
||||
@ServiceConnection
|
||||
static PostgreSQLContainer postgres = new PostgreSQLContainer("postgres:17");
|
||||
|
||||
@Test
|
||||
void neverReached() {
|
||||
// The test body is irrelevant -- container startup fails before this runs.
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user