diff --git a/bom/pom.xml b/bom/pom.xml
index ba88d13718..185f257cbd 100755
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -97,7 +97,7 @@
1.21
3.1.2
- 3.0.0
+ 3.2.6
1.19.0
@@ -996,14 +996,18 @@
${akka-persistence-inmemory.version}
test
-
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
- ${flapdoodle.version}
+ com.github.docker-java
+ docker-java-core
+ ${docker-java.version}
+ test
+
+
+ com.github.docker-java
+ docker-java-transport-zerodep
+ ${docker-java.version}
test
-
org.openjdk.jmh
jmh-core
diff --git a/services/concierge/actors/pom.xml b/services/concierge/actors/pom.xml
index 574c7ad1ce..b29b1a0ebf 100644
--- a/services/concierge/actors/pom.xml
+++ b/services/concierge/actors/pom.xml
@@ -66,12 +66,6 @@
awaitility
test
-
- org.eclipse.ditto
- ditto-services-utils-test
- test-jar
- test
-
ch.qos.logback
logback-classic
diff --git a/services/connectivity/messaging/pom.xml b/services/connectivity/messaging/pom.xml
index bdccfdb9f3..317bf9bb1d 100644
--- a/services/connectivity/messaging/pom.xml
+++ b/services/connectivity/messaging/pom.xml
@@ -215,11 +215,6 @@
awaitility
test
-
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
- test
-
org.eclipse.ditto
ditto-services-utils-test
diff --git a/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/persistence/ConnectionPersistenceActorTest.java b/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/persistence/ConnectionPersistenceActorTest.java
index 625690685d..305650f90f 100644
--- a/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/persistence/ConnectionPersistenceActorTest.java
+++ b/services/connectivity/messaging/src/test/java/org/eclipse/ditto/services/connectivity/messaging/persistence/ConnectionPersistenceActorTest.java
@@ -45,7 +45,6 @@
import javax.annotation.Nullable;
-import org.apache.commons.compress.utils.Sets;
import org.awaitility.Awaitility;
import org.eclipse.ditto.json.JsonPointer;
import org.eclipse.ditto.json.JsonValue;
@@ -142,7 +141,7 @@
*/
public final class ConnectionPersistenceActorTest extends WithMockServers {
- private static final Set SUBJECTS = Sets.newHashSet(TestConstants.Authorization.SUBJECT_ID,
+ private static final Set SUBJECTS = Set.of(TestConstants.Authorization.SUBJECT_ID,
TestConstants.Authorization.UNAUTHORIZED_SUBJECT_ID);
private static final Set TWIN_AND_LIVE_EVENTS =
EnumSet.of(StreamingType.EVENTS, StreamingType.LIVE_EVENTS);
diff --git a/services/connectivity/starter/pom.xml b/services/connectivity/starter/pom.xml
index 2dabe1f36e..688a2f5b30 100644
--- a/services/connectivity/starter/pom.xml
+++ b/services/connectivity/starter/pom.xml
@@ -104,11 +104,6 @@
test
test-jar
-
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
- test
-
com.typesafe.akka
akka-testkit_${scala.version}
diff --git a/services/policies/persistence/pom.xml b/services/policies/persistence/pom.xml
index c615537199..0237127e0f 100755
--- a/services/policies/persistence/pom.xml
+++ b/services/policies/persistence/pom.xml
@@ -98,12 +98,6 @@
com.typesafe.akka
akka-stream_${scala.version}
-
-
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
- test
-
ch.qos.logback
logback-classic
diff --git a/services/policies/starter/pom.xml b/services/policies/starter/pom.xml
index 78c38ed55e..83e1320144 100755
--- a/services/policies/starter/pom.xml
+++ b/services/policies/starter/pom.xml
@@ -111,11 +111,6 @@
akka-testkit_${scala.version}
test
-
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
- test
-
org.eclipse.ditto
ditto-services-utils-test
diff --git a/services/things/persistence/pom.xml b/services/things/persistence/pom.xml
index 441477387b..9b59967fc0 100755
--- a/services/things/persistence/pom.xml
+++ b/services/things/persistence/pom.xml
@@ -163,12 +163,6 @@
test-jar
test
-
-
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
- test
-
ch.qos.logback
logback-classic
diff --git a/services/things/starter/pom.xml b/services/things/starter/pom.xml
index a2ed7421de..e8fb0bb6ac 100755
--- a/services/things/starter/pom.xml
+++ b/services/things/starter/pom.xml
@@ -111,11 +111,6 @@
akka-testkit_${scala.version}
test
-
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
- test
-
org.eclipse.ditto
ditto-services-utils-test
diff --git a/services/thingsearch/persistence/pom.xml b/services/thingsearch/persistence/pom.xml
index 66df212c1d..1d24c874b0 100755
--- a/services/thingsearch/persistence/pom.xml
+++ b/services/thingsearch/persistence/pom.xml
@@ -173,8 +173,13 @@
test
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
+ com.github.docker-java
+ docker-java-core
+ test
+
+
+ com.github.docker-java
+ docker-java-transport-zerodep
test
diff --git a/services/thingsearch/persistence/src/test/java/org/eclipse/ditto/services/thingsearch/persistence/AbstractThingSearchPersistenceITBase.java b/services/thingsearch/persistence/src/test/java/org/eclipse/ditto/services/thingsearch/persistence/AbstractThingSearchPersistenceITBase.java
index e64ed56d89..df51289fd0 100644
--- a/services/thingsearch/persistence/src/test/java/org/eclipse/ditto/services/thingsearch/persistence/AbstractThingSearchPersistenceITBase.java
+++ b/services/thingsearch/persistence/src/test/java/org/eclipse/ditto/services/thingsearch/persistence/AbstractThingSearchPersistenceITBase.java
@@ -40,6 +40,7 @@
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.ClassRule;
import com.mongodb.reactivestreams.client.MongoCollection;
import com.typesafe.config.Config;
@@ -67,7 +68,9 @@ public abstract class AbstractThingSearchPersistenceITBase {
protected static QueryBuilderFactory qbf;
- private static MongoDbResource mongoResource;
+ @ClassRule
+ public static final MongoDbResource MONGO_RESOURCE = new MongoDbResource();
+
private static DittoMongoClient mongoClient;
private MongoCollection thingsCollection;
@@ -82,9 +85,6 @@ public static void startMongoResource() {
final Config rawTestConfig = ConfigFactory.load("test");
final DefaultLimitsConfig limitsConfig = DefaultLimitsConfig.of(rawTestConfig.getConfig("ditto"));
qbf = new MongoQueryBuilderFactory(limitsConfig);
-
- mongoResource = new MongoDbResource("localhost");
- mongoResource.start();
mongoClient = provideClientWrapper();
}
@@ -112,7 +112,7 @@ private TestSearchUpdaterStream provideWritePersistence() {
private static DittoMongoClient provideClientWrapper() {
return MongoClientWrapper.getBuilder()
.connectionString(
- "mongodb://" + mongoResource.getBindIp() + ":" + mongoResource.getPort() + "/testSearchDB")
+ "mongodb://" + MONGO_RESOURCE.getBindIp() + ":" + MONGO_RESOURCE.getPort() + "/testSearchDB")
.connectionPoolMaxSize(100)
.connectionPoolMaxWaitQueueSize(500000)
.connectionPoolMaxWaitTime(Duration.ofSeconds(30))
@@ -159,9 +159,6 @@ public static void stopMongoResource() {
if (mongoClient != null) {
mongoClient.close();
}
- if (mongoResource != null) {
- mongoResource.stop();
- }
} catch (final IllegalStateException e) {
System.err.println("IllegalStateException during shutdown of MongoDB: " + e.getMessage());
}
diff --git a/services/thingsearch/starter/pom.xml b/services/thingsearch/starter/pom.xml
index 735a48be93..aabc43aa56 100755
--- a/services/thingsearch/starter/pom.xml
+++ b/services/thingsearch/starter/pom.xml
@@ -122,8 +122,13 @@
test
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
+ com.github.docker-java
+ docker-java-core
+ test
+
+
+ com.github.docker-java
+ docker-java-transport-zerodep
test
diff --git a/services/thingsearch/starter/src/test/java/org/eclipse/ditto/services/thingsearch/starter/actors/SearchActorIT.java b/services/thingsearch/starter/src/test/java/org/eclipse/ditto/services/thingsearch/starter/actors/SearchActorIT.java
index e090679c37..06033c23ff 100644
--- a/services/thingsearch/starter/src/test/java/org/eclipse/ditto/services/thingsearch/starter/actors/SearchActorIT.java
+++ b/services/thingsearch/starter/src/test/java/org/eclipse/ditto/services/thingsearch/starter/actors/SearchActorIT.java
@@ -51,6 +51,7 @@
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.ClassRule;
import org.junit.Test;
import com.mongodb.reactivestreams.client.MongoCollection;
@@ -72,7 +73,8 @@ public final class SearchActorIT {
AuthorizationSubject.newInstance("ditto:ditto"));
private static QueryParser queryParser;
- private static MongoDbResource mongoResource;
+ @ClassRule
+ public static final MongoDbResource MONGO_RESOURCE = new MongoDbResource();
private static DittoMongoClient mongoClient;
private MongoThingsSearchPersistence readPersistence;
@@ -84,8 +86,6 @@ public final class SearchActorIT {
@BeforeClass
public static void startMongoResource() {
queryParser = SearchRootActor.getQueryParser(DefaultLimitsConfig.of(ConfigFactory.empty()));
- mongoResource = new MongoDbResource("localhost");
- mongoResource.start();
mongoClient = provideClientWrapper();
}
@@ -115,7 +115,7 @@ private static TestSearchUpdaterStream provideWritePersistence() {
private static DittoMongoClient provideClientWrapper() {
return MongoClientWrapper.getBuilder()
.connectionString(
- "mongodb://" + mongoResource.getBindIp() + ":" + mongoResource.getPort() + "/testSearchDB")
+ "mongodb://" + MONGO_RESOURCE.getBindIp() + ":" + MONGO_RESOURCE.getPort() + "/testSearchDB")
.build();
}
@@ -136,9 +136,6 @@ public static void stopMongoResource() {
if (mongoClient != null) {
mongoClient.close();
}
- if (mongoResource != null) {
- mongoResource.stop();
- }
} catch (final IllegalStateException e) {
System.err.println("IllegalStateException during shutdown of MongoDB: " + e.getMessage());
}
diff --git a/services/thingsearch/updater-actors/pom.xml b/services/thingsearch/updater-actors/pom.xml
index d0b98cdf92..63ddb171ae 100755
--- a/services/thingsearch/updater-actors/pom.xml
+++ b/services/thingsearch/updater-actors/pom.xml
@@ -110,14 +110,13 @@
test
- org.eclipse.ditto
- ditto-services-utils-test
- test-jar
+ com.github.docker-java
+ docker-java-core
test
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
+ com.github.docker-java
+ docker-java-transport-zerodep
test
diff --git a/services/utils/persistence/pom.xml b/services/utils/persistence/pom.xml
index bc4b95ef78..c75f96e161 100755
--- a/services/utils/persistence/pom.xml
+++ b/services/utils/persistence/pom.xml
@@ -121,8 +121,13 @@
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
+ com.github.docker-java
+ docker-java-core
+ test
+
+
+ com.github.docker-java
+ docker-java-transport-zerodep
test
diff --git a/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/indices/IndexInitializerIT.java b/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/indices/IndexInitializerIT.java
index fc7bcb0f01..8bf29f2379 100644
--- a/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/indices/IndexInitializerIT.java
+++ b/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/indices/IndexInitializerIT.java
@@ -25,16 +25,13 @@
import java.util.concurrent.CompletionException;
import java.util.concurrent.CompletionStage;
-import javax.annotation.Nullable;
-
import org.eclipse.ditto.services.utils.persistence.mongo.DittoMongoClient;
import org.eclipse.ditto.services.utils.persistence.mongo.MongoClientWrapper;
import org.eclipse.ditto.services.utils.persistence.mongo.assertions.MongoIndexAssertions;
import org.eclipse.ditto.services.utils.test.mongo.MongoDbResource;
import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Before;
-import org.junit.BeforeClass;
+import org.junit.ClassRule;
import org.junit.Test;
import com.mongodb.MongoCommandException;
@@ -52,6 +49,9 @@
*/
public final class IndexInitializerIT {
+ @ClassRule
+ public static final MongoDbResource MONGO_RESOURCE = new MongoDbResource();
+
private static final int CONNECTION_POOL_MAX_SIZE = 5;
private static final int CONNECTION_POOL_MAX_WAIT_QUEUE_SIZE = 5;
private static final long CONNECTION_POOL_MAX_WAIT_TIME_SECS = 3L;
@@ -89,37 +89,22 @@ public final class IndexInitializerIT {
Arrays.asList(DefaultIndexKey.of(FOO_FIELD, IndexDirection.ASCENDING),
DefaultIndexKey.of(BAR_FIELD, IndexDirection.ASCENDING)), false);
- @Nullable private static MongoDbResource mongoResource;
-
private ActorSystem system;
private Materializer materializer;
private DittoMongoClient mongoClient;
private IndexInitializer indexInitializerUnderTest;
private IndexOperations indexOperations;
- @BeforeClass
- public static void startMongoResource() {
- mongoResource = new MongoDbResource("localhost");
- mongoResource.start();
- }
-
- @AfterClass
- public static void stopMongoResource() {
- if (mongoResource != null) {
- mongoResource.stop();
- }
- }
-
@Before
public void before() {
system = ActorSystem.create("AkkaTestSystem");
materializer = SystemMaterializer.get(system).materializer();
- requireNonNull(mongoResource);
+ requireNonNull(MONGO_RESOURCE);
requireNonNull(materializer);
mongoClient = MongoClientWrapper.getBuilder()
- .hostnameAndPort(mongoResource.getBindIp(), mongoResource.getPort())
+ .hostnameAndPort(MONGO_RESOURCE.getBindIp(), MONGO_RESOURCE.getPort())
.defaultDatabaseName(getClass().getSimpleName() + "-" + UUID.randomUUID().toString())
.connectionPoolMaxSize(CONNECTION_POOL_MAX_SIZE)
.connectionPoolMaxWaitQueueSize(CONNECTION_POOL_MAX_WAIT_QUEUE_SIZE)
diff --git a/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/ops/eventsource/MongoEventSourceITAssertions.java b/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/ops/eventsource/MongoEventSourceITAssertions.java
index 5345983e6e..6e44d0c96f 100644
--- a/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/ops/eventsource/MongoEventSourceITAssertions.java
+++ b/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/ops/eventsource/MongoEventSourceITAssertions.java
@@ -36,8 +36,8 @@
import org.eclipse.ditto.signals.commands.namespaces.PurgeNamespace;
import org.eclipse.ditto.signals.commands.namespaces.PurgeNamespaceResponse;
import org.junit.After;
-import org.junit.AfterClass;
import org.junit.BeforeClass;
+import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.rules.TestName;
import org.mockito.Mockito;
@@ -62,10 +62,8 @@ public abstract class MongoEventSourceITAssertions {
protected static MongoDbConfig mongoDbConfig;
- /**
- * Embedded MongoDB resource.
- */
- private static MongoDbResource mongoDbResource;
+ @ClassRule
+ public static final MongoDbResource MONGO_RESOURCE = new MongoDbResource();
protected static String mongoDbUri;
protected static PersistenceOperationsConfig persistenceOperationsConfig;
@@ -75,10 +73,7 @@ public abstract class MongoEventSourceITAssertions {
@BeforeClass
public static void startMongoDb() {
- mongoDbResource = new MongoDbResource("localhost");
- mongoDbResource.start();
-
- mongoDbUri = String.format("mongodb://%s:%s/test", mongoDbResource.getBindIp(), mongoDbResource.getPort());
+ mongoDbUri = String.format("mongodb://%s:%s/test", MONGO_RESOURCE.getBindIp(), MONGO_RESOURCE.getPort());
mongoDbConfig = DefaultMongoDbConfig.of(getConfig());
persistenceOperationsConfig = mock(PersistenceOperationsConfig.class);
@@ -92,14 +87,6 @@ private static Config getConfig() {
return mongoDbTestConfig;
}
- @AfterClass
- public static void tearDown() {
- if (null != mongoDbResource) {
- mongoDbResource.stop();
- mongoDbResource = null;
- }
- }
-
@After
public void shutDownActorSystem() {
if (actorSystem != null) {
diff --git a/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/streaming/MongoReadJournalIT.java b/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/streaming/MongoReadJournalIT.java
index 418dc2a017..11785ab5b3 100644
--- a/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/streaming/MongoReadJournalIT.java
+++ b/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/streaming/MongoReadJournalIT.java
@@ -26,6 +26,7 @@
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.ClassRule;
import org.junit.Test;
import com.typesafe.config.Config;
@@ -45,10 +46,10 @@
*/
public final class MongoReadJournalIT {
- private static final String MONGO_HOST = "localhost";
private static final String MONGO_DB = "mongoReadJournalIT";
- private static MongoDbResource mongoResource;
+ @ClassRule
+ public static final MongoDbResource MONGO_RESOURCE = new MongoDbResource();
private static DittoMongoClient mongoClient;
private ActorSystem actorSystem;
@@ -57,10 +58,8 @@ public final class MongoReadJournalIT {
@BeforeClass
public static void startMongoResource() {
- mongoResource = new MongoDbResource(MONGO_HOST);
- mongoResource.start();
mongoClient = MongoClientWrapper.getBuilder()
- .hostnameAndPort(mongoResource.getBindIp(), mongoResource.getPort())
+ .hostnameAndPort(MONGO_RESOURCE.getBindIp(), MONGO_RESOURCE.getPort())
.defaultDatabaseName(MONGO_DB)
.connectionPoolMaxSize(100)
.connectionPoolMaxWaitQueueSize(500_000)
@@ -74,9 +73,6 @@ public static void stopMongoResource() {
if (null != mongoClient) {
mongoClient.close();
}
- if (null != mongoResource) {
- mongoResource.stop();
- }
} catch (final IllegalStateException e) {
System.err.println("IllegalStateException during shutdown of MongoDB: " + e.getMessage());
}
@@ -85,7 +81,8 @@ public static void stopMongoResource() {
@Before
public void setUp() {
// set persistence plugin Mongo URI for JavaDslReadJournal test
- final String mongoUri = String.format("mongodb://%s:%d/%s", MONGO_HOST, mongoResource.getPort(), MONGO_DB);
+ final String mongoUri =
+ String.format("mongodb://%s:%d/%s", MONGO_RESOURCE.getBindIp(), MONGO_RESOURCE.getPort(), MONGO_DB);
final Config config = ConfigFactory.load("mongo-read-journal-test")
.withValue("akka.contrib.persistence.mongodb.mongo.mongouri", ConfigValueFactory.fromAnyRef(mongoUri));
actorSystem = ActorSystem.create("AkkaTestSystem", config);
diff --git a/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/streaming/MongoTimestampPersistenceIT.java b/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/streaming/MongoTimestampPersistenceIT.java
index 30f0e21702..c99d86a8ad 100644
--- a/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/streaming/MongoTimestampPersistenceIT.java
+++ b/services/utils/persistence/src/test/java/org/eclipse/ditto/services/utils/persistence/mongo/streaming/MongoTimestampPersistenceIT.java
@@ -30,6 +30,7 @@
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.ClassRule;
import org.junit.Test;
import com.mongodb.reactivestreams.client.MongoCollection;
@@ -48,20 +49,20 @@
*/
public final class MongoTimestampPersistenceIT {
- private static MongoDbResource mongoResource;
+ @ClassRule
+ public static final MongoDbResource MONGO_RESOURCE = new MongoDbResource();
private static DittoMongoClient mongoClient;
private static final String KNOWN_COLLECTION = "knownCollection";
+
private ActorSystem actorSystem;
private Materializer materializer;
private MongoTimestampPersistence syncPersistence;
@BeforeClass
public static void startMongoResource() {
- mongoResource = new MongoDbResource("localhost");
- mongoResource.start();
mongoClient = MongoClientWrapper.getBuilder()
- .hostnameAndPort(mongoResource.getBindIp(), mongoResource.getPort())
+ .hostnameAndPort(MONGO_RESOURCE.getBindIp(), MONGO_RESOURCE.getPort())
.defaultDatabaseName("mongoTimestampPersistenceIT")
.connectionPoolMaxSize(100)
.connectionPoolMaxWaitQueueSize(500_000)
@@ -75,9 +76,6 @@ public static void stopMongoResource() {
if (null != mongoClient) {
mongoClient.close();
}
- if (null != mongoResource) {
- mongoResource.stop();
- }
} catch (final IllegalStateException e) {
System.err.println("IllegalStateException during shutdown of MongoDB: " + e.getMessage());
}
diff --git a/services/utils/test/pom.xml b/services/utils/test/pom.xml
index d7ae228982..f8a1b6fb54 100755
--- a/services/utils/test/pom.xml
+++ b/services/utils/test/pom.xml
@@ -31,10 +31,14 @@
ditto-model-base
test
-
- de.flapdoodle.embed
- de.flapdoodle.embed.mongo
+ com.github.docker-java
+ docker-java-core
+ test
+
+
+ com.github.docker-java
+ docker-java-transport-zerodep
test
diff --git a/services/utils/test/src/test/java/org/eclipse/ditto/services/utils/test/mongo/DockerContainer.java b/services/utils/test/src/test/java/org/eclipse/ditto/services/utils/test/mongo/DockerContainer.java
new file mode 100644
index 0000000000..b3a807b157
--- /dev/null
+++ b/services/utils/test/src/test/java/org/eclipse/ditto/services/utils/test/mongo/DockerContainer.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.eclipse.ditto.services.utils.test.mongo;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.github.dockerjava.api.DockerClient;
+import com.github.dockerjava.api.model.Container;
+import com.github.dockerjava.api.model.ContainerNetwork;
+import com.github.dockerjava.api.model.ContainerNetworkSettings;
+import com.github.dockerjava.api.model.ContainerPort;
+
+/**
+ * Provides an easy way to start, stop and remove the once created docker container.
+ */
+final class DockerContainer {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DockerContainer.class);
+ private static final Integer DOCKER_STOP_TIMEOUT_SECONDS = 5;
+ private final DockerClient dockerClient;
+ private final String containerId;
+
+ public DockerContainer(final DockerClient dockerClient, final String containerId) {
+ this.dockerClient = dockerClient;
+ this.containerId = containerId;
+ }
+
+ void start() {
+ LOGGER.info("Starting docker container with ID <{}>.", containerId);
+ dockerClient.startContainerCmd(containerId).exec();
+ }
+
+ void stop() {
+ LOGGER.info("Stopping docker container with ID <{}>.", containerId);
+ dockerClient.stopContainerCmd(containerId).withTimeout(DOCKER_STOP_TIMEOUT_SECONDS).exec();
+ }
+
+ void remove() {
+ LOGGER.info("Removing docker container with ID <{}>.", containerId);
+ dockerClient.removeContainerCmd(containerId).exec();
+ }
+
+ /**
+ * Translates the given private port (for mongo DB it is for example 27017) to the port it has been bound to
+ * on the host machine.
+ *
+ * @param privatePort the private port (for mongo DB it is for example 27017).
+ * @return the bound port.
+ * @throws IllegalArgumentException when the given private port was not exposed by this container.
+ */
+ int getPort(final int privatePort) {
+ final Container container = getContainer();
+ return Arrays.stream(container.getPorts())
+ .filter(containerPort -> {
+ final Integer containerPrivatePort = containerPort.getPrivatePort();
+ return containerPrivatePort != null && containerPrivatePort == privatePort &&
+ containerPort.getPublicPort() != null;
+ })
+ .findAny()
+ .map(ContainerPort::getPublicPort)
+ .orElseThrow(() -> {
+ final String message =
+ String.format("No internal port <%d> exposed in this docker container", privatePort);
+ return new IllegalArgumentException(message);
+ });
+ }
+
+ String getHostname() {
+ return Optional.ofNullable(getContainer().getNetworkSettings())
+ .map(ContainerNetworkSettings::getNetworks)
+ .map(networks -> networks.get("bridge"))
+ .map(ContainerNetwork::getGateway)
+ .orElseThrow(
+ () -> new IllegalArgumentException("Could not find a gateway defined for network 'bridge'.")
+ );
+ }
+
+ private Container getContainer() {
+ return dockerClient.listContainersCmd()
+ .exec()
+ .stream()
+ .filter(container -> container.getId().equals(containerId))
+ .findAny()
+ .orElseThrow(() -> {
+ final String message = String.format("No container with ID <%s> found.", containerId);
+ return new IllegalStateException(message);
+ });
+ }
+
+}
diff --git a/services/utils/test/src/test/java/org/eclipse/ditto/services/utils/test/mongo/DockerImagePullHandler.java b/services/utils/test/src/test/java/org/eclipse/ditto/services/utils/test/mongo/DockerImagePullHandler.java
new file mode 100644
index 0000000000..4191a1a37f
--- /dev/null
+++ b/services/utils/test/src/test/java/org/eclipse/ditto/services/utils/test/mongo/DockerImagePullHandler.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.eclipse.ditto.services.utils.test.mongo;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.concurrent.CompletableFuture;
+
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.github.dockerjava.api.async.ResultCallback;
+import com.github.dockerjava.api.model.PullResponseItem;
+
+/**
+ * Allows to watch completion of image pulling process and logs its progress.
+ */
+final class DockerImagePullHandler implements ResultCallback {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DockerImagePullHandler.class);
+
+ @Nullable
+ private Closeable closeable;
+ private final CompletableFuture imagePullFuture;
+
+ private DockerImagePullHandler() {
+ imagePullFuture = new CompletableFuture<>();
+ }
+
+ static DockerImagePullHandler newInstance() {
+ return new DockerImagePullHandler();
+ }
+
+ @Override
+ public void onStart(final Closeable closeable) {
+ LOGGER.info("Pulling docker image started. Closable: <{}>.", closeable);
+ this.closeable = closeable;
+ }
+
+ @Override
+ public void onNext(final PullResponseItem pullResponseItem) {
+ LOGGER.info("Got next pull response item <{}>.", pullResponseItem);
+ }
+
+ @Override
+ public void onError(final Throwable throwable) {
+ LOGGER.error("Got error during pulling image.", throwable);
+ imagePullFuture.completeExceptionally(throwable);
+ }
+
+ @Override
+ public void onComplete() {
+ LOGGER.info("Pulling docker image completed.");
+ imagePullFuture.complete(null);
+ }
+
+ public CompletableFuture getImagePullFuture() {
+ return imagePullFuture;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (closeable != null) {
+ LOGGER.info("Aborting pulling docker image.");
+ closeable.close();
+ imagePullFuture.complete(null);
+ }
+ }
+}
diff --git a/services/utils/test/src/test/java/org/eclipse/ditto/services/utils/test/mongo/MongoContainerFactory.java b/services/utils/test/src/test/java/org/eclipse/ditto/services/utils/test/mongo/MongoContainerFactory.java
new file mode 100644
index 0000000000..92be102a06
--- /dev/null
+++ b/services/utils/test/src/test/java/org/eclipse/ditto/services/utils/test/mongo/MongoContainerFactory.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.eclipse.ditto.services.utils.test.mongo;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+import com.github.dockerjava.api.DockerClient;
+import com.github.dockerjava.api.model.ExposedPort;
+import com.github.dockerjava.api.model.HostConfig;
+import com.github.dockerjava.api.model.Image;
+import com.github.dockerjava.api.model.PortBinding;
+import com.github.dockerjava.api.model.Ports;
+import com.github.dockerjava.core.DefaultDockerClientConfig;
+import com.github.dockerjava.core.DockerClientImpl;
+import com.github.dockerjava.zerodep.ZerodepDockerHttpClient;
+
+/**
+ * Responsible for creating and configuring the mongo db docker container that should be started for tests.
+ */
+final class MongoContainerFactory {
+
+ private static final String MONGO_IMAGE_NAME = "mongo";
+ private static final String MONGO_VERSION = "4.2";
+ private static final String MONGO_IMAGE_IDENTIFIER = MONGO_IMAGE_NAME + ":" + MONGO_VERSION;
+ private static final int MONGO_INTERNAL_PORT = 27017;
+ private static final PortBinding MONGO_PORT_BINDING_TO_RANDOM_PORT =
+ new PortBinding(Ports.Binding.empty(), ExposedPort.tcp(MONGO_INTERNAL_PORT));
+ private static final List MONGO_COMMANDS = Arrays.asList("mongod", "--storageEngine", "wiredTiger");
+
+ private static final MongoContainerFactory INSTANCE = new MongoContainerFactory();
+
+ private final DockerClient dockerClient;
+
+ private MongoContainerFactory() {
+ final DefaultDockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder().build();
+ final ZerodepDockerHttpClient httpClient = new ZerodepDockerHttpClient.Builder()
+ .dockerHost(config.getDockerHost())
+ .sslConfig(config.getSSLConfig())
+ .build();
+ dockerClient = DockerClientImpl.getInstance(config, httpClient);
+
+ if (isMongoImageAbsent()) {
+ pullMongoImage();
+ }
+ }
+
+ /**
+ * @return returns the singleton instance of this factory.
+ */
+ static MongoContainerFactory getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Creates the mongo docker container with all required configuration and returns it.
+ * It's not started after it has been returned.
+ *
+ * @return the created {@link DockerContainer}.
+ */
+ DockerContainer createMongoContainer() {
+ return getMongoImageId()
+ .map(imageId -> dockerClient.createContainerCmd(imageId)
+ .withCmd(MONGO_COMMANDS)
+ .withHostConfig(HostConfig.newHostConfig().withPortBindings(MONGO_PORT_BINDING_TO_RANDOM_PORT))
+ .exec()
+ .getId())
+ .map(containerId -> new DockerContainer(dockerClient, containerId))
+ .orElseThrow(
+ () -> new IllegalStateException("Could not create container because no image was present.")
+ );
+ }
+
+ private boolean isMongoImageAbsent() {
+ return getMongoImageId().isEmpty();
+ }
+
+ private Optional getMongoImageId() {
+ return dockerClient.listImagesCmd()
+ .withImageNameFilter(MONGO_IMAGE_IDENTIFIER)
+ .exec()
+ .stream()
+ .findFirst()
+ .map(Image::getId);
+ }
+
+ private void pullMongoImage() {
+ final DockerImagePullHandler dockerImagePullHandler = DockerImagePullHandler.newInstance();
+ dockerClient.pullImageCmd(MONGO_IMAGE_IDENTIFIER).exec(dockerImagePullHandler);
+ dockerImagePullHandler.getImagePullFuture().join();
+ }
+
+}
diff --git a/services/utils/test/src/test/java/org/eclipse/ditto/services/utils/test/mongo/MongoDbResource.java b/services/utils/test/src/test/java/org/eclipse/ditto/services/utils/test/mongo/MongoDbResource.java
index 5e8b3d1fca..fd2af84f9f 100755
--- a/services/utils/test/src/test/java/org/eclipse/ditto/services/utils/test/mongo/MongoDbResource.java
+++ b/services/utils/test/src/test/java/org/eclipse/ditto/services/utils/test/mongo/MongoDbResource.java
@@ -12,251 +12,43 @@
*/
package org.eclipse.ditto.services.utils.test.mongo;
-import java.io.IOException;
-import java.net.ServerSocket;
-import java.net.SocketException;
-import java.net.URI;
-import java.util.Optional;
-import java.util.function.Supplier;
-
-import javax.annotation.Nullable;
-
-import org.junit.Assume;
import org.junit.rules.ExternalResource;
-import org.slf4j.Logger;
-
-import de.flapdoodle.embed.mongo.Command;
-import de.flapdoodle.embed.mongo.MongodExecutable;
-import de.flapdoodle.embed.mongo.MongodProcess;
-import de.flapdoodle.embed.mongo.MongodStarter;
-import de.flapdoodle.embed.mongo.config.Defaults;
-import de.flapdoodle.embed.mongo.config.MongoCmdOptions;
-import de.flapdoodle.embed.mongo.config.MongodConfig;
-import de.flapdoodle.embed.mongo.config.Net;
-import de.flapdoodle.embed.mongo.distribution.Version;
-import de.flapdoodle.embed.process.config.io.ProcessOutput;
-import de.flapdoodle.embed.process.config.store.HttpProxyFactory;
-import de.flapdoodle.embed.process.config.store.ImmutableDownloadConfig;
-import de.flapdoodle.embed.process.io.progress.StandardConsoleProgressListener;
/**
* External Mongo DB resource for utilization within tests.
*/
public final class MongoDbResource extends ExternalResource {
- /**
- * Environment variable key for a HTTP Proxy.
- */
- private static final String HTTP_PROXY_ENV_KEY = "HTTP_PROXY";
-
- /**
- * Environment variable key for the port number of the MongoDB process.
- */
- private static final String MONGO_PORT_ENV_KEY = "MONGO_PORT";
-
- private final String bindIp;
- private final Integer defaultPort;
- private final Logger logger;
-
- /**
- * The MongoDB executable.
- */
- private MongodExecutable mongodExecutable;
-
- /**
- * The MongoDB process.
- */
- private MongodProcess mongodProcess;
-
- /**
- * Constructs a new {@code MongoDbResource} object.
- *
- * @param bindIp the IP to bind the DB on
- */
- public MongoDbResource(final String bindIp) {
- this(bindIp, null, null);
- }
-
- /**
- * Constructs a new {@code MongoDbResource} object.
- *
- * @param bindIp the IP to bind the DB on
- * @param logger the logger used for mongod output, may be {@code null} (logging turned off)
- */
- public MongoDbResource(final String bindIp, final Logger logger) {
- this(bindIp, null, logger);
- }
-
- /**
- * Constructs a new {@code MongoDbResource} object.
- *
- * @param bindIp the IP to bind the DB on
- * @param defaultPort the default listening port. Bind a random port if it is {@code null}.
- * @param logger the logger used for mongod output, may be {@code null} (logging turned off)
- */
- public MongoDbResource(final String bindIp, final Integer defaultPort, final Logger logger) {
- this.bindIp = bindIp;
- this.defaultPort = defaultPort;
- this.logger = logger;
- mongodExecutable = null;
- mongodProcess = null;
- }
-
- public void start() {
- before();
- }
+ private static final int MONGO_INTERNAL_PORT = 27017;
+ private final DockerContainer mongoContainer;
- public void stop() {
- after();
+ public MongoDbResource() {
+ mongoContainer = MongoContainerFactory.getInstance().createMongoContainer();
}
@Override
protected void before() {
- final Optional proxyUppercase = Optional.ofNullable(System.getenv(HTTP_PROXY_ENV_KEY));
- final Optional proxyLowercase = Optional.ofNullable(System.getenv(HTTP_PROXY_ENV_KEY.toLowerCase()));
- final Optional httpProxy = proxyUppercase.isPresent() ? proxyUppercase : proxyLowercase;
- @Nullable final HttpProxyFactory proxyFactory = httpProxy
- .map(URI::create)
- .map(proxyURI -> new HttpProxyFactory(proxyURI.getHost(), proxyURI.getPort()))
- .orElse(null);
-
- final int mongoDbPort = defaultPort != null
- ? defaultPort
- : System.getenv(MONGO_PORT_ENV_KEY) != null
- ? Integer.parseInt(System.getenv(MONGO_PORT_ENV_KEY))
- : findFreePort();
-
- mongodExecutable = tryToConfigureMongoDb(bindIp, mongoDbPort, proxyFactory, logger);
- mongodProcess = tryToStartMongoDb(mongodExecutable);
- Assume.assumeTrue("MongoDB resource failed to start.", isHealthy());
+ mongoContainer.start();
}
@Override
protected void after() {
- if (mongodProcess != null) {
- mongodProcess.stop();
- }
- if (mongodExecutable != null) {
- mongodExecutable.stop();
- }
- }
-
- /**
- * @return whether mongodb started successfully.
- */
- public boolean isHealthy() {
- return mongodProcess != null && mongodExecutable != null;
+ mongoContainer.stop();
+ mongoContainer.remove();
}
/**
* @return the port on which the db listens.
*/
public int getPort() {
- return mongodProcess.getConfig().net().getPort();
+ return mongoContainer.getPort(MONGO_INTERNAL_PORT);
}
/**
* @return the IP on which the db was bound.
*/
public String getBindIp() {
- return mongodProcess.getConfig().net().getBindIp();
- }
-
- /**
- * This method will return a free port number.
- *
- * @return the port number.
- * @throws IllegalStateException if no free port available.
- */
- private static int findFreePort() {
- final Supplier freePortFinder = new FreePortFinder();
- return freePortFinder.get();
- }
-
- private static MongodExecutable tryToConfigureMongoDb(final String bindIp,
- final int mongoDbPort,
- @Nullable final HttpProxyFactory proxyFactory,
- final Logger logger) {
-
- try {
- return configureMongoDb(bindIp, mongoDbPort, proxyFactory, logger);
- } catch (final Throwable e) {
- return null;
- }
- }
-
- private static MongodExecutable configureMongoDb(final String bindIp,
- final int mongoDbPort,
- @Nullable final HttpProxyFactory proxyFactory,
- final Logger logger) throws IOException {
-
- final Command command = Command.MongoD;
-
- final ProcessOutput processOutput;
- if (logger != null) {
- processOutput = ProcessOutput.getInstance("mongod", logger);
- } else {
- processOutput = ProcessOutput.getDefaultInstanceSilent();
- }
-
- final ImmutableDownloadConfig.Builder downloadConfigBuilder =
- Defaults.downloadConfigFor(command).progressListener(new StandardConsoleProgressListener());
- if (proxyFactory != null) {
- downloadConfigBuilder.proxyFactory(proxyFactory);
- }
-
- final MongodStarter mongodStarter = MongodStarter.getInstance(Defaults.runtimeConfigFor(command)
- .processOutput(processOutput)
- .artifactStore(Defaults.extractedArtifactStoreFor(command)
- .withDownloadConfig(downloadConfigBuilder.build()))
- .build());
-
- return mongodStarter.prepare(MongodConfig.builder()
- .net(new Net(bindIp, mongoDbPort, false))
- .version(Version.Main.V3_6)
- .cmdOptions(MongoCmdOptions.builder()
- .storageEngine("wiredTiger")
- .useNoJournal(false)
- .build())
- .build());
- }
-
- private static MongodProcess tryToStartMongoDb(final MongodExecutable mongodExecutable) {
- try {
- return mongodExecutable.start();
- } catch (final IOException e) {
- throw new IllegalStateException("Failed to start MongoDB!", e);
- }
- }
-
- private static final class FreePortFinder implements Supplier {
-
- @Override
- public Integer get() {
- try (final ServerSocket socket = tryToCreateServerSocket()) {
- tryToSetReuseAddress(socket);
- return socket.getLocalPort();
- } catch (final IOException e) {
- throw new IllegalStateException("Failed to close server socket!", e);
- }
- }
-
- private static ServerSocket tryToCreateServerSocket() {
- try {
- return new ServerSocket(0);
- } catch (final IOException e) {
- throw new IllegalStateException("Failed to create a ServerSocket object!", e);
- }
- }
-
- private static void tryToSetReuseAddress(final ServerSocket serverSocket) {
- try {
- serverSocket.setReuseAddress(true);
- } catch (final SocketException e) {
- throw new IllegalStateException("Failed to set reuse address to server socket!", e);
- }
- }
-
+ return mongoContainer.getHostname();
}
}