From 7ef121e0fd2f5098eef52df33ded79b9e35a3ea2 Mon Sep 17 00:00:00 2001 From: "Greg L. Turnquist" Date: Fri, 13 May 2022 16:34:25 -0500 Subject: [PATCH] Replace Flapdoodle with Testcontainers for MongoDB support. For more details on this usage of Testcontainers, see https://bsideup.github.io/posts/local_development_with_testcontainers/ Related issues: https://github.com/spring-projects/spring-boot/issues/30863 --- ...ession-sample-boot-mongodb-reactive.gradle | 2 +- ...SpringSessionMongoReactiveApplication.java | 40 +++++++++++++++- .../src/main/resources/application.properties | 2 + .../src/main/resources/application.yml | 8 ---- .../mongodb/examples/AttributeTests.java | 7 +-- ...ion-sample-boot-mongodb-traditional.gradle | 3 +- .../examples/EmbeddedMongoPortLogger.java | 46 ------------------- .../SpringSessionMongoTraditionalBoot.java | 39 +++++++++++++++- .../src/main/resources/application.properties | 5 +- .../session/mongodb/examples/BootTests.java | 2 + 10 files changed, 89 insertions(+), 65 deletions(-) create mode 100644 spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/main/resources/application.properties delete mode 100644 spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/main/resources/application.yml delete mode 100644 spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/main/java/org/springframework/session/mongodb/examples/EmbeddedMongoPortLogger.java diff --git a/spring-session-samples/spring-session-sample-boot-mongodb-reactive/spring-session-sample-boot-mongodb-reactive.gradle b/spring-session-samples/spring-session-sample-boot-mongodb-reactive/spring-session-sample-boot-mongodb-reactive.gradle index f4bb6fe6..bdfdaf77 100644 --- a/spring-session-samples/spring-session-sample-boot-mongodb-reactive/spring-session-sample-boot-mongodb-reactive.gradle +++ b/spring-session-samples/spring-session-sample-boot-mongodb-reactive/spring-session-sample-boot-mongodb-reactive.gradle @@ -5,7 +5,7 @@ dependencies { implementation "org.springframework.boot:spring-boot-starter-webflux" implementation "org.springframework.boot:spring-boot-starter-thymeleaf" implementation "org.springframework.boot:spring-boot-starter-data-mongodb-reactive" - implementation "de.flapdoodle.embed:de.flapdoodle.embed.mongo" + implementation "org.testcontainers:mongodb" testImplementation "org.springframework.boot:spring-boot-starter-test" testImplementation "org.seleniumhq.selenium:htmlunit-driver" diff --git a/spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/main/java/org/springframework/session/mongodb/examples/SpringSessionMongoReactiveApplication.java b/spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/main/java/org/springframework/session/mongodb/examples/SpringSessionMongoReactiveApplication.java index b42676c6..9b25c27f 100644 --- a/spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/main/java/org/springframework/session/mongodb/examples/SpringSessionMongoReactiveApplication.java +++ b/spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/main/java/org/springframework/session/mongodb/examples/SpringSessionMongoReactiveApplication.java @@ -18,7 +18,16 @@ package org.springframework.session.mongodb.examples; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; import org.springframework.session.data.mongo.config.annotation.web.reactive.EnableMongoWebSession; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.utility.DockerImageName; + +import java.util.HashMap; +import java.util.Map; /** * Pure Spring-based application (using Spring Boot for dependency management), hence no @@ -31,8 +40,35 @@ import org.springframework.session.data.mongo.config.annotation.web.reactive.Ena @EnableMongoWebSession public class SpringSessionMongoReactiveApplication { - public static void main(String[] args) { - SpringApplication.run(SpringSessionMongoReactiveApplication.class); + /** + * Use Testcontainers to managed MongoDB through Docker. + *

