spring-projects / spring-projects/spring-boot

Using @ServiceConnection on a Container @Bean method does not work with AOT-processed tests

Open
#42,851 9 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

theme: aot type: bug
Dominant language
Java
Stars
81.5k
Forks
42.7k
Avg merge
2d 4h
Merged PRs (30d)
65

Description

Spring Boot application fails to run the nativeTest task with Testcontainers.

I generated a simple project using start.spring.io:

image

On the first run, it fails due to a reflection issue:

...
o.t.d.DockerClientProviderStrategy       : Could not find a valid Docker environment. Please check configuration. Attempted configurations were:
	UnixSocketClientProviderStrategy: failed with exception RuntimeException (org.testcontainers.shaded.com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.github.dockerjava.api.model.RuntimeInfo: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
 at [Source: N/A; line: -1, column: -1] (through reference chain: com.github.dockerjava.api.model.Info["Runtimes"]->java.util.LinkedHashMap["io.containerd.runc.v2"])). Root cause JsonMappingException (Can not construct instance of com.github.dockerjava.api.model.RuntimeInfo: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
 at [Source: N/A; line: -1, column: -1] (through reference chain: com.github.dockerjava.api.model.Info["Runtimes"]->java.util.LinkedHashMap["io.containerd.runc.v2"]))
	DockerDesktopClientProviderStrategy: failed with exception RuntimeException (org.testcontainers.shaded.com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.github.dockerjava.api.model.RuntimeInfo: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
 at [Source: N/A; line: -1, column: -1] (through reference chain: com.github.dockerjava.api.model.Info["Runtimes"]->java.util.LinkedHashMap["io.containerd.runc.v2"])). Root cause JsonMappingException (Can not construct instance of com.github.dockerjava.api.model.RuntimeInfo: no suitable constructor found, can not deserialize from Object value (missing default constructor or creator, or perhaps need to add/enable type information?)
 at [Source: N/A; line: -1, column: -1] (through reference chain: com.github.dockerjava.api.model.Info["Runtimes"]->java.util.LinkedHashMap["io.containerd.runc.v2"]))As no valid configuration was found, execution cannot continue.
See https://java.testcontainers.org/on_failure.html for more details.
...

I solved this issue by adding a reflect.json file in src/test/resources/META-INF/native-image/ with the following content::

[
  {
    "name":"com.github.dockerjava.api.model.RuntimeInfo",
    "allDeclaredFields":true,
    "queryAllDeclaredMethods":true,
    "queryAllDeclaredConstructors":true,
    "methods":[{"name":"<init>","parameterTypes":[] }, {"name":"setPath","parameterTypes":["java.lang.String"] }]
  },
  {
    "name":"com.github.dockerjava.api.model.Info",
    "allDeclaredFields":true,
    "queryAllDeclaredMethods":true,
    "queryAllDeclaredConstructors":true,
    "methods":[{"name":"<init>","parameterTypes":[] }]
  }
]

However, I'm confused because Testcontainers seems to be supported by GraalVM as indicated here: https://www.graalvm.org/native-image/libraries-and-frameworks/

With that configuration, I encountered another issue that I'm unsure how to resolve:

> Task :nativeTest
JUnit Platform on Native Image - report
----------------------------------------

12:37:58.794 [main] INFO org.springframework.test.context.support.AnnotationConfigContextLoaderUtils -- Could not detect default configuration classes for test class [com.example.demo.DemoApplicationTests]: DemoApplicationTests does not declare any static, non-private, non-final, nested classes annotated with @Configuration.
12:37:58.797 [main] INFO org.springframework.boot.test.context.SpringBootTestContextBootstrapper -- Found @SpringBootConfiguration com.example.demo.DemoApplication for test class com.example.demo.DemoApplicationTests

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.4)

