Add module commons-testing-junit4-mongodb.
authorGary Gregory <garydgregory@gmail.com>
Tue, 6 Feb 2018 00:04:11 +0000 (17:04 -0700)
committerGary Gregory <garydgregory@gmail.com>
Tue, 6 Feb 2018 00:04:11 +0000 (17:04 -0700)
13 files changed:
commons-testing-generic/pom.xml
commons-testing-generic/src/main/java/org/apache/commons/testing/Closer.java [new file with mode: 0644]
commons-testing-generic/src/main/java/org/apache/commons/testing/net/AvailableServerPortFinder.java [new file with mode: 0644]
commons-testing-generic/src/test/java/org/apache/commons/testing/CloserTest.java [new file with mode: 0644]
commons-testing-generic/src/test/java/org/apache/commons/testing/net/AvailableServerPortFinderTest.java [new file with mode: 0644]
commons-testing-junit4-mongodb/pom.xml [new file with mode: 0644]
commons-testing-junit4-mongodb/src/main/java/org/apache/commons/testing/junit4/mongodb/MongoDbTestRule.java [new file with mode: 0644]
commons-testing-junit4-mongodb/src/test/java/org/apache/commons/testing/junit4/mongodb/MongoDbTestRuleTest.java [new file with mode: 0644]
commons-testing-junit4/pom.xml
commons-testing-junit4/src/main/java/org/apache/commons/testing/junit4/RuleChainFactory.java [new file with mode: 0644]
commons-testing-junit4/src/main/java/org/apache/commons/testing/junit4/net/AvailableServerPortSystemPropertyTestRule.java [new file with mode: 0644]
commons-testing-junit4/src/test/java/org/apache/commons/testing/junit4/net/AvailableServerPortSystemPropertyTestRuleTest.java [new file with mode: 0644]
pom.xml

index b70c253..b50486a 100644 (file)
     </site>\r
   </distributionManagement>\r
 \r
+  <dependencies>\r
+    <dependency>\r
+      <groupId>junit</groupId>\r
+      <artifactId>junit</artifactId>\r
+      <scope>test</scope>\r
+    </dependency>\r
+  </dependencies>\r
+\r
   <reporting>\r
     <plugins>\r
       <plugin>\r
