From 903cac492ea5dcf3ed7502cdd9375dfe3dfce180 Mon Sep 17 00:00:00 2001 From: Vedran Pavic Date: Sun, 20 Mar 2016 01:43:54 +0100 Subject: [PATCH] Use Flapdoodle Embedded MongoDB for integration tests and samples --- .travis.yml | 3 +- docs/src/docs/asciidoc/guides/mongo.adoc | 16 +++--- samples/mongo/build.gradle | 3 +- .../java/sample/EmbeddedMongoPortLogger.java | 44 +++++++++++++++ .../src/main/resources/application.properties | 1 + spring-session/build.gradle | 3 +- .../mongo/AbstractMongoRepositoryITests.java | 30 +++++++++++ .../session/data/mongo/MongoITestUtils.java | 53 +++++++++++++++++++ .../mongo/MongoRepositoryJacksonITests.java | 15 ++---- ...MongoRepositoryJdkSerializationITests.java | 15 ++---- 10 files changed, 151 insertions(+), 32 deletions(-) create mode 100644 samples/mongo/src/main/java/sample/EmbeddedMongoPortLogger.java create mode 100644 spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoITestUtils.java diff --git a/.travis.yml b/.travis.yml index 4e05d41b..3dc538bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: java services: - redis-server - - mongodb jdk: - oraclejdk8 @@ -21,4 +20,4 @@ cache: - $HOME/.gradle/caches/ - $HOME/.gradle/wrapper/ -script: ./gradlew build \ No newline at end of file +script: ./gradlew build diff --git a/docs/src/docs/asciidoc/guides/mongo.adoc b/docs/src/docs/asciidoc/guides/mongo.adoc index 3055dfde..1c1636d6 100644 --- a/docs/src/docs/asciidoc/guides/mongo.adoc +++ b/docs/src/docs/asciidoc/guides/mongo.adoc @@ -122,12 +122,6 @@ The Mongo Sample Application demonstrates how to use Spring Session to transpare You can run the sample by obtaining the {download-url}[source code] and invoking the following command: -[NOTE] -==== -For the sample to work, you must have MongoDB on localhost and run it with the default port (27017). -Alternatively you can use docker to run local instance `docker run -p 27017:27017 mongo` -==== - ---- $ ./gradlew :samples:mongo:bootRun ---- @@ -156,9 +150,15 @@ When Spring Security's `SecurityContextPersistenceFilter` saves the `SecurityCon When a new `HttpSession` is created, Spring Session creates a cookie named SESSION in your browser that contains the id of your session. Go ahead and view the cookies (click for help with https://developer.chrome.com/devtools/docs/resources#cookies[Chrome] or https://getfirebug.com/wiki/index.php/Cookies_Panel#Cookies_List[Firefox]). -If you like, you can easily remove the session using mongo client. For example, on a Linux based system you can type: +If you like, you can easily inspect the session using mongo client. For example, on a Linux based system you can type: - $ mongo +[NOTE] +==== +The sample application uses an embedded MongoDB instance that listens on a randomly allocated port. +The port used by embedded MongoDB together with exact command to connect to it is logged during application startup. +==== + + $ mongo --port ... > use test > db.sessions.find().pretty() diff --git a/samples/mongo/build.gradle b/samples/mongo/build.gradle index 3c0438a1..c42bbba3 100644 --- a/samples/mongo/build.gradle +++ b/samples/mongo/build.gradle @@ -21,6 +21,7 @@ dependencies { "org.springframework.boot:spring-boot-starter-web", "org.springframework.boot:spring-boot-starter-thymeleaf", "nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect", + "de.flapdoodle.embed:de.flapdoodle.embed.mongo", "org.springframework.security:spring-security-web:$springSecurityVersion", "org.springframework.security:spring-security-config:$springSecurityVersion" @@ -50,4 +51,4 @@ def reservePort() { def result = socket.localPort socket.close() result -} \ No newline at end of file +} diff --git a/samples/mongo/src/main/java/sample/EmbeddedMongoPortLogger.java b/samples/mongo/src/main/java/sample/EmbeddedMongoPortLogger.java new file mode 100644 index 00000000..9dbe1eda --- /dev/null +++ b/samples/mongo/src/main/java/sample/EmbeddedMongoPortLogger.java @@ -0,0 +1,44 @@ +/* + * 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 + * + * http://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 sample; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +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 Logger logger = LoggerFactory.getLogger(EmbeddedMongoPortLogger.class); + + private Environment environment; + + 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"); + } + + public void setEnvironment(Environment environment) { + this.environment = environment; + } + +} diff --git a/samples/mongo/src/main/resources/application.properties b/samples/mongo/src/main/resources/application.properties index f0baad36..51ab5db5 100644 --- a/samples/mongo/src/main/resources/application.properties +++ b/samples/mongo/src/main/resources/application.properties @@ -1,2 +1,3 @@ spring.thymeleaf.cache=false spring.template.cache=false +spring.data.mongodb.port=0 diff --git a/spring-session/build.gradle b/spring-session/build.gradle index 5e546fba..68939653 100644 --- a/spring-session/build.gradle +++ b/spring-session/build.gradle @@ -28,7 +28,8 @@ dependencies { integrationTestCompile "redis.clients:jedis:2.4.1", "org.apache.commons:commons-pool2:2.2", "com.hazelcast:hazelcast-client:$hazelcastVersion", - "com.h2database:h2:$h2Version" + "com.h2database:h2:$h2Version", + "de.flapdoodle.embed:de.flapdoodle.embed.mongo:1.50.2" integrationTestRuntime "org.springframework.shell:spring-shell:1.0.0.RELEASE" diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/AbstractMongoRepositoryITests.java b/spring-session/src/integration-test/java/org/springframework/session/data/mongo/AbstractMongoRepositoryITests.java index 24778156..50bca1fe 100644 --- a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/AbstractMongoRepositoryITests.java +++ b/spring-session/src/integration-test/java/org/springframework/session/data/mongo/AbstractMongoRepositoryITests.java @@ -15,13 +15,21 @@ */ package org.springframework.session.data.mongo; +import java.io.IOException; +import java.net.UnknownHostException; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; +import com.mongodb.MongoClient; +import de.flapdoodle.embed.mongo.MongodExecutable; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.DependsOn; +import org.springframework.data.mongodb.core.MongoOperations; +import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.AuthorityUtils; @@ -30,11 +38,15 @@ import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.session.FindByIndexNameSessionRepository; import org.springframework.session.Session; import org.springframework.session.data.AbstractITests; +import org.springframework.util.SocketUtils; import static org.assertj.core.api.Assertions.assertThat; /** + * Abstract base class for {@link MongoOperationsSessionRepository} tests. + * * @author Jakub Kubrynski + * @author Vedran Pavic */ abstract public class AbstractMongoRepositoryITests extends AbstractITests { @@ -364,4 +376,22 @@ abstract public class AbstractMongoRepositoryITests extends AbstractITests { return this.changedContext.getAuthentication().getName(); } + protected static class BaseConfig { + + private int embeddedMongoPort = SocketUtils.findAvailableTcpPort(); + + @Bean(initMethod = "start", destroyMethod = "stop") + public MongodExecutable embeddedMongoServer() throws IOException { + return MongoITestUtils.embeddedMongoServer(this.embeddedMongoPort); + } + + @Bean + @DependsOn("embeddedMongoServer") + public MongoOperations mongoOperations() throws UnknownHostException { + MongoClient mongo = new MongoClient("localhost", this.embeddedMongoPort); + return new MongoTemplate(mongo, "test"); + } + + } + } diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoITestUtils.java b/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoITestUtils.java new file mode 100644 index 00000000..fa4f94f7 --- /dev/null +++ b/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoITestUtils.java @@ -0,0 +1,53 @@ +/* + * 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 + * + * http://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.data.mongo; + +import java.io.IOException; + +import de.flapdoodle.embed.mongo.MongodExecutable; +import de.flapdoodle.embed.mongo.MongodStarter; +import de.flapdoodle.embed.mongo.config.IMongodConfig; +import de.flapdoodle.embed.mongo.config.MongodConfigBuilder; +import de.flapdoodle.embed.mongo.config.Net; +import de.flapdoodle.embed.mongo.distribution.Version; +import de.flapdoodle.embed.process.runtime.Network; + +/** + * Utility class for Mongo integration tests. + * + * @author Vedran Pavic + */ +final class MongoITestUtils { + + private MongoITestUtils() { + } + + /** + * Creates {@link MongodExecutable} for use in integration tests. + * @param port the port for embedded Mongo to bind to + * @return the {@link MongodExecutable} instance + * @throws IOException in case of I/O errors + */ + static MongodExecutable embeddedMongoServer(int port) throws IOException { + IMongodConfig mongodConfig = new MongodConfigBuilder() + .version(Version.Main.PRODUCTION) + .net(new Net(port, Network.localhostIsIPv6())) + .build(); + MongodStarter mongodStarter = MongodStarter.getDefaultInstance(); + return mongodStarter.prepare(mongodConfig); + } + +} diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoRepositoryJacksonITests.java b/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoRepositoryJacksonITests.java index b24872fa..0f05827f 100644 --- a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoRepositoryJacksonITests.java +++ b/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoRepositoryJacksonITests.java @@ -15,27 +15,27 @@ */ package org.springframework.session.data.mongo; -import java.net.UnknownHostException; import java.util.Collections; import java.util.Map; import java.util.UUID; import com.fasterxml.jackson.databind.Module; -import com.mongodb.MongoClient; import org.junit.Test; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.geo.GeoModule; -import org.springframework.data.mongodb.core.MongoOperations; -import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession; import org.springframework.test.context.ContextConfiguration; import static org.assertj.core.api.Assertions.assertThat; /** + * Integration tests for {@link MongoOperationsSessionRepository} that use + * {@link JacksonMongoSessionConverter} based session serialization. + * * @author Jakub Kubrynski + * @author Vedran Pavic */ @ContextConfiguration public class MongoRepositoryJacksonITests extends AbstractMongoRepositoryITests { @@ -57,12 +57,7 @@ public class MongoRepositoryJacksonITests extends AbstractMongoRepositoryITests @Configuration @EnableMongoHttpSession - static class Config { - - @Bean - public MongoOperations mongoOperations() throws UnknownHostException { - return new MongoTemplate(new MongoClient(), "test"); - } + static class Config extends BaseConfig { @Bean public AbstractMongoSessionConverter mongoSessionConverter() { diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoRepositoryJdkSerializationITests.java b/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoRepositoryJdkSerializationITests.java index 99dd16bc..5c63e094 100644 --- a/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoRepositoryJdkSerializationITests.java +++ b/spring-session/src/integration-test/java/org/springframework/session/data/mongo/MongoRepositoryJdkSerializationITests.java @@ -15,23 +15,23 @@ */ package org.springframework.session.data.mongo; -import java.net.UnknownHostException; import java.util.Map; -import com.mongodb.MongoClient; import org.junit.Test; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.mongodb.core.MongoOperations; -import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.session.data.mongo.config.annotation.web.http.EnableMongoHttpSession; import org.springframework.test.context.ContextConfiguration; import static org.assertj.core.api.Assertions.assertThat; /** + * Integration tests for {@link MongoOperationsSessionRepository} that use + * {@link JacksonMongoSessionConverter} based session serialization. + * * @author Jakub Kubrynski + * @author Vedran Pavic */ @ContextConfiguration public class MongoRepositoryJdkSerializationITests extends AbstractMongoRepositoryITests { @@ -75,12 +75,7 @@ public class MongoRepositoryJdkSerializationITests extends AbstractMongoReposito @Configuration @EnableMongoHttpSession - static class Config { - - @Bean - public MongoOperations mongoOperations() throws UnknownHostException { - return new MongoTemplate(new MongoClient(), "test"); - } + static class Config extends BaseConfig { @Bean public AbstractMongoSessionConverter mongoSessionConverter() {