diff --git a/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java b/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java
index 64ea31fac53..57571c4d0c0 100644
--- a/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java
+++ b/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java
@@ -67,14 +67,46 @@ import org.eclipse.jetty.util.log.Logger;
/**
* Helper class to test the Jetty Distribution
.
* API can change without any further notice.
+ * Usage:
+ *
+ * // Create the distribution.
+ * String jettyVersion = "9.4.14.v20181114";
+ * DistributionTester distribution = DistributionTester.Builder.newInstance()
+ * .jettyVersion(jettyVersion)
+ * .jettyBase(Paths.get("demo-base"))
+ * .build();
+ *
+ * // The first run initializes the Jetty Base.
+ * try (DistributionTester.Run run1 = distribution.start("--create-startd", "--add-to-start=http2c,jsp,deploy"))
+ * {
+ * assertTrue(run1.awaitFor(5, TimeUnit.SECONDS));
+ * assertEquals(0, run1.getExitValue());
+ *
+ * // Install a web application.
+ * File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + jettyVersion);
+ * distribution.installWarFile(war, "test");
+ *
+ * // The second run starts the distribution.
+ * int port = 9090;
+ * try (DistributionTester.Run run = distribution.start("jetty.http.port=" + port))
+ * {
+ * // Wait for Jetty to be fully started.
+ * assertTrue(run1.awaitConsoleLogsFor("Started @", 20, TimeUnit.SECONDS));
+ *
+ * // Make a HTTP request to the web application.
+ * HttpClient client = new HttpClient();
+ * client.start();
+ * ContentResponse response = client.GET("http://localhost:" + port + "/test/index.jsp");
+ * assertEquals(HttpStatus.OK_200, response.getStatus());
+ * }
+ * }
+ *
*/
public class DistributionTester
{
private static final Logger LOGGER = Log.getLogger(DistributionTester.class);
private Config config;
- private List consoleStreamers = new ArrayList<>();
- private List logs = new ArrayList<>();
private DistributionTester(Config config)
{
@@ -82,7 +114,7 @@ public class DistributionTester
}
/**
- * Starts the instance with the given arguments
+ * Starts the distribution with the given arguments
*
* @param args arguments to use to start the distribution
*/
@@ -92,16 +124,12 @@ public class DistributionTester
}
/**
- * Start the instance with the arguments
+ * Start the distribution with the arguments
*
* @param args arguments to use to start the distribution
*/
public DistributionTester.Run start(List args) throws Exception
{
- // do we want to be sure and use "--testing-mode" to not break surefire with a System.exit ???
-
- logs.clear();
-
List commands = new ArrayList<>();
commands.add(getJavaExecutable());
commands.add("-jar");
@@ -116,13 +144,14 @@ public class DistributionTester
pbCmd.directory(workingDir);
Process process = pbCmd.start();
- consoleStreamers.add(startPump("STDOUT", process.getInputStream()));
- consoleStreamers.add(startPump("STDERR", process.getErrorStream()));
-
return new Run(process);
}
- public int randomPort() throws IOException
+ /**
+ * @return a free port chosen by the OS that can be used to listen to
+ * @throws IOException if a free port is not available
+ */
+ public int freePort() throws IOException
{
try (ServerSocket server = new ServerSocket())
{
@@ -132,6 +161,13 @@ public class DistributionTester
}
}
+ /**
+ * Installs in {@code ${jetty.base}/webapps} the given war file under the given context path.
+ *
+ * @param warFile the war file to install
+ * @param context the context path
+ * @throws IOException if the installation fails
+ */
public void installWarFile(File warFile, String context) throws IOException
{
//webapps
@@ -142,8 +178,11 @@ public class DistributionTester
}
/**
+ * Resolves an artifact given its Maven coordinates.
+ *
* @param coordinates :[:[:]]:
* @return the artifact
+ * @see #installWarFile(File, String)
*/
public File resolveArtifact(String coordinates) throws ArtifactResolutionException
{
@@ -191,14 +230,6 @@ public class DistributionTester
return "java";
}
- private ConsoleStreamer startPump(String mode, InputStream stream)
- {
- ConsoleStreamer pump = new ConsoleStreamer(stream);
- Thread thread = new Thread(pump, "ConsoleStreamer/" + mode);
- thread.start();
- return pump;
- }
-
private void unzip(File zipFile, File output) throws IOException
{
try (InputStream fileInputStream = Files.newInputStream(zipFile.toPath());
@@ -293,11 +324,6 @@ public class DistributionTester
return session;
}
- public Path getJettyHome()
- {
- return config.jettyHome;
- }
-
private static class Config
{
private Path jettyBase;
@@ -309,51 +335,14 @@ public class DistributionTester
@Override
public String toString()
{
- return "Config{" + "jettyBase=" + jettyBase + ", jettyHome=" + jettyHome + ", jettyVersion='" + jettyVersion
- + '\'' + ", mavenLocalRepository='" + mavenLocalRepository + '\'' + ", mavenRemoteRepositories="
- + mavenRemoteRepositories + '}';
- }
- }
-
- /**
- * Simple streamer for the console output from a Process
- */
- private class ConsoleStreamer implements Runnable
- {
- private final BufferedReader reader;
- private volatile boolean stop;
-
- public ConsoleStreamer(InputStream stream)
- {
- this.reader = new BufferedReader(new InputStreamReader(stream));
- }
-
- @Override
- public void run()
- {
- try
- {
- String line;
- while ((line = reader.readLine()) != null && !stop)
- {
- LOGGER.info("{}", line);
- DistributionTester.this.logs.add(line);
- }
- }
- catch (IOException ignore)
- {
- // ignore
- }
- finally
- {
- IO.close(reader);
- }
- }
-
- public void stop()
- {
- stop = true;
- IO.close(reader);
+ return String.format("%s@%x{jettyBase=%s, jettyHome=%s, jettyVersion=%s, mavenLocalRepository=%s, mavenRemoteRepositories=%s}",
+ getClass().getSimpleName(),
+ hashCode(),
+ jettyBase,
+ jettyHome,
+ jettyVersion,
+ mavenLocalRepository,
+ mavenRemoteRepositories);
}
}
@@ -377,17 +366,32 @@ public class DistributionTester
}
}
- public class Run implements Closeable
+ /**
+ * A distribution run wraps the process that started the Jetty distribution.
+ */
+ public static class Run implements Closeable
{
private final Process process;
+ private final List consoleStreamers = new ArrayList<>();
+ private final List logs = new ArrayList<>();
- public Run(Process process)
+ private Run(Process process)
{
this.process = process;
+ consoleStreamers.add(startPump("STDOUT", process.getInputStream()));
+ consoleStreamers.add(startPump("STDERR", process.getErrorStream()));
+ }
+
+ private ConsoleStreamer startPump(String mode, InputStream stream)
+ {
+ ConsoleStreamer pump = new ConsoleStreamer(stream);
+ Thread thread = new Thread(pump, "ConsoleStreamer/" + mode);
+ thread.start();
+ return pump;
}
/**
- * Waits for the given time for the distribution to stop.
+ * Waits for the given time for the distribution process to stop.
*
* @param time the time to wait
* @param unit the unit of time
@@ -402,13 +406,17 @@ public class DistributionTester
return result;
}
- public int getExitValue()
+ /**
+ * @return the distribution process exit value
+ * @throws IllegalThreadStateException if the distribution process is not terminated yet
+ */
+ public int getExitValue() throws IllegalThreadStateException
{
return process.exitValue();
}
/**
- * Stops the distribution.
+ * Stops the distribution process.
*
* @see #awaitFor(long, TimeUnit)
*/
@@ -418,6 +426,9 @@ public class DistributionTester
stopConsoleStreamers();
}
+ /**
+ * Forcibly destroys the distribution process.
+ */
public void destroy()
{
process.destroyForcibly();
@@ -430,9 +441,7 @@ public class DistributionTester
}
/**
- * Method to use in finally block of a test and when using @After in a unit test.
- * if running, it stops the distribution.
- * Cleanup JettyBase and JettyHome directories
+ * @see #destroy()
*/
@Override
public void close()
@@ -440,6 +449,15 @@ public class DistributionTester
destroy();
}
+ /**
+ * Awaits the console logs to contain the given text, for the given amount of time.
+ *
+ * @param txt the text that must be present in the console logs
+ * @param time the time to wait
+ * @param unit the unit of time
+ * @return true if the text was found, false if the timeout elapsed
+ * @throws InterruptedException if the wait is interrupted
+ */
public boolean awaitConsoleLogsFor(String txt, long time, TimeUnit unit) throws InterruptedException
{
long end = System.nanoTime() + unit.toNanos(time);
@@ -452,6 +470,48 @@ public class DistributionTester
}
return false;
}
+
+ /**
+ * Simple streamer for the console output from a Process
+ */
+ private class ConsoleStreamer implements Runnable
+ {
+ private final BufferedReader reader;
+ private volatile boolean stop;
+
+ public ConsoleStreamer(InputStream stream)
+ {
+ this.reader = new BufferedReader(new InputStreamReader(stream));
+ }
+
+ @Override
+ public void run()
+ {
+ try
+ {
+ String line;
+ while ((line = reader.readLine()) != null && !stop)
+ {
+ LOGGER.info("{}", line);
+ logs.add(line);
+ }
+ }
+ catch (IOException ignore)
+ {
+ // ignore
+ }
+ finally
+ {
+ IO.close(reader);
+ }
+ }
+
+ public void stop()
+ {
+ stop = true;
+ IO.close(reader);
+ }
+ }
}
public static class Builder
diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DistributionTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DistributionTests.java
index 131336218ae..11718fed86f 100644
--- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DistributionTests.java
+++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DistributionTests.java
@@ -53,7 +53,7 @@ public class DistributionTests extends AbstractDistributionTest
assertTrue(run1.awaitFor(5, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
- int port = distribution.randomPort();
+ int port = distribution.freePort();
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS));
@@ -90,7 +90,7 @@ public class DistributionTests extends AbstractDistributionTest
File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "test");
- int port = distribution.randomPort();
+ int port = distribution.freePort();
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS));
@@ -127,7 +127,7 @@ public class DistributionTests extends AbstractDistributionTest
File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "test");
- int port = distribution.randomPort();
+ int port = distribution.freePort();
String[] args2 = {
"--jpms",
"jetty.http.port=" + port
@@ -167,7 +167,7 @@ public class DistributionTests extends AbstractDistributionTest
File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "test");
- int port = distribution.randomPort();
+ int port = distribution.freePort();
try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS));
@@ -192,11 +192,8 @@ public class DistributionTests extends AbstractDistributionTest
.mavenLocalRepository(System.getProperty("mavenRepoPath"))
.build();
- int port = distribution.randomPort();
- String[] args1 = {
- "jetty.http.port=" + port
- };
- try (DistributionTester.Run run1 = distribution.start(args1))
+ int port = distribution.freePort();
+ try (DistributionTester.Run run1 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run1.awaitConsoleLogsFor("Started @", 20, TimeUnit.SECONDS));