diff --git a/commons-testing-generic/src/main/java/org/apache/commons/testing/Closer.java b/commons-testing-generic/src/main/java/org/apache/commons/testing/Closer.java
new file mode 100644 (file)
index 0000000..41bce1e
--- /dev/null
@@ -0,0 +1,60 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache license, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the license for the specific language governing permissions and\r
+ * limitations under the license.\r
+ */\r
+\r
+package org.apache.commons.testing;\r
+\r
+/**\r
+ * Helper class for closing resources.\r
+ */\r
+public final class Closer {\r
+\r
+    /**\r
+     * Closes an AutoCloseable or ignores if {@code null}.\r
+     *\r
+     * @param closeable\r
+     *            the resource to close; may be null\r
+     * @throws Exception\r
+     *             if the resource cannot be closed\r
+     * @since 1.0.0\r
+     */\r
+    public static void close(final AutoCloseable closeable) throws Exception {\r
+        if (closeable != null) {\r
+            closeable.close();\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Closes an AutoCloseable and returns {@code true} if it closed without exception.\r
+     *\r
+     * @param closeable\r
+     *            the resource to close; may be null\r
+     * @return true if resource was closed successfully, or false if an exception was thrown\r
+     * @since 1.0.0\r
+     */\r
+    public static boolean closeSilently(final AutoCloseable closeable) {\r
+        try {\r
+            close(closeable);\r
+            return true;\r
+        } catch (final Exception ignored) {\r
+            return false;\r
+        }\r
+    }\r
+\r
+    private Closer() {\r
+    }\r
+\r
+}\r
diff --git a/commons-testing-generic/src/main/java/org/apache/commons/testing/net/AvailableServerPortFinder.java b/commons-testing-generic/src/main/java/org/apache/commons/testing/net/AvailableServerPortFinder.java
new file mode 100644 (file)
index 0000000..9a276e9
--- /dev/null
@@ -0,0 +1,155 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache license, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the license for the specific language governing permissions and\r
+ * limitations under the license.\r
+ */\r
+package org.apache.commons.testing.net;\r
+\r
+import java.io.IOException;\r
+import java.net.DatagramSocket;\r
+import java.net.ServerSocket;\r
+import java.util.NoSuchElementException;\r
+import java.util.concurrent.atomic.AtomicInteger;\r
+\r
+import org.apache.commons.testing.Closer;\r
+\r
+/**\r
+ * Finds currently available server ports.\r
+ */\r
+public final class AvailableServerPortFinder {\r
+\r
+    /**\r
+     * The minimum server currentMinPort number for IPv4.\r
+     * Set at 1100 to avoid returning privileged currentMinPort numbers.\r
+     */\r
+    public static final int MIN_PORT_NUMBER = 1100;\r
+\r
+    /**\r
+     * Incremented to the next lowest available port when getNextAvailable() is called.\r
+     */\r
+    private static AtomicInteger currentMinPort = new AtomicInteger(MIN_PORT_NUMBER);\r
+\r
+    /**\r
+     * We'll hold open the lowest port in this process\r
+     * so parallel processes won't use the same block\r
+     * of ports. They'll go up to the next block.\r
+     */\r
+    private static final ServerSocket LOCK;\r
+\r
+    /**\r
+     * The maximum server currentMinPort number for IPv4.\r
+     */\r
+    public static final int MAX_PORT_NUMBER = 65535;\r
+\r
+    static {\r
+        int port = MIN_PORT_NUMBER;\r
+        ServerSocket ss = null;\r
+\r
+        while (ss == null) {\r
+            try {\r
+                ss = new ServerSocket(port);\r
+            } catch (final Exception e) {\r
+                ss = null;\r
+                port += 200;\r
+            }\r
+        }\r
+        LOCK = ss;\r
+        Runtime.getRuntime().addShutdownHook(new Thread() {\r
+            @Override\r
+            public void run() {\r
+                close();\r
+            }\r
+        });\r
+        currentMinPort.set(port + 1);\r
+    }\r
+\r
+    /**\r
+     * Checks to see if a specific port is available.\r
+     *\r
+     * @param port the port number to check for availability\r
+     * @return {@code true} if the port is available, or {@code false} if not\r
+     * @throws IllegalArgumentException is thrown if the port number is out of range\r
+     */\r
+    public static synchronized boolean available(final int port) throws IllegalArgumentException {\r
+        if (port < currentMinPort.get() || port > MAX_PORT_NUMBER) {\r
+            throw new IllegalArgumentException("Invalid start currentMinPort: " + port);\r
+        }\r
+\r
+        ServerSocket ss = null;\r
+        DatagramSocket ds = null;\r
+        try {\r
+            ss = new ServerSocket(port);\r
+            ss.setReuseAddress(true);\r
+            ds = new DatagramSocket(port);\r
+            ds.setReuseAddress(true);\r
+            return true;\r
+        } catch (final IOException e) {\r
+            // Do nothing\r
+        } finally {\r
+            Closer.closeSilently(ds);\r
+            Closer.closeSilently(ss);\r
+        }\r
+\r
+        return false;\r
+    }\r
+\r
+    public static void close() {\r
+        Closer.closeSilently(LOCK);\r
+    }\r
+\r
+    /**\r
+     * Gets the next available port starting at the lowest number. This is the preferred\r
+     * method to use. The port return is immediately marked in use and doesn't rely on the caller actually opening\r
+     * the port.\r
+     *\r
+     * @throws IllegalArgumentException is thrown if the port number is out of range\r
+     * @throws NoSuchElementException if there are no ports available\r
+     * @return the available port\r
+     */\r
+    public static synchronized int getNextAvailable() {\r
+        final int next = getNextAvailable(currentMinPort.get());\r
+        currentMinPort.set(next + 1);\r
+        return next;\r
+    }\r
+\r
+    /**\r
+     * Gets the next available port starting at a given from port.\r
+     *\r
+     * @param fromPort the from port to scan for availability\r
+     * @throws IllegalArgumentException is thrown if the port number is out of range\r
+     * @throws NoSuchElementException if there are no ports available\r
+     * @return the available port\r
+     */\r
+    public static synchronized int getNextAvailable(final int fromPort) {\r
+        if (fromPort < currentMinPort.get() || fromPort > MAX_PORT_NUMBER) {\r
+            throw new IllegalArgumentException("From port number not in valid range: " + fromPort);\r
+        }\r
+\r
+        for (int i = fromPort; i <= MAX_PORT_NUMBER; i++) {\r
+            if (available(i)) {\r
+                return i;\r
+            }\r
+        }\r
+\r
+        throw new NoSuchElementException("Could not find an available port above " + fromPort);\r
+    }\r
+\r
+    /**\r
+     * Creates a new instance.\r
+     */\r
+    private AvailableServerPortFinder() {\r
+        // Do nothing\r
+    }\r
+\r
+}\r
diff --git a/commons-testing-generic/src/test/java/org/apache/commons/testing/CloserTest.java b/commons-testing-generic/src/test/java/org/apache/commons/testing/CloserTest.java
new file mode 100644 (file)
index 0000000..b812292
--- /dev/null
@@ -0,0 +1,57 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache license, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the license for the specific language governing permissions and\r
+ * limitations under the license.\r
+ */\r
+package org.apache.commons.testing;\r
+\r
+import org.junit.Assert;\r
+import org.junit.Test;\r
+\r
+public class CloserTest {\r
+\r
+    static class MarkAutoCloseable implements AutoCloseable {\r
+\r
+        private boolean closed;\r
+\r
+        @Override\r
+        public void close() throws Exception {\r
+            closed = true;\r
+        }\r
+\r
+        boolean isClosed() {\r
+            return closed;\r
+        }\r
+\r
+    }\r
+\r
+    @Test\r
+    public void testCloseAutoCloseable() throws Exception {\r
+        @SuppressWarnings("resource")\r
+        final MarkAutoCloseable closeable = new MarkAutoCloseable();\r
+        Assert.assertFalse(closeable.isClosed());\r
+        Closer.close(closeable);\r
+        Assert.assertTrue(closeable.isClosed());\r
+    }\r
+\r
+    @Test\r
+    public void testCloseSlientlyAutoCloseable() {\r
+        @SuppressWarnings("resource")\r
+        final MarkAutoCloseable closeable = new MarkAutoCloseable();\r
+        Assert.assertFalse(closeable.isClosed());\r
+        Closer.closeSilently(closeable);\r
+        Assert.assertTrue(closeable.isClosed());\r
+    }\r
+\r
+}\r
diff --git a/commons-testing-generic/src/test/java/org/apache/commons/testing/net/AvailableServerPortFinderTest.java b/commons-testing-generic/src/test/java/org/apache/commons/testing/net/AvailableServerPortFinderTest.java
new file mode 100644 (file)
index 0000000..d1dde88
--- /dev/null
@@ -0,0 +1,30 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache license, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the license for the specific language governing permissions and\r
+ * limitations under the license.\r
+ */\r
+\r
+package org.apache.commons.testing.net;\r
+\r
+import org.junit.Assert;\r
+import org.junit.Test;\r
+\r
+public class AvailableServerPortFinderTest {\r
+\r
+    @Test\r
+    public void testGetNextAvailable() {\r
+        Assert.assertTrue(AvailableServerPortFinder.getNextAvailable() > 0);\r
+    }\r
+\r
+}\r
diff --git a/commons-testing-junit4-mongodb/pom.xml b/commons-testing-junit4-mongodb/pom.xml
new file mode 100644 (file)
index 0000000..da8e5a7
--- /dev/null
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!--\r
+\r
+  Licensed to the Apache Software Foundation (ASF) under one\r
+  or more contributor license agreements. See the NOTICE file\r
+  distributed with this work for additional information\r
+  regarding copyright ownership. The ASF licenses this file\r
+  to you under the Apache License, Version 2.0 (the\r
+  "License"); you may not use this file except in compliance\r
+  with the License. You may obtain a copy of the License at\r
+\r
+  http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+  Unless required by applicable law or agreed to in writing, software\r
+  distributed under the License is distributed on an "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+  See the License for the specific language governing permissions and\r
+  limitations under the License.\r
+\r
+-->\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+  <modelVersion>4.0.0</modelVersion>\r
+\r
+  <parent>\r
+    <groupId>org.apache.commons</groupId>\r
+    <artifactId>commons-testing-parent</artifactId>\r
+    <version>1.0.0-SNAPSHOT</version>\r
+    <relativePath>../</relativePath>\r
+  </parent>\r
+\r
+  <artifactId>commons-testing-junit4-mongodb</artifactId>\r
+  <packaging>jar</packaging>\r
+\r
+  <name>Apache Commons Testing for JUnit4 and MongoDB</name>\r
+  <description>Apache Commons Testing for JUnit4 and MongoDB</description>\r
+\r
+  <properties>\r
+    <testingParentDir>${basedir}/..</testingParentDir>\r
+    <commons.osgi.symbolicName>org.apache.commons.testing.junit4.mongodb.mongodb.mongodb</commons.osgi.symbolicName>\r
+  </properties>\r
+\r
+  <build>\r
+    <plugins>\r
+      <plugin>\r
+        <groupId>org.apache.felix</groupId>\r
+        <artifactId>maven-bundle-plugin</artifactId>\r
+        <configuration>\r
+          <instructions>\r
+            <Bundle-SymbolicName>org.apache.commons.testing.junit4.mongodb.mongodb.mongodb</Bundle-SymbolicName>\r
+            <Automatic-Module-Name>org.apache.commons.testing.junit4.mongodb.mongodb.mongodb</Automatic-Module-Name>\r
+          </instructions>\r
+        </configuration>\r
+      </plugin>\r
+    </plugins>\r
+  </build>\r
+\r
+  <distributionManagement>\r
+    <site>\r
+      <id>commonstesting-junit4-site</id>\r
+      <url>scm:svn:${commons.scmPubUrl}/junit4/</url>\r
+    </site>\r
+  </distributionManagement>\r
+\r
+  <dependencies>\r
+    <dependency>\r
+      <groupId>org.apache.commons</groupId>\r
+      <artifactId>commons-testing-junit4</artifactId>\r
+      <version>${project.version}</version>\r
+    </dependency>\r
+    <dependency>\r
+      <groupId>org.mongodb</groupId>\r
+      <artifactId>mongodb-driver</artifactId>\r
+    </dependency>\r
+    <dependency>\r
+      <groupId>org.mongodb</groupId>\r
+      <artifactId>bson</artifactId>\r
+    </dependency>\r
+    <dependency>\r
+      <groupId>de.flapdoodle.embed</groupId>\r
+      <artifactId>de.flapdoodle.embed.mongo</artifactId>\r
+    </dependency>\r
+  </dependencies>\r
+\r
+  <reporting>\r
+    <plugins>\r
+      <plugin>\r
+        <groupId>org.apache.maven.plugins</groupId>\r
+        <artifactId>maven-checkstyle-plugin</artifactId>\r
+        <version>${checkstyle.plugin.version}</version>\r
+        <configuration>\r
+          <configLocation>${testingParentDir}/checkstyle.xml</configLocation>\r
+          <suppressionsLocation>${testingParentDir}/checkstyle-suppressions.xml</suppressionsLocation>\r
+          <enableRulesSummary>false</enableRulesSummary>\r
+          <propertyExpansion>basedir=${basedir}</propertyExpansion>\r
+          <propertyExpansion>licensedir=${testingParentDir}/checkstyle-header.txt</propertyExpansion>\r
+        </configuration>\r
+      </plugin>\r
+      <plugin>\r
+        <groupId>org.codehaus.mojo</groupId>\r
+        <artifactId>findbugs-maven-plugin</artifactId>\r
+        <version>${findbugs.plugin.version}</version>\r
+        <configuration>\r
+          <fork>true</fork>\r
+          <jvmArgs>-Duser.language=en</jvmArgs>\r
+          <threshold>Normal</threshold>\r
+          <effort>Default</effort>\r
+          <excludeFilterFile>${testingParentDir}/findbugs-exclude-filter.xml</excludeFilterFile>\r
+        </configuration>\r
+      </plugin>\r
+    </plugins>\r
+  </reporting>\r
+</project>\r
diff --git a/commons-testing-junit4-mongodb/src/main/java/org/apache/commons/testing/junit4/mongodb/MongoDbTestRule.java b/commons-testing-junit4-mongodb/src/main/java/org/apache/commons/testing/junit4/mongodb/MongoDbTestRule.java
new file mode 100644 (file)
index 0000000..9873466
--- /dev/null
@@ -0,0 +1,140 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package org.apache.commons.testing.junit4.mongodb;\r
+\r
+import java.util.Objects;\r
+\r
+import org.junit.rules.TestRule;\r
+import org.junit.runner.Description;\r
+import org.junit.runners.model.Statement;\r
+\r
+import com.mongodb.MongoClient;\r
+\r
+import de.flapdoodle.embed.mongo.MongodExecutable;\r
+import de.flapdoodle.embed.mongo.MongodProcess;\r
+import de.flapdoodle.embed.mongo.MongodStarter;\r
+import de.flapdoodle.embed.mongo.config.MongodConfigBuilder;\r
+import de.flapdoodle.embed.mongo.config.Net;\r
+import de.flapdoodle.embed.mongo.config.Timeout;\r
+import de.flapdoodle.embed.mongo.distribution.Version;\r
+import de.flapdoodle.embed.mongo.distribution.Version.Main;\r
+import de.flapdoodle.embed.process.runtime.Network;\r
+\r
+/**\r
+ * A JUnit test rule to manage a MongoDB embedded instance.\r
+ *\r
+ * @author <a href="mailto:ggregory@rocketsoftware.com">Gary Gregory</a>\r
+ */\r
+public class MongoDbTestRule implements TestRule {\r
+\r
+    private static final Main DEFAULT_MONGODB_VERSION = Version.Main.V3_4;\r
+\r
+    private static final int BUILDER_TIMEOUT_MILLIS = 30000;\r
+\r
+    /**\r
+     * Store MongodStarter (or RuntimeConfig) in a static final field if you want to use artifact store caching (or else disable caching)\r
+     */\r
+    protected static final MongodStarter starter = MongodStarter.getDefaultInstance();\r
+\r
+    public static int getBuilderTimeoutMillis() {\r
+        return BUILDER_TIMEOUT_MILLIS;\r
+    }\r
+\r
+    public static MongodStarter getStarter() {\r
+        return starter;\r
+    }\r
+\r
+    protected final String portSystemPropertyName;\r
+    protected final Main mongoDbVersion;\r
+\r
+    protected MongoClient mongoClient;\r
+    protected MongodExecutable mongodExecutable;\r
+    protected MongodProcess mongodProcess;\r
+\r
+    public MongoDbTestRule(final String portSystemPropertyName) {\r
+        this(portSystemPropertyName, DEFAULT_MONGODB_VERSION);\r
+    }\r
+\r
+    public MongoDbTestRule(final String portSystemPropertyName, Main mongoDbVersion) {\r
+        this.portSystemPropertyName = Objects.requireNonNull(portSystemPropertyName, "portSystemPropertyName");\r
+        this.mongoDbVersion = mongoDbVersion;\r
+    }\r
+\r
+    @Override\r
+    public Statement apply(final Statement base, final Description description) {\r
+        return new Statement() {\r
+\r
+            @Override\r
+            public void evaluate() throws Throwable {\r
+                final String value = Objects.requireNonNull(System.getProperty(portSystemPropertyName), "System property '" + portSystemPropertyName + "' is null");\r
+                final int port = Integer.parseInt(value);\r
+                mongodExecutable = starter.prepare(\r
+                // @formatter:off\r
+                        new MongodConfigBuilder()\r
+                            .version(mongoDbVersion)\r
+                            .timeout(new Timeout(BUILDER_TIMEOUT_MILLIS))\r
+                            .net(\r
+                                    new Net("localhost", port, Network.localhostIsIPv6()))\r
+                            .build());\r
+                // @formatter:on\r
+                mongodProcess = mongodExecutable.start();\r
+                mongoClient = new MongoClient("localhost", port);\r
+                try {\r
+                    base.evaluate();\r
+                } finally {\r
+                    if (mongodProcess != null) {\r
+                        mongodProcess.stop();\r
+                        mongodProcess = null;\r
+                    }\r
+                    if (mongodExecutable != null) {\r
+                        mongodExecutable.stop();\r
+                        mongodExecutable = null;\r
+                    }\r
+                }\r
+            }\r
+        };\r
+    }\r
+\r
+    public MongoClient getMongoClient() {\r
+        return mongoClient;\r
+    }\r
+\r
+    public MongodExecutable getMongodExecutable() {\r
+        return mongodExecutable;\r
+    }\r
+\r
+    public MongodProcess getMongodProcess() {\r
+        return mongodProcess;\r
+    }\r
+\r
+    @Override\r
+    public String toString() {\r
+        final StringBuilder builder = new StringBuilder();\r
+        builder.append("MongoDbTestRule [portSystemPropertyName=");\r
+        builder.append(portSystemPropertyName);\r
+        builder.append(", mongoClient=");\r
+        builder.append(mongoClient);\r
+        builder.append(", mongodExecutable=");\r
+        builder.append(mongodExecutable);\r
+        builder.append(", mongodProcess=");\r
+        builder.append(mongodProcess);\r
+        builder.append("]");\r
+        return builder.toString();\r
+    }\r
+\r
+}
\ No newline at end of file
diff --git a/commons-testing-junit4-mongodb/src/test/java/org/apache/commons/testing/junit4/mongodb/MongoDbTestRuleTest.java b/commons-testing-junit4-mongodb/src/test/java/org/apache/commons/testing/junit4/mongodb/MongoDbTestRuleTest.java
new file mode 100644 (file)
index 0000000..141286c
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2017-2018 Rocket Software, Inc. All rights reserved.\r
+\r
+package org.apache.commons.testing.junit4.mongodb;\r
+\r
+import org.apache.commons.testing.junit4.RuleChainFactory;\r
+import org.apache.commons.testing.junit4.net.AvailableServerPortSystemPropertyTestRule;\r
+import org.junit.Assert;\r
+import org.junit.ClassRule;\r
+import org.junit.Test;\r
+import org.junit.rules.RuleChain;\r
+\r
+import com.mongodb.client.MongoIterable;\r
+\r
+/**\r
+ * Tests {@link MongoDbTestRule}.\r
+ */\r
+public class MongoDbTestRuleTest {\r
+\r
+    public static final AvailableServerPortSystemPropertyTestRule mongoDbPortTestRule = AvailableServerPortSystemPropertyTestRule\r
+            .create(MongoDbTestRuleTest.class.getName());\r
+\r
+    public static final MongoDbTestRule mongoDbTestRule = new MongoDbTestRule(mongoDbPortTestRule.getName());\r
+\r
+    @ClassRule\r
+    public static RuleChain mongoDbChain = RuleChainFactory.create(mongoDbPortTestRule, mongoDbTestRule);\r
+\r
+    @Test\r
+    public void testAccess() {\r
+        final MongoIterable<String> databaseNames = mongoDbTestRule.getMongoClient().listDatabaseNames();\r
+        Assert.assertNotNull(databaseNames);\r
+        Assert.assertNotNull(databaseNames.first());\r
+    }\r
+\r
+    @Test\r
+    public void testMongoDbRule() {\r
+        Assert.assertNotNull(MongoDbTestRule.getStarter());\r
+        Assert.assertNotNull(mongoDbTestRule);\r
+        Assert.assertNotNull(mongoDbTestRule.getMongoClient());\r
+        Assert.assertNotNull(mongoDbTestRule.getMongodExecutable());\r
+        Assert.assertNotNull(mongoDbTestRule.getMongodProcess());\r
+    }\r
+}\r
index c12d50f..836c935 100644 (file)
 \r
   <dependencies>\r
     <dependency>\r
+      <groupId>org.apache.commons</groupId>\r
+      <artifactId>commons-testing-generic</artifactId>\r
+      <version>${project.version}</version>\r
+    </dependency>\r
+    <dependency>\r
       <groupId>junit</groupId>\r
       <artifactId>junit</artifactId>\r
     </dependency>\r
diff --git a/commons-testing-junit4/src/main/java/org/apache/commons/testing/junit4/RuleChainFactory.java b/commons-testing-junit4/src/main/java/org/apache/commons/testing/junit4/RuleChainFactory.java
new file mode 100644 (file)
index 0000000..b63333f
--- /dev/null
@@ -0,0 +1,45 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache license, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the license for the specific language governing permissions and\r
+ * limitations under the license.\r
+ */\r
+\r
+package org.apache.commons.testing.junit4;\r
+\r
+import org.junit.rules.RuleChain;\r
+import org.junit.rules.TestRule;\r
+\r
+/**\r
+ * Builds JUnit {@link RuleChain}s.\r
+ */\r
+public class RuleChainFactory {\r
+\r
+    /**\r
+     * Creates a {@link RuleChain} where the rules are evaluated in the order you pass in.\r
+     * \r
+     * @param testRules\r
+     *            test rules to evaluate\r
+     * @return a new rule chain.\r
+     */\r
+    public static RuleChain create(final TestRule... testRules) {\r
+        if (testRules == null || testRules.length == 0) {\r
+            return RuleChain.emptyRuleChain();\r
+        }\r
+        RuleChain ruleChain = RuleChain.outerRule(testRules[0]);\r
+        for (int i = 1; i < testRules.length; i++) {\r
+            ruleChain = ruleChain.around(testRules[i]);\r
+        }\r
+        return ruleChain;\r
+    }\r
+}\r
diff --git a/commons-testing-junit4/src/main/java/org/apache/commons/testing/junit4/net/AvailableServerPortSystemPropertyTestRule.java b/commons-testing-junit4/src/main/java/org/apache/commons/testing/junit4/net/AvailableServerPortSystemPropertyTestRule.java
new file mode 100644 (file)
index 0000000..f8db859
--- /dev/null
@@ -0,0 +1,81 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache license, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the license for the specific language governing permissions and\r
+ * limitations under the license.\r
+ */\r
+\r
+package org.apache.commons.testing.junit4.net;\r
+\r
+import org.apache.commons.testing.net.AvailableServerPortFinder;\r
+import org.junit.rules.TestRule;\r
+import org.junit.runner.Description;\r
+import org.junit.runners.model.Statement;\r
+\r
+/**\r
+ * A JUnit TestRule to discover an available port and save it in a system property.\r
+ */\r
+public class AvailableServerPortSystemPropertyTestRule implements TestRule {\r
+\r
+    public static AvailableServerPortSystemPropertyTestRule create(final String name) {\r
+        return new AvailableServerPortSystemPropertyTestRule(name);\r
+    }\r
+\r
+    protected final String name;\r
+    protected int port;\r
+\r
+    protected AvailableServerPortSystemPropertyTestRule(final String name) {\r
+        this.name = name;\r
+    }\r
+\r
+    @Override\r
+    public Statement apply(final Statement base, final Description description) {\r
+        return new Statement() {\r
+\r
+            @Override\r
+            public void evaluate() throws Throwable {\r
+                final String oldValue = System.getProperty(name);\r
+                try {\r
+                    port = AvailableServerPortFinder.getNextAvailable();\r
+                    System.setProperty(name, Integer.toString(port));\r
+                    base.evaluate();\r
+                } finally {\r
+                    // Restore if previously set\r
+                    if (oldValue != null) {\r
+                        System.setProperty(name, oldValue);\r
+                    }\r
+                }\r
+            }\r
+        };\r
+    }\r
+\r
+    public String getName() {\r
+        return name;\r
+    }\r
+\r
+    public int getPort() {\r
+        return port;\r
+    }\r
+\r
+    @Override\r
+    public String toString() {\r
+        final StringBuilder builder = new StringBuilder();\r
+        builder.append("AvailableServerPortSystemPropertyTestRule [name=");\r
+        builder.append(name);\r
+        builder.append(", port=");\r
+        builder.append(port);\r
+        builder.append("]");\r
+        return builder.toString();\r
+    }\r
+\r
+}\r
diff --git a/commons-testing-junit4/src/test/java/org/apache/commons/testing/junit4/net/AvailableServerPortSystemPropertyTestRuleTest.java b/commons-testing-junit4/src/test/java/org/apache/commons/testing/junit4/net/AvailableServerPortSystemPropertyTestRuleTest.java
new file mode 100644 (file)
index 0000000..1a8a9e0
--- /dev/null
@@ -0,0 +1,42 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements. See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache license, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the license for the specific language governing permissions and\r
+ * limitations under the license.\r
+ */\r
+\r
+package org.apache.commons.testing.junit4.net;\r
+\r
+import java.io.IOException;\r
+import java.net.ServerSocket;\r
+\r
+import org.junit.Assert;\r
+import org.junit.Rule;\r
+import org.junit.Test;\r
+\r
+public class AvailableServerPortSystemPropertyTestRuleTest {\r
+\r
+    private static final String NAME = AvailableServerPortSystemPropertyTestRuleTest.class.getName();\r
+\r
+    @Rule\r
+    public AvailableServerPortSystemPropertyTestRule rule = new AvailableServerPortSystemPropertyTestRule(NAME);\r
+\r
+    @Test\r
+    public void test() throws IOException {\r
+        final int port = rule.getPort();\r
+        Assert.assertTrue(port > 0);\r
+        try (final ServerSocket ss = new ServerSocket(port)) {\r
+            // nothing\r
+        }\r
+    }\r
+}\r
diff --git a/pom.xml b/pom.xml
index d3f50ee..909ad78 100644 (file)
--- a/pom.xml
+++ b/pom.xml
       <dependency>\r
         <groupId>junit</groupId>\r
         <artifactId>junit</artifactId>\r
-        <version>4.12</version>\r
+        <version>${junit4.version}</version>\r
       </dependency>\r
       <dependency>\r
         <groupId>org.apache.commons</groupId>\r
         <artifactId>commons-lang3</artifactId>\r
-        <version>3.7</version>\r
+        <version>${commons-lang.version}</version>\r
+      </dependency>\r
+      <dependency>\r
+        <groupId>org.mongodb</groupId>\r
+        <artifactId>mongodb-driver</artifactId>\r
+        <version>${mongodb3.version}</version>\r
+      </dependency>\r
+      <dependency>\r
+        <groupId>org.mongodb</groupId>\r
+        <artifactId>bson</artifactId>\r
+        <version>${mongodb3.version}</version>\r
+      </dependency>\r
+      <dependency>\r
+        <groupId>de.flapdoodle.embed</groupId>\r
+        <artifactId>de.flapdoodle.embed.mongo</artifactId>\r
+        <version>${embed.mongodb}</version>\r
       </dependency>\r
     </dependencies>\r
   </dependencyManagement>\r
     <commons.scmPubCheckoutDirectory>site-content</commons.scmPubCheckoutDirectory>\r
     <commons.encoding>utf-8</commons.encoding>\r
 \r
-    <!-- Override clirr version to be able to build the site on Java 7 -->\r
+    <!-- Plugin versions -->\r
     <commons.clirr.version>2.8</commons.clirr.version>\r
     <checkstyle.plugin.version>3.0.0</checkstyle.plugin.version>\r
     <findbugs.plugin.version>3.0.5</findbugs.plugin.version>\r
+    <embed.mongodb>2.0.1</embed.mongodb>\r
 \r
+    <!-- Component versions -->\r
+    <mongodb2.version>2.14.3</mongodb2.version>\r
+    <mongodb3.version>3.6.1</mongodb3.version>\r
+    <junit4.version>4.12</junit4.version>\r
+    <commons-lang.version>3.7</commons-lang.version>\r
   </properties>\r
 \r
 \r
     <module>commons-testing-generic</module>\r
     <module>commons-testing-junit4</module>\r
     <!--<module>commons-testing-junit5</module> -->\r
-    <!--<module>commons-testing-junit4-mongodb</module> -->\r
+    <module>commons-testing-junit4-mongodb</module>\r
   </modules>\r
 \r
   <profiles>\r