+ * @see https://bsideup.github.io/posts/local_development_with_testcontainers/ + */ + static class Initializer implements ApplicationContextInitializer { + + static MongoDBContainer mongo = new MongoDBContainer(DockerImageName.parse("mongo:5.0")); + + public static Map getProperties() { + mongo.start(); + + HashMap properties = new HashMap<>(); + properties.put("spring.data.mongodb.host", mongo.getHost()); + properties.put("spring.data.mongodb.port", mongo.getFirstMappedPort() + ""); + return properties; + } + + @Override + public void initialize(ConfigurableApplicationContext context) { + ConfigurableEnvironment env = context.getEnvironment(); + env.getPropertySources().addFirst(new MapPropertySource("testcontainers", (Map) getProperties())); + } } + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(SpringSessionMongoReactiveApplication.class); + application.addInitializers(new Initializer()); + application.run(args); + } } diff --git a/spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/main/resources/application.properties b/spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/main/resources/application.properties new file mode 100644 index 00000000..5fcf72eb --- /dev/null +++ b/spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/main/resources/application.properties @@ -0,0 +1,2 @@ +logging.level.org.springframework.data.mongodb=DEBUG +logging.level.org.springframework.session=DEBUG diff --git a/spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/main/resources/application.yml b/spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/main/resources/application.yml deleted file mode 100644 index c412cf95..00000000 --- a/spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/main/resources/application.yml +++ /dev/null @@ -1,8 +0,0 @@ -logging: - level: - org.springframework.data.mongodb: DEBUG - org.springframework.session: DEBUG -spring: - mongodb: - embedded: - version: 3.4.3 diff --git a/spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/test/java/org/springframework/session/mongodb/examples/AttributeTests.java b/spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/test/java/org/springframework/session/mongodb/examples/AttributeTests.java index ccc38baa..11bf6bec 100644 --- a/spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/test/java/org/springframework/session/mongodb/examples/AttributeTests.java +++ b/spring-session-samples/spring-session-sample-boot-mongodb-reactive/src/test/java/org/springframework/session/mongodb/examples/AttributeTests.java @@ -16,21 +16,21 @@ package org.springframework.session.mongodb.examples; -import java.util.List; - import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.openqa.selenium.WebDriver; import org.openqa.selenium.htmlunit.HtmlUnitDriver; - import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.session.mongodb.examples.pages.HomePage; import org.springframework.session.mongodb.examples.pages.HomePage.Attribute; +import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; +import java.util.List; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -39,6 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat; */ @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ContextConfiguration(initializers = SpringSessionMongoReactiveApplication.Initializer.class) public class AttributeTests { @LocalServerPort diff --git a/spring-session-samples/spring-session-sample-boot-mongodb-traditional/spring-session-sample-boot-mongodb-traditional.gradle b/spring-session-samples/spring-session-sample-boot-mongodb-traditional/spring-session-sample-boot-mongodb-traditional.gradle index 79e19b78..a04410e8 100644 --- a/spring-session-samples/spring-session-sample-boot-mongodb-traditional/spring-session-sample-boot-mongodb-traditional.gradle +++ b/spring-session-samples/spring-session-sample-boot-mongodb-traditional/spring-session-sample-boot-mongodb-traditional.gradle @@ -8,7 +8,8 @@ dependencies { implementation "org.thymeleaf.extras:thymeleaf-extras-springsecurity5" implementation "org.springframework.boot:spring-boot-starter-data-mongodb" implementation "org.springframework.boot:spring-boot-starter-security" - implementation "de.flapdoodle.embed:de.flapdoodle.embed.mongo" + implementation "org.testcontainers:mongodb" + testImplementation "org.springframework.boot:spring-boot-starter-test" testImplementation "org.seleniumhq.selenium:htmlunit-driver" diff --git a/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/main/java/org/springframework/session/mongodb/examples/EmbeddedMongoPortLogger.java b/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/main/java/org/springframework/session/mongodb/examples/EmbeddedMongoPortLogger.java deleted file mode 100644 index 3a055330..00000000 --- a/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/main/java/org/springframework/session/mongodb/examples/EmbeddedMongoPortLogger.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2014-2016 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.session.mongodb.examples; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.context.EnvironmentAware; -import org.springframework.core.env.Environment; -import org.springframework.stereotype.Component; - -@Component -class EmbeddedMongoPortLogger implements ApplicationRunner, EnvironmentAware { - - private static final Log logger = LogFactory.getLog(EmbeddedMongoPortLogger.class); - - private Environment environment; - - @Override - public void run(ApplicationArguments args) throws Exception { - String port = this.environment.getProperty("local.mongo.port"); - logger.info("Embedded Mongo started on port " + port + ", use 'mongo --port " + port + "' command to connect"); - } - - @Override - public void setEnvironment(Environment environment) { - this.environment = environment; - } - -} diff --git a/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/main/java/org/springframework/session/mongodb/examples/SpringSessionMongoTraditionalBoot.java b/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/main/java/org/springframework/session/mongodb/examples/SpringSessionMongoTraditionalBoot.java index 6d4cab29..91b72c23 100644 --- a/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/main/java/org/springframework/session/mongodb/examples/SpringSessionMongoTraditionalBoot.java +++ b/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/main/java/org/springframework/session/mongodb/examples/SpringSessionMongoTraditionalBoot.java @@ -18,6 +18,15 @@ package org.springframework.session.mongodb.examples; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.testcontainers.containers.MongoDBContainer; +import org.testcontainers.utility.DockerImageName; + +import java.util.HashMap; +import java.util.Map; /** * @author Rob Winch @@ -25,8 +34,34 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringSessionMongoTraditionalBoot { - public static void main(String[] args) { - SpringApplication.run(SpringSessionMongoTraditionalBoot.class, args); + /** + * Use Testcontainers to managed MongoDB through Docker. + *

