diff --git a/src/main/java/com/github/joelittlejohn/embedmongo/port/PortUnavailableException.java b/src/main/java/com/github/joelittlejohn/embedmongo/PortUtils.java similarity index 54% rename from src/main/java/com/github/joelittlejohn/embedmongo/port/PortUnavailableException.java rename to src/main/java/com/github/joelittlejohn/embedmongo/PortUtils.java index 2add5af195cd7bb91bd2afac802edc8fd38fad54..3e94b259e472545d8dd447f4a7b8ca3dd800f0f8 100644 --- a/src/main/java/com/github/joelittlejohn/embedmongo/port/PortUnavailableException.java +++ b/src/main/java/com/github/joelittlejohn/embedmongo/PortUtils.java @@ -13,13 +13,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.github.joelittlejohn.embedmongo.port; +package com.github.joelittlejohn.embedmongo; -/** - * Represents exceptional state when given port is not available. - */ -public class PortUnavailableException extends RuntimeException { - public PortUnavailableException(int port, Throwable cause) { - super("Port " + port + " is not available", cause); +import java.io.IOException; +import java.net.ServerSocket; + +public final class PortUtils { + + private PortUtils() { } + + public static int allocateRandomPort() { + try { + ServerSocket server = new ServerSocket(0); + int port = server.getLocalPort(); + server.close(); + return port; + } catch (IOException e) { + throw new RuntimeException("Failed to acquire a random free port", e); + } + } + } diff --git a/src/main/java/com/github/joelittlejohn/embedmongo/StartEmbeddedMongoMojo.java b/src/main/java/com/github/joelittlejohn/embedmongo/StartEmbeddedMongoMojo.java index 2600afbf8a28ca2101561c5a252d01930a345101..ea9f3be12eb922df352413908cbddbc1ae94a8dc 100644 --- a/src/main/java/com/github/joelittlejohn/embedmongo/StartEmbeddedMongoMojo.java +++ b/src/main/java/com/github/joelittlejohn/embedmongo/StartEmbeddedMongoMojo.java @@ -28,14 +28,12 @@ import java.net.SocketAddress; import java.net.URI; import java.net.UnknownHostException; import java.util.List; -import java.util.Properties; import java.util.concurrent.TimeUnit; -import com.github.joelittlejohn.embedmongo.port.PortHelper; -import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.project.MavenProject; import com.github.joelittlejohn.embedmongo.log.Loggers; import com.github.joelittlejohn.embedmongo.log.Loggers.LoggingStyle; @@ -56,7 +54,6 @@ import de.flapdoodle.embed.process.distribution.GenericVersion; import de.flapdoodle.embed.process.distribution.IVersion; import de.flapdoodle.embed.process.exceptions.DistributionException; import de.flapdoodle.embed.process.runtime.Network; -import org.apache.maven.project.MavenProject; /** * When invoked, this goal starts an instance of mongo. The required binaries @@ -81,8 +78,11 @@ public class StartEmbeddedMongoMojo extends AbstractMojo { private int port; /** - * Random port should be used for MongoDB instead of the one specified by {@code port}. - * + * Whether a random free port should be used for MongoDB instead of the one + * specified by {@code port}. If {@code randomPort} is {@code true}, the + * random port chosen will be available in the Maven project property + * {@code embedmongo.port}. + * * @parameter expression="${embedmongo.randomPort}" default-value="false" * @since 0.1.8 */ @@ -149,13 +149,13 @@ public class StartEmbeddedMongoMojo extends AbstractMojo { * @parameter expression="${embedmongo.logFile}" * @since 0.1.7 */ - private String logFile = Loggers.DEFAULT_LOG_FILE_NAME; + private final String logFile = Loggers.DEFAULT_LOG_FILE_NAME; /** * @parameter expression="${embedmongo.logFileEncoding}" * @since 0.1.7 */ - private String logFileEncoding = Loggers.DEFAULT_LOG_FILE_ENCODING; + private final String logFileEncoding = Loggers.DEFAULT_LOG_FILE_ENCODING; /** * The proxy user to be used when downloading MongoDB @@ -175,21 +175,12 @@ public class StartEmbeddedMongoMojo extends AbstractMojo { /** * The maven project. - * + * * @parameter expression="${project}" * @readonly */ private MavenProject project; - /** - * The Maven Session Object for setting allocated port to session's user properties. - * - * @parameter expression="${session}" - * @readonly - */ - private MavenSession session; - - @Override @SuppressWarnings("unchecked") public void execute() throws MojoExecutionException, MojoFailureException { @@ -205,10 +196,12 @@ public class StartEmbeddedMongoMojo extends AbstractMojo { .defaults(Command.MongoD) .processOutput(getOutputConfig()) .build(); + if (randomPort) { - port = new PortHelper().allocateRandomPort(); + port = PortUtils.allocateRandomPort(); } - savePortToSessionUserProperties(); + savePortToProjectProperties(); + MongodConfig mongoConfig = new MongodConfig(getVersion(), new Net(bindIp, port, Network.localhostIsIPv6()), new Storage(getDataDirectory(), null, 0), @@ -241,22 +234,12 @@ public class StartEmbeddedMongoMojo extends AbstractMojo { } /** - * Saves port to the {@link MavenSession#userProperties} to provide client with ability to retrieve port - * later in integration-test-phase via {@link PortHelper#getMongoPort(String)} method. - * Port is saved as a property {@code MONGO_PORT_PROPERTY + "." + artifactId} where {@code artifactId} - * is id of project artifact where the integration tests are run. - * The {@code artifactId} suffix is necessary because concurrent executions of {@code embedmongo-maven-plugin} - * cannot share the same property. - * <p> - * {@code userProperties} seems to be the only way how to propagate property to the forked JVM run - * started by failsafe plugin. - * </p> + * Saves port to the {@link MavenProject#getProperties()} (with the property + * name {@code embedmongo.port}) to allow others (plugins, tests, etc) to + * find the randomly allocated port. */ - private void savePortToSessionUserProperties() { - final String portKey = PortHelper.MONGO_PORT_PROPERTY + "." + project.getArtifactId(); - final String portValue = Integer.toString(port); - final Properties userProperties = session.getUserProperties(); - userProperties.setProperty(portKey, portValue); + private void savePortToProjectProperties() { + project.getProperties().put("embedmongo.port", String.valueOf(port)); } private ProcessOutput getOutputConfig() throws MojoFailureException { @@ -281,6 +264,7 @@ public class StartEmbeddedMongoMojo extends AbstractMojo { // Add authenticator with proxyUser and proxyPassword if (proxyUser != null && proxyPassword != null) { Authenticator.setDefault(new Authenticator() { + @Override public PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(proxyUser, proxyPassword.toCharArray()); } diff --git a/src/main/java/com/github/joelittlejohn/embedmongo/port/PortHelper.java b/src/main/java/com/github/joelittlejohn/embedmongo/port/PortHelper.java deleted file mode 100644 index 303059879d3749690d9fed5e0c8afb52c86a2941..0000000000000000000000000000000000000000 --- a/src/main/java/com/github/joelittlejohn/embedmongo/port/PortHelper.java +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright © 2012 Joe Littlejohn - * - * 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 com.github.joelittlejohn.embedmongo.port; - -import org.codehaus.plexus.util.StringUtils; - -import java.io.IOException; -import java.net.ServerSocket; - -/** - * Port helper for common operations with port. - * <p> - * It can : - * <ul> - * <li>allocate random free port - Inspired by - * <a href="https://github.com/sonatype/port-allocator-maven-plugin/blob/master/src/main/java/org/sonatype/plugins/portallocator/PortAllocatorMojo.java"> - * PortAllocatorMojo</a>.</li> - * <li>Return port already allocated by invoking start goal of {@code embedmongo-maven-plugin}</li> - * </ul> - -* </p> - */ -public class PortHelper { - - public static final String MONGO_PORT_PROPERTY = "embedmongo.port"; - - - /** - * Finds port where the mongodb started in previous phase by {@code embedmongo-maven-plugin} should be running. - * This assumes that embedmongo-maven-plugin' goal start has already been invoked for {@code artifactId} - * and allocates port properly. - * - * @param artifactId maven artifact id of module for which the port set by {@code embedmongo-maven-plugin} should be found. - * @return port of mongodb for running integration tests of given {@code artifactId} - */ - public static int getMongoPort(String artifactId) { - String portProperty; - if (artifactId == null || artifactId.length() == 0) { - throw new IllegalArgumentException("maven artifactId has to be specified to find port for proper maven module."); - } else { - portProperty = MONGO_PORT_PROPERTY + "." + artifactId; - } - final String port = System.getProperty(portProperty); - if (StringUtils.isEmpty(port)) { - throw new IllegalStateException("No mongo port has been set by embedmongo maven plugin via system property '" - + portProperty + "'!\n Check plugin configuration and make sure that mongoDb is started before" - + " you are trying to access its port."); - } - return Integer.valueOf(port); - } - - - /** - * Allocates new free random port. - * - * <p> - * This implementation allocate random free port and closes it immediately. - * In some (hopefully) rare situations the port may be occupied in the meantime between calling this method - * and using returned port on client side. - * </p> - * @return random free port - */ - public int allocateRandomPort() { - return allocate(0); - } - - - //--------------------------------------------------- HELPER METHODS ----------------------------------------------- - - private static int allocate(int portNumber) { - ServerSocket server; - try { - server = new ServerSocket(portNumber); - } catch (IOException e) { - throw new PortUnavailableException(portNumber, e); - } - - portNumber = server.getLocalPort(); - try { - server.close(); - } catch (IOException e) { - throw new RuntimeException("Unable to release port " + portNumber, e); - } - return portNumber; - } -} diff --git a/src/test/java/com/github/joelittlejohn/embedmongo/port/PortHelperTest.java b/src/test/java/com/github/joelittlejohn/embedmongo/PortUtilsTest.java similarity index 82% rename from src/test/java/com/github/joelittlejohn/embedmongo/port/PortHelperTest.java rename to src/test/java/com/github/joelittlejohn/embedmongo/PortUtilsTest.java index aa406cc27b83831b9cf0c420544ca414ea8a0b5a..fcb9198a7d2208641ac6ffd93a77c4a9bb870885 100644 --- a/src/test/java/com/github/joelittlejohn/embedmongo/port/PortHelperTest.java +++ b/src/test/java/com/github/joelittlejohn/embedmongo/PortUtilsTest.java @@ -13,10 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.github.joelittlejohn.embedmongo.port; - -import org.junit.After; -import org.junit.Test; +package com.github.joelittlejohn.embedmongo; import java.io.IOException; import java.net.ServerSocket; @@ -26,9 +23,11 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -public class PortHelperTest { +import org.junit.After; +import org.junit.Test; + +public class PortUtilsTest { - private final PortHelper portHelper = new PortHelper(); private final ScheduledExecutorService testPooledExecutor = Executors.newScheduledThreadPool(20); @After @@ -37,8 +36,10 @@ public class PortHelperTest { } /** - * This test executes method {@link com.github.joelittlejohn.embedmongo.port.PortHelper#allocateRandomPort()} many times - * concurrently to make sure that port allocation works correctly under stress. + * This test executes method + * {@link com.github.joelittlejohn.embedmongo.PortUtils#allocateRandomPort()} + * many times concurrently to make sure that port allocation works correctly + * under stress. */ @Test public void testAllocateRandomPort() throws Exception { @@ -50,9 +51,9 @@ public class PortHelperTest { public void run() { int port = -1; try { - port = portHelper.allocateRandomPort(); + port = PortUtils.allocateRandomPort(); new ServerSocket(port); - // port has been bind successfully + // port has been bound successfully } catch (IOException e) { throw new RuntimeException("Port " + port + " cannot be bind!"); } finally { diff --git a/src/test/resources/randomport/pom.xml b/src/test/resources/randomport/pom.xml index 96762ac2e77477fa0fe042449747f2729f0d91ea..614010f09c1ad158c38a9fcaec444496921c6b99 100644 --- a/src/test/resources/randomport/pom.xml +++ b/src/test/resources/randomport/pom.xml @@ -39,6 +39,7 @@ </goals> <configuration> <port>37017</port> + <randomPort>true</randomPort> <databaseDirectory>/tmp/mongotest</databaseDirectory> <logging>console</logging> <version>v2.2.0</version> @@ -63,6 +64,11 @@ <goal>integration-test</goal> <goal>verify</goal> </goals> + <configuration> + <systemPropertyVariables> + <mongo.port>${embedmongo.port}</mongo.port> + </systemPropertyVariables> + </configuration> </execution> </executions> </plugin> diff --git a/src/test/resources/randomport/src/test/java/com/github/joelittlejohn/embedmongo/MongoIT.java b/src/test/resources/randomport/src/test/java/com/github/joelittlejohn/embedmongo/MongoIT.java index 8fe6fcc5064cb2d54acca8deb7feffce4b4972c5..a1424d35cc3055788fefbcc2d743730e3bf7bd35 100644 --- a/src/test/resources/randomport/src/test/java/com/github/joelittlejohn/embedmongo/MongoIT.java +++ b/src/test/resources/randomport/src/test/java/com/github/joelittlejohn/embedmongo/MongoIT.java @@ -15,19 +15,18 @@ */ package com.github.joelittlejohn.embedmongo; -import com.github.joelittlejohn.embedmongo.port.PortHelper; +import java.net.Socket; + import org.junit.After; import org.junit.Test; -import java.net.Socket; - public class MongoIT { private Socket mongoSocket; @Test public void testConnectMongo() throws Exception { - mongoSocket = new Socket("127.0.0.1", PortHelper.getMongoPort("embedmongo-maven-plugin-random-port-test")); + mongoSocket = new Socket("127.0.0.1", Integer.valueOf(System.getProperty("mongo.port"))); } @After