You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by mr...@apache.org on 2018/09/11 11:53:44 UTC

svn commit: r1840545 - in /jackrabbit/oak/trunk/oak-store-document: ./ src/test/java/org/apache/jackrabbit/oak/plugins/document/ src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/

Author: mreutegg
Date: Tue Sep 11 11:53:44 2018
New Revision: 1840545

URL: http://svn.apache.org/viewvc?rev=1840545&view=rev
Log:
OAK-7732: Use docker for MongoDB based tests when available

Try fallback to local docker if configured MongoDB is not available

Added:
    jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDockerRule.java   (with props)
Modified:
    jackrabbit/oak/trunk/oak-store-document/pom.xml
    jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoConnectionFactory.java
    jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoUtils.java

Modified: jackrabbit/oak/trunk/oak-store-document/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/pom.xml?rev=1840545&r1=1840544&r2=1840545&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-store-document/pom.xml Tue Sep 11 11:53:44 2018
@@ -327,5 +327,10 @@
       <artifactId>metrics-core</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>com.arakelian</groupId>
+      <artifactId>docker-junit-rule</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>

Modified: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoConnectionFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoConnectionFactory.java?rev=1840545&r1=1840544&r2=1840545&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoConnectionFactory.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoConnectionFactory.java Tue Sep 11 11:53:44 2018
@@ -20,26 +20,44 @@ import java.util.List;
 
 import com.google.common.collect.Lists;
 