2024-10-23T12:37:58.813+02:00  INFO 9667 --- [demo] [           main] com.example.demo.DemoApplicationTests    : Starting AOT-processed DemoApplicationTests using Java 21.0.4 with PID 9667 (started by rowickim in /private/tmp/demo)
2024-10-23T12:37:58.813+02:00  INFO 9667 --- [demo] [           main] com.example.demo.DemoApplicationTests    : No active profile set, falling back to 1 default profile: "default"
2024-10-23T12:37:58.816+02:00  INFO 9667 --- [demo] [           main] org.testcontainers.images.PullPolicy     : Image pull policy will be performed by: DefaultPullPolicy()
2024-10-23T12:37:58.816+02:00  INFO 9667 --- [demo] [           main] o.t.utility.ImageNameSubstitutor         : Image name substitution will be performed by: DefaultImageNameSubstitutor (composite of 'ConfigurationFileImageNameSubstitutor' and 'PrefixingImageNameSubstitutor')
2024-10-23T12:37:58.825+02:00  INFO 9667 --- [demo] [           main] o.t.d.DockerClientProviderStrategy       : Loaded org.testcontainers.dockerclient.UnixSocketClientProviderStrategy from ~/.testcontainers.properties, will try it first
2024-10-23T12:37:58.846+02:00  INFO 9667 --- [demo] [           main] o.t.d.DockerClientProviderStrategy       : Found Docker environment with local Unix socket (unix:///var/run/docker.sock)
2024-10-23T12:37:58.847+02:00  INFO 9667 --- [demo] [           main] org.testcontainers.DockerClientFactory   : Docker host IP address is localhost
2024-10-23T12:37:58.852+02:00  INFO 9667 --- [demo] [           main] org.testcontainers.DockerClientFactory   : Connected to docker:
  Server Version: 27.2.0
  API Version: 1.47
  Operating System: Docker Desktop
  Total Memory: 7838 MB
2024-10-23T12:37:58.852+02:00  WARN 9667 --- [demo] [           main] o.testcontainers.utility.ResourceReaper  :
********************************************************************************
Ryuk has been disabled. This can cause unexpected behavior in your environment.
********************************************************************************
2024-10-23T12:37:58.852+02:00  INFO 9667 --- [demo] [           main] org.testcontainers.DockerClientFactory   : Checking the system...
2024-10-23T12:37:58.852+02:00  INFO 9667 --- [demo] [           main] org.testcontainers.DockerClientFactory   : ✔︎ Docker server version should be at least 1.6.0
2024-10-23T12:37:58.859+02:00  INFO 9667 --- [demo] [           main] tc.mongo:latest                          : Creating container for image: mongo:latest
2024-10-23T12:37:59.004+02:00  INFO 9667 --- [demo] [           main] tc.mongo:latest                          : Container mongo:latest is starting: cb2dd662645f26c2cb8ffdf5dd73d4332628b60c2a5e6487fcfe101c4480456e
2024-10-23T12:37:59.877+02:00  INFO 9667 --- [demo] [           main] tc.mongo:latest                          : Container mongo:latest started in PT1.018256S
2024-10-23T12:38:00.339+02:00  WARN 9667 --- [demo] [           main] o.s.c.support.GenericApplicationContext  : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'standardMongoSettingsCustomizer': Unsatisfied dependency expressed through method 'standardMongoSettingsCustomizer' parameter 1: No qualifying bean of type 'org.springframework.boot.autoconfigure.mongo.MongoConnectionDetails' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

It looks like the task aotTestClasses doesn't add any MongoConnectionDetails to the application context.

Here is the zipped project for reference: demo.zip

Environment Details

I'm using the following version of GraalVM:

❯ java -version
java version "21.0.4" 2024-07-16 LTS
Java(TM) SE Runtime Environment Oracle GraalVM 21.0.4+8.1 (build 21.0.4+8-LTS-jvmci-23.1-b41)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 21.0.4+8.1 (build 21.0.4+8-LTS-jvmci-23.1-b41, mixed mode, sharing)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the reported nativeTest failure from the attached generated project and inspect what aotTestClasses contributes to the AOT-processed test context. Compare the failing @ServiceConnection container setup with the missing MongoConnectionDetails bean; done means the nativeTest task starts the Mongo container, creates the connection details, and completes successfully.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, java, mongodb, spring-boot
Domain
backend, build-system, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.