+ * @see https://bsideup.github.io/posts/local_development_with_testcontainers/ + */ + static class Initializer implements ApplicationContextInitializer { + + static MongoDBContainer mongo = new MongoDBContainer(DockerImageName.parse("mongo:5.0")); + + public static Map getProperties() { + mongo.start(); + + HashMap properties = new HashMap<>(); + properties.put("spring.data.mongodb.host", mongo.getHost()); + properties.put("spring.data.mongodb.port", mongo.getFirstMappedPort() + ""); + return properties; + } + + @Override + public void initialize(ConfigurableApplicationContext context) { + ConfigurableEnvironment env = context.getEnvironment(); + env.getPropertySources().addFirst(new MapPropertySource("testcontainers", (Map) getProperties())); + } } + public static void main(String[] args) { + SpringApplication application = new SpringApplication(SpringSessionMongoTraditionalBoot.class); + application.addInitializers(new Initializer()); + application.run(args); + } } diff --git a/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/main/resources/application.properties b/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/main/resources/application.properties index 45d08779..b8ff4f23 100644 --- a/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/main/resources/application.properties +++ b/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/main/resources/application.properties @@ -1,4 +1,5 @@ spring.thymeleaf.cache=false spring.template.cache=false -spring.data.mongodb.port=0 -spring.mongodb.embedded.version=3.4.3 + +logging.level.org.springframework.data.mongodb=DEBUG +logging.level.org.springframework.session=DEBUG diff --git a/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/test/java/org/springframework/session/mongodb/examples/BootTests.java b/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/test/java/org/springframework/session/mongodb/examples/BootTests.java index 58f37cb2..c91e193b 100644 --- a/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/test/java/org/springframework/session/mongodb/examples/BootTests.java +++ b/spring-session-samples/spring-session-sample-boot-mongodb-traditional/src/test/java/org/springframework/session/mongodb/examples/BootTests.java @@ -33,6 +33,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.session.mongodb.examples.pages.HomePage; import org.springframework.session.mongodb.examples.pages.LoginPage; +import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.htmlunit.webdriver.MockMvcHtmlUnitDriverBuilder; @@ -45,6 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat; @ExtendWith(SpringExtension.class) @AutoConfigureMockMvc @SpringBootTest(webEnvironment = WebEnvironment.MOCK) +@ContextConfiguration(initializers = SpringSessionMongoTraditionalBoot.Initializer.class) public class BootTests { @Autowired