I have put together a minimal example that demonstrates how the use of the @ServiceConnection annotation with Spring Boot 3.1.2 and testcontainers breaks native tests.
When running ./gradlew nativeTest, I get the following error:
org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsNotFoundException: No ConnectionDetails found for source '@ServiceConnection source for MongoDbTestBase.database'
To reproduce the problem, run the following commands:
git clone https://github.com/magnus-larsson/sb312-tc-native-bug.git
cd sb312-tc-native-bug
./gradlew nativeTest
Note: Running
./gradlew testworks as expected.
To workaround the problem, do the following:
- Edit
src/test/java/se/magnus/microservices/core/product/MongoDbTestBase.java - Comment out
@ServiceConnection - Remove comments from the method
setPropertiesthat is annotated with@DynamicPropertySource
With these changes in place, both ./gradlew test and ./gradlew nativeTest works as expected.
Comment From: philwebb
Could you please provide a link to the reproducer?
EDIT: Never mind, @wilkinsona just pointed out the git clone...
Comment From: magnus-larsson
The git repo is available at https://github.com/magnus-larsson/sb312-tc-native-bug.
I noted that the issue is marked with status:waiting-for-feedback, is there any more info required from my side?
Comment From: mhalbritter
Hey @magnus-larsson, sorry for taking my time to look at this issue. Thanks for the report and for the reproducer. You don't need to provide more information, we have everything we need.
I can reproduce this. The 3 registrations are returned in org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories#getConnectionDetails:
List<Registration<S, ?>> registrations = getRegistrations(source, required);
but this call always returns null in a native image:
ConnectionDetails connectionDetails = registration.factory().getConnectionDetails(source);
On the JVM this works for the MongoContainerConnectionDetailsFactory.
Comment From: mhalbritter
The MongoContainerConnectionDetailsFactory checks for the presence of the com.mongodb.ConnectionString class, which is not registered for reflection in a native image, and this check returns false.
Comment From: mhalbritter
Until we fix this, you can use this workaround:
@ImportRuntimeHints(MyHints.class)
public abstract class MongoDbTestBase {
// ... snip ...
static class MyHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection().registerType(TypeReference.of("com.mongodb.ConnectionString"));
}
}
}
Comment From: magnus-larsson
It looks like Spring Boot 3.1.4 solved this issue.
I don't need the workaround described above to make nativeTests work after upgrading to Spring Boot 3.1.4.
Comment From: wilkinsona
Thanks for the update, @magnus-larsson.
I'm surprised that it works for you with Spring boot 3.1.4. As far as I can tell, nothing is generating the reflection hint for com.mongodb.ConnectionString so it shouldn't be available through reflection in a native image.
Updating sb312-tc-native-bug to Spring Boot 3.1.4 and running ./gradlew nativeTest seems to confirm this. All 12 tests fail with exceptions similar to this:
Caused by: org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsNotFoundException: No ConnectionDetails found for source '@ServiceConnection source for MongoDbTestBase.database'
at org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactories.getConnectionDetails(ConnectionDetailsFactories.java:89)
at org.springframework.boot.testcontainers.service.connection.ConnectionDetailsRegistrar.registerBeanDefinitions(ConnectionDetailsRegistrar.java:71)
at org.springframework.boot.testcontainers.service.connection.ConnectionDetailsRegistrar.lambda$registerBeanDefinitions$0(ConnectionDetailsRegistrar.java:66)
at java.base@17.0.8/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.springframework.boot.testcontainers.service.connection.ConnectionDetailsRegistrar.registerBeanDefinitions(ConnectionDetailsRegistrar.java:66)
at org.springframework.boot.testcontainers.service.connection.ServiceConnectionContextCustomizer.customizeContext(ServiceConnectionContextCustomizer.java:66)
at org.springframework.boot.test.context.SpringBootContextLoader$ContextCustomizerAdapter.initialize(SpringBootContextLoader.java:435)
at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:610)
at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:390)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:314)
at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:137)
at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58)
at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46)
at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1409)
at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:545)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:137)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContextForAotRuntime(SpringBootContextLoader.java:119)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInAotMode(DefaultCacheAwareContextLoaderDelegate.java:217)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
... 68 common frames omitted
I think we still need to contribute a hint here.
Comment From: wilkinsona
Looking at the code, I think the factories for Neo4j, Redis, and Zipkin as well as the various different R2DBC factories are also affected.
Comment From: magnus-larsson
@wilkinsona: You are right; I tested it on another project. Native tests still fail in the sb312-tc-native-bug project when using Spring Boot 3.1.4!
Comment From: wilkinsona
I think this has caused #38392.
Comment From: philwebb
The fix for #38392 was merged in f68df82b30a9d73b629c62c66e22956c64eaa73e