diff --git a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc index 6cae636a789..aeab8732484 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/testing/testcontainers.adoc @@ -150,7 +150,7 @@ The following service connection factories are provided in the `spring-boot-test | Containers of type javadoc:{url-testcontainers-jdbc-javadoc}/org.testcontainers.containers.JdbcDatabaseContainer[] | javadoc:org.springframework.boot.autoconfigure.mongo.MongoConnectionDetails[] -| Containers of type javadoc:{url-testcontainers-mongodb-javadoc}/org.testcontainers.containers.MongoDBContainer[] +| Containers of type javadoc:{url-testcontainers-mongodb-javadoc}/org.testcontainers.containers.MongoDBContainer[] or javadoc:{url-testcontainers-mongodb-javadoc}/org.testcontainers.mongodb.MongoDBAtlasLocalContainer[] | javadoc:org.springframework.boot.neo4j.autoconfigure.Neo4jConnectionDetails[] | Containers of type javadoc:{url-testcontainers-neo4j-javadoc}/org.testcontainers.containers.Neo4jContainer[] diff --git a/spring-boot-project/spring-boot-mongodb/build.gradle b/spring-boot-project/spring-boot-mongodb/build.gradle index b46001bc317..1c9af58f379 100644 --- a/spring-boot-project/spring-boot-mongodb/build.gradle +++ b/spring-boot-project/spring-boot-mongodb/build.gradle @@ -42,6 +42,8 @@ dependencies { dockerTestImplementation(project(":spring-boot-project:spring-boot-test")) dockerTestImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support-docker")) dockerTestImplementation(testFixtures(project(":spring-boot-project:spring-boot-docker-compose"))) + dockerTestImplementation("org.testcontainers:junit-jupiter") + dockerTestImplementation("org.mongodb:mongodb-driver-sync") testImplementation(project(":spring-boot-project:spring-boot-test")) testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support")) diff --git a/spring-boot-project/spring-boot-mongodb/src/dockerTest/java/org/springframework/boot/mongodb/testcontainers/MongoDbAtlasLocalContainerConnectionDetailsFactoryIntegrationTests.java b/spring-boot-project/spring-boot-mongodb/src/dockerTest/java/org/springframework/boot/mongodb/testcontainers/MongoDbAtlasLocalContainerConnectionDetailsFactoryIntegrationTests.java new file mode 100644 index 00000000000..7f96cfab8ea --- /dev/null +++ b/spring-boot-project/spring-boot-mongodb/src/dockerTest/java/org/springframework/boot/mongodb/testcontainers/MongoDbAtlasLocalContainerConnectionDetailsFactoryIntegrationTests.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.mongodb.testcontainers; + +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import org.junit.jupiter.api.Test; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import org.testcontainers.mongodb.MongoDBAtlasLocalContainer; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; +import org.springframework.boot.testsupport.container.TestImage; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link MongoDbAtlasLocalContainerConnectionDetailsFactory}. + * + * @author Andy Wilkinson + */ +@SpringJUnitConfig +@Testcontainers(disabledWithoutDocker = true) +class MongoDbAtlasLocalContainerConnectionDetailsFactoryIntegrationTests { + + @Container + @ServiceConnection + static final MongoDBAtlasLocalContainer mongoDb = TestImage.container(MongoDBAtlasLocalContainer.class); + + @Autowired(required = false) + private MongoConnectionDetails connectionDetails; + + @Test + void connectionCanBeMadeToContainer() { + assertThat(this.connectionDetails).isNotNull(); + MongoClient client = MongoClients.create(this.connectionDetails.getConnectionString()); + assertThat(client.listDatabaseNames()).containsExactly("admin", "config", "local"); + } + +} diff --git a/spring-boot-project/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/MongoContainerConnectionDetailsFactory.java b/spring-boot-project/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/AbstractMongoContainerConnectionDetailsFactory.java similarity index 54% rename from spring-boot-project/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/MongoContainerConnectionDetailsFactory.java rename to spring-boot-project/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/AbstractMongoContainerConnectionDetailsFactory.java index 828f28da81c..b5883a06c54 100644 --- a/spring-boot-project/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/MongoContainerConnectionDetailsFactory.java +++ b/spring-boot-project/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/AbstractMongoContainerConnectionDetailsFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-present the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,10 @@ package org.springframework.boot.mongodb.testcontainers; +import java.util.function.Function; + import com.mongodb.ConnectionString; -import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.containers.GenericContainer; import org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails; import org.springframework.boot.ssl.SslBundle; @@ -26,38 +28,48 @@ import org.springframework.boot.testcontainers.service.connection.ContainerConne import org.springframework.boot.testcontainers.service.connection.ServiceConnection; /** - * {@link ContainerConnectionDetailsFactory} to create {@link MongoConnectionDetails} from - * a {@link ServiceConnection @ServiceConnection}-annotated {@link MongoDBContainer}. + * Abstract {@link ContainerConnectionDetailsFactory} to create + * {@link MongoConnectionDetails} from a + * {@link ServiceConnection @ServiceConnection}-annotated MongoDB container. * + * @param type of MongoDB container supported by the factory * @author Moritz Halbritter * @author Andy Wilkinson * @author Phillip Webb + * @author Wouter Blancquaert */ -class MongoContainerConnectionDetailsFactory - extends ContainerConnectionDetailsFactory { +abstract class AbstractMongoContainerConnectionDetailsFactory> + extends ContainerConnectionDetailsFactory { + + private final Function connectionStringFunction; - MongoContainerConnectionDetailsFactory() { + AbstractMongoContainerConnectionDetailsFactory(Function connectionStringFunction) { super(ANY_CONNECTION_NAME, "com.mongodb.ConnectionString"); + this.connectionStringFunction = connectionStringFunction; } @Override - protected MongoConnectionDetails getContainerConnectionDetails(ContainerConnectionSource source) { - return new MongoContainerConnectionDetails(source); + protected MongoConnectionDetails getContainerConnectionDetails(ContainerConnectionSource source) { + return new MongoContainerConnectionDetails<>(source, this.connectionStringFunction); } /** * {@link MongoConnectionDetails} backed by a {@link ContainerConnectionSource}. */ - private static final class MongoContainerConnectionDetails extends ContainerConnectionDetails - implements MongoConnectionDetails { + private static final class MongoContainerConnectionDetails> + extends ContainerConnectionDetails implements MongoConnectionDetails { + + private final Function connectionStringFunction; - private MongoContainerConnectionDetails(ContainerConnectionSource source) { + private MongoContainerConnectionDetails(ContainerConnectionSource source, + Function connectionStringFunction) { super(source); + this.connectionStringFunction = connectionStringFunction; } @Override public ConnectionString getConnectionString() { - return new ConnectionString(getContainer().getReplicaSetUrl()); + return new ConnectionString(this.connectionStringFunction.apply(getContainer())); } @Override diff --git a/spring-boot-project/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/MongoDbAtlasLocalContainerConnectionDetailsFactory.java b/spring-boot-project/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/MongoDbAtlasLocalContainerConnectionDetailsFactory.java new file mode 100644 index 00000000000..b2b965b243a --- /dev/null +++ b/spring-boot-project/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/MongoDbAtlasLocalContainerConnectionDetailsFactory.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.mongodb.testcontainers; + +import org.testcontainers.mongodb.MongoDBAtlasLocalContainer; + +import org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails; +import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; + +/** + * {@link ContainerConnectionDetailsFactory} to create {@link MongoConnectionDetails} from + * a {@link ServiceConnection @ServiceConnection}-annotated + * {@link MongoDBAtlasLocalContainer}. + * + * @author Wouter Blancquaert + */ +class MongoDbAtlasLocalContainerConnectionDetailsFactory + extends AbstractMongoContainerConnectionDetailsFactory { + + MongoDbAtlasLocalContainerConnectionDetailsFactory() { + super(MongoDBAtlasLocalContainer::getDatabaseConnectionString); + } + +} diff --git a/spring-boot-project/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/MongoDbContainerConnectionDetailsFactory.java b/spring-boot-project/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/MongoDbContainerConnectionDetailsFactory.java new file mode 100644 index 00000000000..958676e2d60 --- /dev/null +++ b/spring-boot-project/spring-boot-mongodb/src/main/java/org/springframework/boot/mongodb/testcontainers/MongoDbContainerConnectionDetailsFactory.java @@ -0,0 +1,40 @@ +/* + * Copyright 2012-present the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.mongodb.testcontainers; + +import org.testcontainers.containers.MongoDBContainer; + +import org.springframework.boot.mongodb.autoconfigure.MongoConnectionDetails; +import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory; +import org.springframework.boot.testcontainers.service.connection.ServiceConnection; + +/** + * {@link ContainerConnectionDetailsFactory} to create {@link MongoConnectionDetails} from + * a {@link ServiceConnection @ServiceConnection}-annotated {@link MongoDBContainer}. + * + * @author Moritz Halbritter + * @author Andy Wilkinson + * @author Phillip Webb + */ +class MongoDbContainerConnectionDetailsFactory + extends AbstractMongoContainerConnectionDetailsFactory { + + MongoDbContainerConnectionDetailsFactory() { + super(MongoDBContainer::getReplicaSetUrl); + } + +} diff --git a/spring-boot-project/spring-boot-mongodb/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-mongodb/src/main/resources/META-INF/spring.factories index a4e490f7958..189e62c27c3 100644 --- a/spring-boot-project/spring-boot-mongodb/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-mongodb/src/main/resources/META-INF/spring.factories @@ -1,4 +1,5 @@ # Connection Details Factories org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\ org.springframework.boot.mongodb.docker.compose.MongoDockerComposeConnectionDetailsFactory,\ -org.springframework.boot.mongodb.testcontainers.MongoContainerConnectionDetailsFactory +org.springframework.boot.mongodb.testcontainers.MongoDbAtlasLocalContainerConnectionDetailsFactory,\ +org.springframework.boot.mongodb.testcontainers.MongoDbContainerConnectionDetailsFactory diff --git a/spring-boot-project/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/testcontainers/MongoContainerConnectionDetailsFactoryTests.java b/spring-boot-project/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/testcontainers/AbstractMongoContainerConnectionDetailsFactoryTests.java similarity index 91% rename from spring-boot-project/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/testcontainers/MongoContainerConnectionDetailsFactoryTests.java rename to spring-boot-project/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/testcontainers/AbstractMongoContainerConnectionDetailsFactoryTests.java index ed161ac5940..9fb2438683f 100644 --- a/spring-boot-project/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/testcontainers/MongoContainerConnectionDetailsFactoryTests.java +++ b/spring-boot-project/spring-boot-mongodb/src/test/java/org/springframework/boot/mongodb/testcontainers/AbstractMongoContainerConnectionDetailsFactoryTests.java @@ -26,11 +26,11 @@ import org.springframework.boot.testcontainers.service.connection.ContainerConne import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for {@link MongoContainerConnectionDetailsFactory}. + * Tests for {@link AbstractMongoContainerConnectionDetailsFactory}. * * @author Moritz Halbritter */ -class MongoContainerConnectionDetailsFactoryTests { +class AbstractMongoContainerConnectionDetailsFactoryTests { @Test void shouldRegisterHints() { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/src/main/java/org/springframework/boot/testsupport/container/TestImage.java b/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/src/main/java/org/springframework/boot/testsupport/container/TestImage.java index cc670d59329..dc10652fc7a 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/src/main/java/org/springframework/boot/testsupport/container/TestImage.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/src/main/java/org/springframework/boot/testsupport/container/TestImage.java @@ -40,6 +40,7 @@ import org.testcontainers.elasticsearch.ElasticsearchContainer; import org.testcontainers.grafana.LgtmStackContainer; import org.testcontainers.kafka.ConfluentKafkaContainer; import org.testcontainers.ldap.LLdapContainer; +import org.testcontainers.mongodb.MongoDBAtlasLocalContainer; import org.testcontainers.redpanda.RedpandaContainer; import org.testcontainers.utility.DockerImageName; @@ -157,6 +158,13 @@ public enum TestImage { (container) -> ((MongoDBContainer) container).withStartupAttempts(5) .withStartupTimeout(Duration.ofMinutes(5))), + /** + * A container image suitable for testing MongoDB Atlas. + */ + MONGODB_ATLAS("mongodb/mongodb-atlas-local", "8.0.4", () -> MongoDBAtlasLocalContainer.class, + (container) -> ((MongoDBAtlasLocalContainer) container).withStartupAttempts(5) + .withStartupTimeout(Duration.ofMinutes(5))), + /** * A container image suitable for testing MySQL. */