+import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDockerRule;
 import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection;
 import org.jetbrains.annotations.Nullable;
 import org.junit.rules.ExternalResource;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import static org.junit.Assume.assumeNotNull;
 
 public class MongoConnectionFactory extends ExternalResource {
 
+    private final MongoDockerRule mongo = new MongoDockerRule();
+
     private final List<MongoConnection> connections = Lists.newArrayList();
 
+    @Override
+    public Statement apply(Statement base, Description description) {
+        Statement s = super.apply(base, description);
+        if (mongo.isDockerAvailable()) {
+            s = mongo.apply(s, description);
+        }
+        return s;
+    }
+
     @Nullable
     public MongoConnection getConnection() {
-        MongoConnection c = MongoUtils.getConnection();
-        if (c != null) {
-            connections.add(c);
-        }
-        return c;
+        return getConnection(MongoUtils.DB);
     }
 
     @Nullable
     public MongoConnection getConnection(String dbName) {
+        // first try MongoDB running on configured host and port
         MongoConnection c = MongoUtils.getConnection(dbName);
+        if (c == null && mongo.isDockerAvailable()) {
+            // fall back to docker if available
+            c = new MongoConnection("localhost", mongo.getPort(), dbName);
+        }
+        assumeNotNull(c);
         if (c != null) {
             connections.add(c);
         }

Modified: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoUtils.java?rev=1840545&r1=1840544&r2=1840545&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoUtils.java (original)
+++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/MongoUtils.java Tue Sep 11 11:53:44 2018
@@ -16,10 +16,20 @@
  */
 package org.apache.jackrabbit.oak.plugins.document;
 
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDockerRule;
 import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.mongodb.BasicDBObject;
 import com.mongodb.DB;
+import com.mongodb.MongoClientURI;
 import com.mongodb.client.MongoDatabase;
 
 /**
@@ -28,6 +38,10 @@ import com.mongodb.client.MongoDatabase;
  */
 public class MongoUtils {
 
+    private static final Logger LOG = LoggerFactory.getLogger(MongoUtils.class);
+
+    protected static Map<String, Exception> exceptions = new ConcurrentHashMap<>();
+
     protected static final String HOST =
             System.getProperty("mongo.host", "127.0.0.1");
 
@@ -37,19 +51,44 @@ public class MongoUtils {
     public static final String DB =
             System.getProperty("mongo.db", "MongoMKDB");
 
+    public static final String VERSION =
+            System.getProperty("mongo.version", "3.6");
+
+    private static final String OPTIONS = "connectTimeoutMS=3000&serverSelectionTimeoutMS=3000";
+
     public static final String URL = createMongoURL();
 
     private static String createMongoURL() {
+        // first try configured URL
         String mongoUrl = System.getProperty("mongo.url");
         if (mongoUrl == null || mongoUrl.isEmpty()) {
-            mongoUrl = "mongodb://" + HOST + ":" + PORT + "/" + DB +
-                    "?connectTimeoutMS=3000&serverSelectionTimeoutMS=3000";
+            mongoUrl = "mongodb://" + HOST + ":" + PORT + "/" + DB + "?" + OPTIONS;
+        }
+        // check if we can connect
+        MongoConnection c = getConnectionByURL(mongoUrl);
+        if (c != null) {
+            c.close();
+            return mongoUrl;
+        }
+        // fallback to docker based MongoDB if available
+        MongoDockerRule dockerRule = new MongoDockerRule();
+        if (dockerRule.isDockerAvailable()) {
+            AtomicInteger port = new AtomicInteger();
+            try {
+                dockerRule.apply(new Statement() {
+                    @Override
+                    public void evaluate() {
+                        port.set(dockerRule.getPort());
+                    }
+                }, Description.EMPTY).evaluate();
+                mongoUrl = "mongodb://localhost:" + port.get() + "/" + DB + "?" + OPTIONS;
+            } catch (Throwable t) {
+                LOG.warn("Unable to get MongoDB port from Docker", t);
+            }
         }
         return mongoUrl;
     }
 
-    protected static Exception exception;
-
     /**
      * Get a connection if available. If not available, null is returned.
      *
@@ -66,7 +105,22 @@ public class MongoUtils {
      * @return the connection or null
      */
     public static MongoConnection getConnection(String dbName) {
-        return getConnectionByURL("mongodb://" + HOST + ":" + PORT + "/" + dbName);
+        MongoClientURI clientURI;
+        try {
+            clientURI = new MongoClientURI(URL);
+        } catch (IllegalArgumentException e) {
+            // configured URL is invalid
+            return null;
+        }
+        StringBuilder uri = new StringBuilder("mongodb://");
+        String separator = "";
+        for (String host : clientURI.getHosts()) {
+            uri.append(separator);
+            separator = ",";
+            uri.append(host);
+        }
+        uri.append("/").append(dbName).append("?").append(OPTIONS);
+        return getConnectionByURL(uri.toString());
     }
 
     /**
@@ -156,7 +210,7 @@ public class MongoUtils {
      * @return the connection or null
      */
     private static MongoConnection getConnectionByURL(String url) {
-        if (exception != null) {
+        if (exceptions.get(url) != null) {
             return null;
         }
         MongoConnection mongoConnection;
@@ -165,7 +219,7 @@ public class MongoUtils {
             mongoConnection.getDatabase().runCommand(new BasicDBObject("ping", 1));
             // dropCollections(mongoConnection.getDB());
         } catch (Exception e) {
-            exception = e;
+            exceptions.put(url, e);
             mongoConnection = null;
         }
         return mongoConnection;

Added: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDockerRule.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDockerRule.java?rev=1840545&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDockerRule.java (added)
+++ jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDockerRule.java Tue Sep 11 11:53:44 2018
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jackrabbit.oak.plugins.document.mongo;
+
+import com.arakelian.docker.junit.DockerRule;
+import com.arakelian.docker.junit.model.ImmutableDockerConfig;
+import com.spotify.docker.client.DefaultDockerClient;
+
+import org.apache.jackrabbit.oak.plugins.document.MongoUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A MongoDB {@link DockerRule}.
+ */
+public class MongoDockerRule extends DockerRule {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MongoDockerRule.class);
+
+    private static final String CONFIG_NAME = "MongoDB";
+
+    private static final boolean DOCKER_AVAILABLE;
+
+    static {
+        boolean available = false;
+        try (DefaultDockerClient client = DefaultDockerClient.fromEnv()
+                .connectTimeoutMillis(5000L).readTimeoutMillis(20000L).build()) {
+            client.ping();
+            available = true;
+        } catch (Exception e) {
+            LOG.info("Cannot connect to docker", e);
+        }
+        DOCKER_AVAILABLE = available;
+    }
+
+    public MongoDockerRule() {
+        super(ImmutableDockerConfig.builder()
+                .name(CONFIG_NAME)
+                .image("mongo:" + MongoUtils.VERSION)
+                .ports("27017")
+                .allowRunningBetweenUnitTests(true)
+                .alwaysRemoveContainer(true)
+                .addStartedListener(container -> container.waitForPort("27017/tcp"))
+                .build());
+    }
+
+    public int getPort() {
+        return getContainer().getPortBinding("27017/tcp").getPort();
+    }
+
+    public boolean isDockerAvailable() {
+        return DOCKER_AVAILABLE;
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-store-document/src/test/java/org/apache/jackrabbit/oak/plugins/document/mongo/MongoDockerRule.java
------------------------------------------------------------------------------
    svn:eol-style = native