When using Testcontainers, access to the Mongo instance in the container is available via a URL which is applied using a @DynamicPropertySource:
@DynamicPropertySource
static void applicationProperties(DynamicPropertyRegistry registry) {
registry.add("spring.data.mongodb.uri", mongo::getReplicaSetUrl);
}
This works well when main code also uses spring.data.mongodb.uri to connect to Mongo. It does not work when spring.data.mongodb.host etc have been used instead:
Caused by: java.lang.IllegalStateException: Invalid mongo configuration, either uri or host/port/credentials/replicaSet must be specified
at org.springframework.util.Assert.state(Assert.java:76) ~[spring-core-5.3.16.jar:5.3.16]
at org.springframework.boot.autoconfigure.mongo.MongoPropertiesClientSettingsBuilderCustomizer.validateConfiguration(MongoPropertiesClientSettingsBuilderCustomizer.java:61) ~[main/:na]
at org.springframework.boot.autoconfigure.mongo.MongoPropertiesClientSettingsBuilderCustomizer.customize(MongoPropertiesClientSettingsBuilderCustomizer.java:52) ~[main/:na]
at org.springframework.boot.autoconfigure.mongo.MongoClientFactorySupport.customize(MongoClientFactorySupport.java:55) ~[main/:na]
at org.springframework.boot.autoconfigure.mongo.MongoClientFactorySupport.createMongoClient(MongoClientFactorySupport.java:49) ~[main/:na]
at org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration.mongo(MongoAutoConfiguration.java:56) ~[main/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_252]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_252]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_252]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_252]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.3.16.jar:5.3.16]
... 196 common frames omitted
This can be worked around to some extent by overriding properties:
@DynamicPropertySource
static void applicationProperties(DynamicPropertyRegistry registry) {
registry.add("spring.data.mongodb.host", () -> URI.create(mongo.getReplicaSetUrl()).getHost());
registry.add("spring.data.mongodb.port", () -> URI.create(mongo.getReplicaSetUrl()).getPort());
registry.add("spring.data.mongodb.replica-set-name", () -> "docker-rs");
}
However, it does not work when the main configuration has set the username and password as an override cannot remove the configuration.
We need a more robust way of overriding the main configuration from a test. This will also be of benefit to Embedded Mongo where we currently only set local.mongo.port. It's possible with more advanced embedded Mongo configuration that other settings related to Mongo connectivity must also be set and we do not do so at the moment.
Comment From: chantyapk
@DynamicPropertySource
static void applicationProperties(DynamicPropertyRegistry registry) {
registry.add("spring.data.mongodb.host", () -> URI.create(mongo.getReplicaSetUrl()).getHost());
registry.add("spring.data.mongodb.port", () -> URI.create(mongo.getReplicaSetUrl()).getPort());
registry.add("spring.data.mongodb.replica-set-name", () -> "docker-rs");
}
need to add some @methods to avoid some nullpoint exceptions
Comment From: wilkinsona
There's quite a bit of precedent for a URI-like property taking precedence:
spring.rabbitmq.addressestake precedence over properties that configure a component of an address.spring.redis.urloverrides individual host, port, and password propertiesspring.integration.rsocket.client.urioverrides the separate host and port properties.spring.r2dbc.urltakes precedence over separate properties
This change for Mongo will make things more consistent with these other properties.