From 972dc015bbeecd608b4177c6fda70713efd4df99 Mon Sep 17 00:00:00 2001 From: olivier lamy Date: Mon, 24 Sep 2018 19:24:29 +1000 Subject: [PATCH 01/14] sugar syntax changes Signed-off-by: olivier lamy --- tests/pom.xml | 1 + .../eclipse/jetty/test/support/JettyDistro.java | 15 ++++++--------- .../jetty/test/support/TestableJettyServer.java | 4 ++-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/pom.xml b/tests/pom.xml index 6eac047ab2f..56a34b1eb7e 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -67,5 +67,6 @@ test-quickstart test-jmx test-http-client-transport + test-modules diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/JettyDistro.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/JettyDistro.java index b523e9bf398..299be625e9c 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/JettyDistro.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/JettyDistro.java @@ -56,6 +56,7 @@ import org.eclipse.jetty.toolchain.test.JAR; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.PathAssert; import org.eclipse.jetty.toolchain.test.jupiter.WorkDir; +import org.junit.jupiter.api.Assertions; /** @@ -315,19 +316,15 @@ public class JettyDistro // The actual jetty-distribution-${version} directory is under this directory. // Lets find it. - File subdirs[] = distroUnpackDir.listFiles(new FileFilter() - { - @Override - public boolean accept(File path) + File subdirs[] = distroUnpackDir.listFiles( path -> { if (!path.isDirectory()) { return false; } - return path.getName().startsWith(artifactName + "-"); } - }); + ); if (subdirs.length == 0) { @@ -550,7 +547,7 @@ public class JettyDistro if (cmdLine == null || !cmdLine.contains("XmlConfiguration")) { - fail("Unable to get Jetty command line"); + Assertions.fail( "Unable to get Jetty command line"); } // Need to breakdown commandline into parts, as spaces in command line will cause failures. @@ -595,7 +592,7 @@ public class JettyDistro catch (InterruptedException e) { pid.destroy(); - fail("Unable to get required information within time limit"); + Assertions.fail( "Unable to get required information within time limit"); } } @@ -804,7 +801,7 @@ public class JettyDistro } } - fail("Unable to find java bin"); + Assertions.fail( "Unable to find java bin"); return "java"; } diff --git a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java index d47cc4380db..a612e6592e7 100644 --- a/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java +++ b/tests/test-integration/src/test/java/org/eclipse/jetty/test/support/TestableJettyServer.java @@ -49,7 +49,7 @@ import org.junit.jupiter.api.Disabled; public class TestableJettyServer { private List _xmlConfigurations; - private final Map _properties = new HashMap(); + private final Map _properties = new HashMap<>(); private Server _server; private int _serverPort; private String _scheme = HttpScheme.HTTP.asString(); @@ -60,7 +60,7 @@ public class TestableJettyServer public TestableJettyServer() throws IOException { - _xmlConfigurations = new ArrayList(); + _xmlConfigurations = new ArrayList<>(); Properties properties = new Properties(); /* Establish Popular Directories */ From 6a42d3ba0833deb98a85ef841df843cec0eeac1b Mon Sep 17 00:00:00 2001 From: olivier lamy Date: Mon, 24 Sep 2018 19:24:49 +1000 Subject: [PATCH 02/14] Issue #3343 add api/tools to test jetty distribution Signed-off-by: olivier lamy --- tests/pom.xml | 2 +- tests/test-distribution/pom.xml | 91 +++ .../distribution/DistributionTester.java | 605 ++++++++++++++++++ .../tests/distribution/HttpModuleTests.java | 67 ++ .../src/test/resources/index.html | 1 + .../src/test/resources/static_content.xml | 11 + tests/test-webapps/pom.xml | 3 +- tests/test-webapps/test-simple-webapp/pom.xml | 16 + .../src/main/webapp/WEB-INF/web.xml | 10 + .../src/main/webapp/index.jsp | 5 + 10 files changed, 809 insertions(+), 2 deletions(-) create mode 100644 tests/test-distribution/pom.xml create mode 100644 tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java create mode 100644 tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java create mode 100644 tests/test-distribution/src/test/resources/index.html create mode 100644 tests/test-distribution/src/test/resources/static_content.xml create mode 100644 tests/test-webapps/test-simple-webapp/pom.xml create mode 100644 tests/test-webapps/test-simple-webapp/src/main/webapp/WEB-INF/web.xml create mode 100644 tests/test-webapps/test-simple-webapp/src/main/webapp/index.jsp diff --git a/tests/pom.xml b/tests/pom.xml index 56a34b1eb7e..4078a8dce7d 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -67,6 +67,6 @@ test-quickstart test-jmx test-http-client-transport - test-modules + test-distribution diff --git a/tests/test-distribution/pom.xml b/tests/test-distribution/pom.xml new file mode 100644 index 00000000000..bc9e78b6124 --- /dev/null +++ b/tests/test-distribution/pom.xml @@ -0,0 +1,91 @@ + + + tests-parent + org.eclipse.jetty.tests + 9.4.15-SNAPSHOT + + 4.0.0 + + test-distribution + jar + + + ${project.build.outputDirectory}/jetty_home + 1.3.1 + + + + + org.eclipse.jetty + jetty-client + ${project.version} + + + org.eclipse.jetty + jetty-distribution + ${project.version} + zip + + + org.eclipse.jetty + jetty-start + ${project.version} + + + org.slf4j + slf4j-simple + ${slf4j.version} + + + org.apache.maven + maven-resolver-provider + 3.6.0 + + + org.apache.maven + maven-artifact + 3.6.0 + + + org.apache.maven.resolver + maven-resolver-connector-basic + ${mavenResolver.version} + + + org.apache.maven.resolver + maven-resolver-transport-file + ${mavenResolver.version} + + + org.apache.maven.resolver + maven-resolver-transport-http + ${mavenResolver.version} + + + org.junit.jupiter + junit-jupiter-api + ${junit.version} + + + org.eclipse.jetty.tests + test-simple-webapp + ${project.version} + war + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${settings.localRepository} + ${project.version} + + + + + + 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 new file mode 100644 index 00000000000..6fa371a3230 --- /dev/null +++ b/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java @@ -0,0 +1,605 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.tests.distribution; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.apache.commons.lang3.StringUtils; +import org.apache.maven.repository.internal.MavenRepositorySystemUtils; +import org.codehaus.plexus.util.FileUtils; +import org.codehaus.plexus.util.IOUtil; +import org.eclipse.aether.AbstractRepositoryListener; +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.RepositoryEvent; +import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory; +import org.eclipse.aether.impl.DefaultServiceLocator; +import org.eclipse.aether.repository.LocalRepository; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.resolution.ArtifactRequest; +import org.eclipse.aether.resolution.ArtifactResolutionException; +import org.eclipse.aether.resolution.ArtifactResult; +import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; +import org.eclipse.aether.spi.connector.transport.TransporterFactory; +import org.eclipse.aether.transfer.AbstractTransferListener; +import org.eclipse.aether.transport.file.FileTransporterFactory; +import org.eclipse.aether.transport.http.HttpTransporterFactory; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.start.FS; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; + +/** + *

+ * Please note this class is use for Jetty Distribution testing. + * So API can change without any further notice. + *

+ */ +public class DistributionTester { + + private Process pid; + + private URI baseUri; + + private String jmxUrl; + + private long waitStartTime = 60; + + private long maxWaitToStop = 60000; + + private TimeUnit timeUnit = TimeUnit.SECONDS; + + private Path jettyBase; + + private File jettyHomeDir; + + private String jettyVersion; + private String jettyHome; + private String mavenLocalRepository = System.getProperty("user.home") + "/.m2/repository"; + + private static final Logger LOGGER = Log.getLogger(DistributionTester.class); + + private List logs = new ArrayList<>(); + + private HttpClient httpClient; + + private DistributionTester(Path jettyBase) + throws Exception { + this.jettyBase = jettyBase; + } + + private DistributionTester initialise() throws Exception { + + if (StringUtils.isNotEmpty(jettyHome)) { + jettyHomeDir = Paths.get(jettyHome).toFile(); + } else { + // 9.4.14.v20181114 9.4.15-SNAPSHOT + jettyHomeDir = resolveDistribution(this.jettyVersion); + } + + this.httpClient = new HttpClient(); + httpClient.start(); + + return this; + + } + + public void start() throws Exception { + start(Collections.emptyList()); + } + + public void start(String... args) throws Exception { + start(Arrays.asList(args)); + } + + public void 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(getJavaBin()); + + commands.add("-Djetty.home=" + jettyHomeDir.getAbsolutePath()); + commands.add("-Djetty.base=" + jettyBase.toAbsolutePath().toString()); + + commands.add("-jar"); + commands.add(jettyHomeDir.getAbsolutePath() + "/start.jar"); + commands.add("jetty.http.port=0"); + + commands.addAll(args); + + ProcessBuilder pbCmd = new ProcessBuilder(commands); + pbCmd.directory(jettyHomeDir); + + LOGGER.info("Executing: {}", commands); + LOGGER.info("Working Dir: {}", jettyHomeDir.getAbsolutePath()); + + pbCmd = new ProcessBuilder(commands); + pid = pbCmd.start(); + + ConsoleParser parser = new ConsoleParser(); + List jmxList = parser.newPattern("JMX Remote URL: (.*)", 0); + // Started ServerConnector@76f2bbc1{HTTP/1.1,[http/1.1]}{0.0.0.0:50214} + List connList = + parser.newPattern("[A-Za-z]*Connector@.*\\{.*\\}\\{(.*)\\:([0-9]*)}", 1); + + startPump("STDOUT", parser, this.pid.getInputStream()); + startPump("STDERR", parser, this.pid.getErrorStream()); + + try { + long start = System.currentTimeMillis(); + parser.waitForDone(this.waitStartTime, this.timeUnit); + LOGGER.info("wait start {}", System.currentTimeMillis() - start); + + + if (!jmxList.isEmpty()) { + this.jmxUrl = jmxList.get(0)[0]; + LOGGER.info("## Found JMX connector at {}", this.jmxUrl); + } + + if (!connList.isEmpty()) { + String[] params = connList.get(0); + if (params.length == 2) { + this.baseUri = URI.create("http://localhost:" + params[1]); + } + LOGGER.info("## Found Jetty connector at port: {}", params[1]); + } + + } catch (InterruptedException e) { + pid.destroy(); + } + + } + + + private void startPump(String mode, ConsoleParser parser, InputStream inputStream) { + ConsoleStreamer pump = new ConsoleStreamer(mode, inputStream); + pump.setParser(parser); + Thread thread = new Thread(pump, "ConsoleStreamer/" + mode); + thread.start(); + } + + /** + * Simple streamer for the console output from a Process + */ + private class ConsoleStreamer + implements Runnable { + private String mode; + + private BufferedReader reader; + + private ConsoleParser parser; + + public ConsoleStreamer(String mode, InputStream is) { + this.mode = mode; + this.reader = new BufferedReader(new InputStreamReader(is)); + } + + public void setParser(ConsoleParser connector) { + this.parser = connector; + } + + @Override + public void run() { + String line; + try { + while ((line = reader.readLine()) != (null)) { + if (parser != null) { + parser.parse(line); + } + // using LOGGER generates too long lines.. + //LOGGER.info("[{}] {}",mode, line); + System.out.println("[" + mode + "] " + line); + DistributionTester.this.logs.add(line); + } + } catch (IOException ignore) { + // ignore + } finally { + IO.close(reader); + } + } + } + + private static class ConsoleParser { + private List patterns = new ArrayList<>(); + + private CountDownLatch latch; + + private int count; + + public List newPattern(String exp, int cnt) { + ConsolePattern pat = new ConsolePattern(exp, cnt); + patterns.add(pat); + count += cnt; + return pat.getMatches(); + } + + public void parse(String line) { + for (ConsolePattern pat : patterns) { + Matcher mat = pat.getMatcher(line); + if (mat.find()) { + int num = 0, count = mat.groupCount(); + String[] match = new String[count]; + while (num++ < count) { + match[num - 1] = mat.group(num); + } + pat.getMatches().add(match); + + if (pat.getCount() > 0) { + getLatch().countDown(); + } + } + } + } + + public void waitForDone(long timeout, TimeUnit unit) + throws InterruptedException { + getLatch().await(timeout, unit); + } + + private CountDownLatch getLatch() { + synchronized (this) { + if (latch == null) { + latch = new CountDownLatch(count); + } + } + return latch; + } + } + + private static class ConsolePattern { + private Pattern pattern; + + private List matches; + + private int count; + + ConsolePattern(String exp, int cnt) { + pattern = Pattern.compile(exp); + matches = new ArrayList<>(); + count = cnt; + } + + public Matcher getMatcher(String line) { + return pattern.matcher(line); + } + + public List getMatches() { + return matches; + } + + public int getCount() { + return count; + } + } + + + public void installWarFile(File warFile, String context) throws IOException { + //webapps + Path webapps = Paths.get(jettyBase.toString(),"webapps", context); + if (!Files.exists(webapps)) { + Files.createDirectories(webapps); + } + unzip(warFile, webapps.toFile()); + } + + //--------------------------------------- + // Assert methods + //--------------------------------------- + + public void assertLogsContains(String txt){ + assertTrue(logs.stream().filter(s -> StringUtils.contains(s, txt)).count()>0); + } + + + public void assertUrlStatus(String url, int expectedStatus){ + try { + ContentResponse contentResponse = httpClient.GET(getBaseUri() + url); + int status = contentResponse.getStatus(); + assertEquals(expectedStatus, status, () -> "status not " + expectedStatus + " but " + status); + } catch (InterruptedException|ExecutionException|TimeoutException e) { + fail(e.getMessage(),e); + } + } + + public void assertUrlContains(String url, String content){ + try { + ContentResponse contentResponse = httpClient.GET(getBaseUri() + url); + String contentResponseStr = contentResponse.getContentAsString(); + assertTrue(StringUtils.contains(contentResponseStr, content), () -> "content not containing '" + content + "'"); + } catch (InterruptedException|ExecutionException|TimeoutException e) { + fail(e.getMessage(),e); + } + } + + + private void unzip(File zipFile, File output) throws IOException { + try (InputStream fileInputStream = Files.newInputStream(zipFile.toPath()); + ZipInputStream zipInputStream = new ZipInputStream(fileInputStream)) + { + ZipEntry entry = zipInputStream.getNextEntry(); + while (entry != null) { + if (entry.isDirectory()) { + File dir = new File(output, entry.getName()); + if (!Files.exists(dir.toPath())) { + Files.createDirectories(dir.toPath()); + } + } else { + // Read zipEntry and write to a file. + File file = new File(output, entry.getName()); + if(!Files.exists(file.getParentFile().toPath())){ + Files.createDirectories(file.getParentFile().toPath()); + } + try (OutputStream outputStream = Files.newOutputStream(file.toPath())) { + IOUtil.copy(zipInputStream,outputStream); + } + } + // Get next entry + entry = zipInputStream.getNextEntry(); + } + } + } + + //--------------------------------------- + // Maven Utils methods + //--------------------------------------- + + /** + * + * @param coordinates :[:[:]]: + * @return the artifact + * @throws ArtifactResolutionException + */ + public File resolveArtifact(String coordinates) throws ArtifactResolutionException { + RepositorySystem repositorySystem = newRepositorySystem(); + + Artifact artifact = new DefaultArtifact(coordinates); + + RepositorySystemSession session = newRepositorySystemSession(repositorySystem); + + ArtifactRequest artifactRequest = new ArtifactRequest(); + artifactRequest.setArtifact(artifact); + artifactRequest.setRepositories(newRepositories(repositorySystem, newRepositorySystemSession(repositorySystem))); + ArtifactResult artifactResult = repositorySystem.resolveArtifact(session, artifactRequest); + + artifact = artifactResult.getArtifact(); + return artifact.getFile(); + } + + private File resolveDistribution(String version) throws Exception { + File artifactFile = resolveArtifact("org.eclipse.jetty:jetty-distribution:zip:" + version); + + // create tmp directory to unzip distribution + Path tmp = Files.createTempDirectory("jetty_test"); + tmp.toFile().deleteOnExit(); + + unzip(artifactFile, tmp.toFile()); + return new File(tmp.toFile(), "jetty-distribution-" + version); + } + + + + private RepositorySystem newRepositorySystem() { + DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator(); + locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class); + locator.addService(TransporterFactory.class, FileTransporterFactory.class); + locator.addService(TransporterFactory.class, HttpTransporterFactory.class); + + locator.setErrorHandler(new DefaultServiceLocator.ErrorHandler() { + @Override + public void serviceCreationFailed(Class type, Class impl, Throwable exception) { + LOGGER.warn("Service creation failed for {} implementation {}: {}", + type, impl, exception.getMessage(), exception); + } + }); + + return locator.getService(RepositorySystem.class); + } + + private List newRepositories(RepositorySystem system, RepositorySystemSession session) { + return new ArrayList<>(Collections.singletonList(newCentralRepository())); + } + + private DefaultRepositorySystemSession newRepositorySystemSession(RepositorySystem system) { + DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); + + + LocalRepository localRepo = new LocalRepository(mavenLocalRepository); + session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo)); + + session.setTransferListener(new LogTransferListener()); + session.setRepositoryListener(new LogRepositoryListener()); + + return session; + } + + private static class LogTransferListener extends AbstractTransferListener { + // no op + } + + private static class LogRepositoryListener extends AbstractRepositoryListener { + + @Override + public void artifactDownloaded(RepositoryEvent event) { + LOGGER.debug("distribution downloaded to {}", event.getFile()); + } + + @Override + public void artifactResolved(RepositoryEvent event) { + LOGGER.debug("distribution resolved to {}", event.getFile()); + } + } + + + private static RemoteRepository newCentralRepository() { + return new RemoteRepository.Builder("central", "default", "https://repo.maven.apache.org/maven2/").build(); + } + + + private String getJavaBin() { + String javaexes[] = new String[]{"java", "java.exe"}; + + File javaHomeDir = new File(System.getProperty("java.home")); + for (String javaexe : javaexes) { + File javabin = new File(javaHomeDir, FS.separators("bin/" + javaexe)); + if (javabin.exists() && javabin.isFile()) { + return javabin.getAbsolutePath(); + } + } + return "java"; + } + + public void stop() + throws Exception { + + long start = System.currentTimeMillis(); + while (this.pid.isAlive()&&(System.currentTimeMillis()-start + + + /scratch + + + + true + + + \ No newline at end of file diff --git a/tests/test-webapps/pom.xml b/tests/test-webapps/pom.xml index 64c4f6ee87c..e4d1e2219d3 100644 --- a/tests/test-webapps/pom.xml +++ b/tests/test-webapps/pom.xml @@ -39,5 +39,6 @@ test-jaas-webapp test-jndi-webapp test-http2-webapp + test-simple-webapp - + \ No newline at end of file diff --git a/tests/test-webapps/test-simple-webapp/pom.xml b/tests/test-webapps/test-simple-webapp/pom.xml new file mode 100644 index 00000000000..846a05cf2d0 --- /dev/null +++ b/tests/test-webapps/test-simple-webapp/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + + org.eclipse.jetty.tests + test-webapps-parent + 9.4.15-SNAPSHOT + + + test-simple-webapp + + war + + Test :: Jetty Test Simple Webapp + + diff --git a/tests/test-webapps/test-simple-webapp/src/main/webapp/WEB-INF/web.xml b/tests/test-webapps/test-simple-webapp/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..4905321a949 --- /dev/null +++ b/tests/test-webapps/test-simple-webapp/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,10 @@ + + + + Very Simple Web Application + diff --git a/tests/test-webapps/test-simple-webapp/src/main/webapp/index.jsp b/tests/test-webapps/test-simple-webapp/src/main/webapp/index.jsp new file mode 100644 index 00000000000..c38169bb958 --- /dev/null +++ b/tests/test-webapps/test-simple-webapp/src/main/webapp/index.jsp @@ -0,0 +1,5 @@ + + +

Hello World!

+ + From d9bfece0cc58229021fb70a476c22fbd6781bc96 Mon Sep 17 00:00:00 2001 From: olivier lamy Date: Mon, 11 Feb 2019 12:59:14 +1000 Subject: [PATCH 03/14] rename class, add more javadoc Signed-off-by: olivier lamy --- ...ionTester.java => DistributionRunner.java} | 152 +++++++++++++++--- .../tests/distribution/HttpModuleTests.java | 36 ++--- 2 files changed, 145 insertions(+), 43 deletions(-) rename tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/{DistributionTester.java => DistributionRunner.java} (81%) 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/DistributionRunner.java similarity index 81% rename from tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java rename to tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionRunner.java index 6fa371a3230..bb22e1d67c8 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/DistributionRunner.java @@ -35,7 +35,9 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -81,7 +83,7 @@ import org.eclipse.jetty.util.log.Logger; * So API can change without any further notice. *

*/ -public class DistributionTester { +public class DistributionRunner { private Process pid; @@ -103,23 +105,29 @@ public class DistributionTester { private String jettyHome; private String mavenLocalRepository = System.getProperty("user.home") + "/.m2/repository"; - private static final Logger LOGGER = Log.getLogger(DistributionTester.class); + private static final Logger LOGGER = Log.getLogger(DistributionRunner.class); private List logs = new ArrayList<>(); private HttpClient httpClient; - private DistributionTester(Path jettyBase) + private Map mavenRemoteRepositories = new HashMap<>(); + + private DistributionRunner(Path jettyBase) throws Exception { this.jettyBase = jettyBase; } - private DistributionTester initialise() throws Exception { + /** + * + * @return DistributionRunner setup jettyHome directory and start httpClient. + * @throws Exception + */ + private DistributionRunner initialise() throws Exception { if (StringUtils.isNotEmpty(jettyHome)) { jettyHomeDir = Paths.get(jettyHome).toFile(); } else { - // 9.4.14.v20181114 9.4.15-SNAPSHOT jettyHomeDir = resolveDistribution(this.jettyVersion); } @@ -130,14 +138,28 @@ public class DistributionTester { } + /** + * start the instance with no arguments + * @throws Exception + */ public void start() throws Exception { start(Collections.emptyList()); } + /** + * start the instance with the arguments + * @param args arguments to use to start the distribution + * @throws Exception + */ public void start(String... args) throws Exception { start(Arrays.asList(args)); } + /** + * start the instance with the arguments + * @param args arguments to use to start the distribution + * @throws Exception + */ public void start(List args) throws Exception { @@ -239,7 +261,7 @@ public class DistributionTester { // using LOGGER generates too long lines.. //LOGGER.info("[{}] {}",mode, line); System.out.println("[" + mode + "] " + line); - DistributionTester.this.logs.add(line); + DistributionRunner.this.logs.add(line); } } catch (IOException ignore) { // ignore @@ -446,7 +468,16 @@ public class DistributionTester { } private List newRepositories(RepositorySystem system, RepositorySystemSession session) { - return new ArrayList<>(Collections.singletonList(newCentralRepository())); + List remoteRepositories = new ArrayList<>(this.mavenRemoteRepositories.size()+1); + this.mavenRemoteRepositories.entrySet().stream().forEach(stringStringEntry -> { + remoteRepositories.add(new RemoteRepository.Builder(stringStringEntry.getKey(), "default", stringStringEntry.getValue()).build()); + }); + remoteRepositories.add(newCentralRepository()); + return remoteRepositories; + } + + private static RemoteRepository newCentralRepository() { + return new RemoteRepository.Builder("central", "default", "https://repo.maven.apache.org/maven2/").build(); } private DefaultRepositorySystemSession newRepositorySystemSession(RepositorySystem system) { @@ -480,10 +511,6 @@ public class DistributionTester { } - private static RemoteRepository newCentralRepository() { - return new RemoteRepository.Builder("central", "default", "https://repo.maven.apache.org/maven2/").build(); - } - private String getJavaBin() { String javaexes[] = new String[]{"java", "java.exe"}; @@ -498,6 +525,7 @@ public class DistributionTester { return "java"; } + ? public void stop() throws Exception { @@ -514,12 +542,25 @@ public class DistributionTester { LOGGER.info("still alive so force destroy process"); this.pid.destroyForcibly(); } + if(httpClient!=null&&httpClient.isRunning()){ + httpClient.stop(); + } } + /** + * remove the content from JettyBase directory + * @throws IOException + */ public void cleanJettyBase() throws IOException { FileUtils.cleanDirectory(this.jettyBase.toFile()); } + /** + * 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 + * @throws Exception + */ public void cleanup() throws Exception { stop(); if (Files.exists(this.jettyBase)) { @@ -530,17 +571,28 @@ public class DistributionTester { // cleanup jetty distribution IO.delete(this.jettyHomeDir); } - } + /** + * + * @return the directory used as JettyBase + */ public Path getJettyBase() { return jettyBase; } + /** + * + * @return the {@link URI} to use to access the jetty instance (random port has been detected) + */ public URI getBaseUri() { return baseUri; } + /** + * + * @return the connection to use to access JMX (if configured) + */ public String getJmxUrl() { return jmxUrl; } @@ -564,42 +616,104 @@ public class DistributionTester { private long waitStartTime = 60; + private long maxWaitToStop = 60000; + + private Map mavenRemoteRepositories = new HashMap<>(); + + /** + * + * @param jettyVersion the version to use (format: 9.4.14.v20181114 9.4.15-SNAPSHOT). + * The distribution will be downloaded from local repository or remote + * @return the {@link Builder} + */ public Builder jettyVersion(String jettyVersion) { this.jettyVersion = jettyVersion; return this; } + /** + * + * @param jettyHome Path to the local exploded jetty distribution + * if configured the jettyVersion parameter will not be used + * @return the {@link Builder} + */ public Builder jettyHome(String jettyHome) { this.jettyHome = jettyHome; return this; } + /** + * + * @param mavenLocalRepository Path to the local maven repository + * @return the {@link Builder} + */ public Builder mavenLocalRepository(String mavenLocalRepository) { this.mavenLocalRepository = mavenLocalRepository; return this; } + /** + * + * @param waitStartTime the maximum time in seconds to wait the start of the distribution + * @return the {@link Builder} + */ public Builder waitStartTime(long waitStartTime) { this.waitStartTime = waitStartTime; return this; } + /** + * + * @param maxWaitToStop the maximum time in seconds to wait after stop the distribution + * process before forcing the stop. + * @return the {@link Builder} + */ + public Builder maxWaitToStop(long maxWaitToStop) { + this.maxWaitToStop = maxWaitToStop; + return this; + } + + /** + * + * If needed to resolve JettyDistribtion from another Maven remote repositories + * @param id the id + * @param url the Maven remote repository url + * @return the {@link Builder} + */ + public Builder addRemoteRepository(String id, String url) { + this.mavenRemoteRepositories.put(id, url); + return this; + } + + /** + * + * @return an empty instance of {@link Builder} + */ public static Builder newInstance() { return new Builder(); } - public DistributionTester build() + /** + * + * @return a new configured instance of {@link DistributionRunner} + * @throws Exception + */ + public DistributionRunner build() throws Exception { if (jettyBase == null) { this.jettyBase = Files.createTempDirectory("jetty_base_test"); this.jettyBase.toFile().deleteOnExit(); } - DistributionTester distributionTester = new DistributionTester(jettyBase); - distributionTester.jettyVersion = jettyVersion; - distributionTester.jettyHome = jettyHome; - distributionTester.mavenLocalRepository = mavenLocalRepository; - distributionTester.waitStartTime = waitStartTime; - return distributionTester.initialise(); + DistributionRunner distributionRunner = new DistributionRunner(jettyBase); + distributionRunner.jettyVersion = jettyVersion; + distributionRunner.jettyHome = jettyHome; + distributionRunner.mavenLocalRepository = mavenLocalRepository; + distributionRunner.waitStartTime = waitStartTime; + distributionRunner.maxWaitToStop = maxWaitToStop; + if(!this.mavenRemoteRepositories.isEmpty()) { + distributionRunner.mavenRemoteRepositories.putAll(this.mavenRemoteRepositories); + } + return distributionRunner.initialise(); } } } diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java index 2cc3a334b3b..44aebfd597a 100644 --- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java @@ -18,49 +18,37 @@ package org.eclipse.jetty.tests.distribution; -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.api.ContentResponse; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.io.File; -import java.net.URI; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.Collections; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class HttpModuleTests { @Test public void http_module() throws Exception { - // System.getProperty( "jetty_home" ) - DistributionTester distributionTester = DistributionTester.Builder.newInstance() // + DistributionRunner distributionRunner = DistributionRunner.Builder.newInstance() // .jettyVersion(System.getProperty("jetty_version")) // .mavenLocalRepository(System.getProperty("mavenRepoPath")) // .waitStartTime(30) // .build(); // try { - distributionTester.start("--create-startd", "--approve-all-licenses", "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,jmx-remote,servlet,servlets"); - distributionTester.stop(); + distributionRunner.start("--create-startd", "--approve-all-licenses", "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,jmx-remote,servlet,servlets"); + distributionRunner.stop(); - Path jettyBase = distributionTester.getJettyBase(); + Path jettyBase = distributionRunner.getJettyBase(); - File war = distributionTester.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + System.getProperty("jetty_version")); - distributionTester.installWarFile(war, "test"); - distributionTester.start(); - distributionTester.assertLogsContains("Started @"); - distributionTester.assertUrlStatus("/test/index.jsp", 200); - distributionTester.assertUrlContains("/test/index.jsp", "Hello"); + File war = distributionRunner.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + System.getProperty("jetty_version")); + distributionRunner.installWarFile(war, "test"); + distributionRunner.start(); + distributionRunner.assertLogsContains("Started @"); + distributionRunner.assertUrlStatus("/test/index.jsp", 200); + distributionRunner.assertUrlContains("/test/index.jsp", "Hello"); } finally { - distributionTester.stop(); - distributionTester.cleanup(); + distributionRunner.stop(); + distributionRunner.cleanup(); } } From 85fd1db963d72f8322a049bb5d97edffd9ffc1a8 Mon Sep 17 00:00:00 2001 From: olivier lamy Date: Mon, 11 Feb 2019 15:55:27 +1000 Subject: [PATCH 04/14] add jpms test Signed-off-by: olivier lamy --- .../distribution/DistributionRunner.java | 11 ++-- .../distribution/JpmsActivatedTests.java | 59 +++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java diff --git a/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionRunner.java b/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionRunner.java index bb22e1d67c8..c0f4d66f45e 100644 --- a/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionRunner.java +++ b/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionRunner.java @@ -525,7 +525,10 @@ public class DistributionRunner { return "java"; } - ? + /** + * Stop the distribution + * @throws Exception + */ public void stop() throws Exception { @@ -542,9 +545,6 @@ public class DistributionRunner { LOGGER.info("still alive so force destroy process"); this.pid.destroyForcibly(); } - if(httpClient!=null&&httpClient.isRunning()){ - httpClient.stop(); - } } /** @@ -563,6 +563,9 @@ public class DistributionRunner { */ public void cleanup() throws Exception { stop(); + if(httpClient!=null&&httpClient.isRunning()){ + httpClient.stop(); + } if (Files.exists(this.jettyBase)) { // cleanup jetty base IO.delete(this.jettyBase.toFile()); diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java new file mode 100644 index 00000000000..6ef7548ca77 --- /dev/null +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java @@ -0,0 +1,59 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.tests.distribution; + +import java.io.File; +import java.nio.file.Path; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnJre; +import org.junit.jupiter.api.condition.EnabledOnJre; +import org.junit.jupiter.api.condition.JRE; + +public class JpmsActivatedTests +{ + @Test + @DisabledOnJre(JRE.JAVA_8) + public void jpms_activated() throws Exception + { + DistributionRunner distributionRunner = DistributionRunner.Builder.newInstance() // + .jettyVersion(System.getProperty("jetty_version")) // + .mavenLocalRepository(System.getProperty("mavenRepoPath")) // + .waitStartTime(30) // + .build(); // + try + { + distributionRunner.start("--create-startd", "--approve-all-licenses", "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,jmx-remote,servlet,servlets"); + distributionRunner.stop(); + + Path jettyBase = distributionRunner.getJettyBase(); + + File war = distributionRunner.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + System.getProperty("jetty_version")); + distributionRunner.installWarFile(war, "test"); + distributionRunner.start("--jpms"); + distributionRunner.assertLogsContains("Started @"); + distributionRunner.assertUrlStatus("/test/index.jsp", 200); + distributionRunner.assertUrlContains("/test/index.jsp", "Hello"); + } finally { + distributionRunner.stop(); + distributionRunner.cleanup(); + } + + } +} From dd4041dae1f5c979d0a49479ecdc911aebbb3da9 Mon Sep 17 00:00:00 2001 From: olivier lamy Date: Mon, 11 Feb 2019 17:14:27 +1000 Subject: [PATCH 05/14] cleanup not used variable Signed-off-by: olivier lamy --- .../org/eclipse/jetty/tests/distribution/HttpModuleTests.java | 2 -- .../eclipse/jetty/tests/distribution/JpmsActivatedTests.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java index 44aebfd597a..0afef157e2b 100644 --- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java @@ -38,8 +38,6 @@ public class HttpModuleTests distributionRunner.start("--create-startd", "--approve-all-licenses", "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,jmx-remote,servlet,servlets"); distributionRunner.stop(); - Path jettyBase = distributionRunner.getJettyBase(); - File war = distributionRunner.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + System.getProperty("jetty_version")); distributionRunner.installWarFile(war, "test"); distributionRunner.start(); diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java index 6ef7548ca77..cd7964cd6cf 100644 --- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java @@ -42,8 +42,6 @@ public class JpmsActivatedTests distributionRunner.start("--create-startd", "--approve-all-licenses", "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,jmx-remote,servlet,servlets"); distributionRunner.stop(); - Path jettyBase = distributionRunner.getJettyBase(); - File war = distributionRunner.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + System.getProperty("jetty_version")); distributionRunner.installWarFile(war, "test"); distributionRunner.start("--jpms"); From 214bc03270ccb96f5a43388de463b208629a8a23 Mon Sep 17 00:00:00 2001 From: olivier lamy Date: Mon, 11 Feb 2019 19:08:57 +1000 Subject: [PATCH 06/14] DistributionTester is definitely a better name Signed-off-by: olivier lamy --- ...ionRunner.java => DistributionTester.java} | 32 +++++++++---------- .../tests/distribution/HttpModuleTests.java | 23 +++++++------ .../distribution/JpmsActivatedTests.java | 24 +++++++------- 3 files changed, 38 insertions(+), 41 deletions(-) rename tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/{DistributionRunner.java => DistributionTester.java} (96%) diff --git a/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionRunner.java b/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java similarity index 96% rename from tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionRunner.java rename to tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java index c0f4d66f45e..31f74f46e0d 100644 --- a/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionRunner.java +++ b/tests/test-distribution/src/main/java/org/eclipse/jetty/tests/distribution/DistributionTester.java @@ -83,7 +83,7 @@ import org.eclipse.jetty.util.log.Logger; * So API can change without any further notice. *

*/ -public class DistributionRunner { +public class DistributionTester { private Process pid; @@ -105,7 +105,7 @@ public class DistributionRunner { private String jettyHome; private String mavenLocalRepository = System.getProperty("user.home") + "/.m2/repository"; - private static final Logger LOGGER = Log.getLogger(DistributionRunner.class); + private static final Logger LOGGER = Log.getLogger(DistributionTester.class); private List logs = new ArrayList<>(); @@ -113,17 +113,17 @@ public class DistributionRunner { private Map mavenRemoteRepositories = new HashMap<>(); - private DistributionRunner(Path jettyBase) + private DistributionTester(Path jettyBase) throws Exception { this.jettyBase = jettyBase; } /** * - * @return DistributionRunner setup jettyHome directory and start httpClient. + * @return DistributionTester setup jettyHome directory and start httpClient. * @throws Exception */ - private DistributionRunner initialise() throws Exception { + private DistributionTester initialise() throws Exception { if (StringUtils.isNotEmpty(jettyHome)) { jettyHomeDir = Paths.get(jettyHome).toFile(); @@ -261,7 +261,7 @@ public class DistributionRunner { // using LOGGER generates too long lines.. //LOGGER.info("[{}] {}",mode, line); System.out.println("[" + mode + "] " + line); - DistributionRunner.this.logs.add(line); + DistributionTester.this.logs.add(line); } } catch (IOException ignore) { // ignore @@ -698,25 +698,25 @@ public class DistributionRunner { /** * - * @return a new configured instance of {@link DistributionRunner} + * @return a new configured instance of {@link DistributionTester} * @throws Exception */ - public DistributionRunner build() + public DistributionTester build() throws Exception { if (jettyBase == null) { this.jettyBase = Files.createTempDirectory("jetty_base_test"); this.jettyBase.toFile().deleteOnExit(); } - DistributionRunner distributionRunner = new DistributionRunner(jettyBase); - distributionRunner.jettyVersion = jettyVersion; - distributionRunner.jettyHome = jettyHome; - distributionRunner.mavenLocalRepository = mavenLocalRepository; - distributionRunner.waitStartTime = waitStartTime; - distributionRunner.maxWaitToStop = maxWaitToStop; + DistributionTester distributionTester = new DistributionTester(jettyBase); + distributionTester.jettyVersion = jettyVersion; + distributionTester.jettyHome = jettyHome; + distributionTester.mavenLocalRepository = mavenLocalRepository; + distributionTester.waitStartTime = waitStartTime; + distributionTester.maxWaitToStop = maxWaitToStop; if(!this.mavenRemoteRepositories.isEmpty()) { - distributionRunner.mavenRemoteRepositories.putAll(this.mavenRemoteRepositories); + distributionTester.mavenRemoteRepositories.putAll(this.mavenRemoteRepositories); } - return distributionRunner.initialise(); + return distributionTester.initialise(); } } } diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java index 0afef157e2b..08c3ae187a1 100644 --- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java @@ -21,32 +21,31 @@ package org.eclipse.jetty.tests.distribution; import org.junit.jupiter.api.Test; import java.io.File; -import java.nio.file.Path; public class HttpModuleTests { @Test public void http_module() throws Exception { - DistributionRunner distributionRunner = DistributionRunner.Builder.newInstance() // + DistributionTester distributionTester = DistributionTester.Builder.newInstance() // .jettyVersion(System.getProperty("jetty_version")) // .mavenLocalRepository(System.getProperty("mavenRepoPath")) // .waitStartTime(30) // .build(); // try { - distributionRunner.start("--create-startd", "--approve-all-licenses", "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,jmx-remote,servlet,servlets"); - distributionRunner.stop(); + distributionTester.start("--create-startd", "--approve-all-licenses", "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,jmx-remote,servlet,servlets"); + distributionTester.stop(); - File war = distributionRunner.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + System.getProperty("jetty_version")); - distributionRunner.installWarFile(war, "test"); - distributionRunner.start(); - distributionRunner.assertLogsContains("Started @"); - distributionRunner.assertUrlStatus("/test/index.jsp", 200); - distributionRunner.assertUrlContains("/test/index.jsp", "Hello"); + File war = distributionTester.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + System.getProperty("jetty_version")); + distributionTester.installWarFile(war, "test"); + distributionTester.start(); + distributionTester.assertLogsContains("Started @"); + distributionTester.assertUrlStatus("/test/index.jsp", 200); + distributionTester.assertUrlContains("/test/index.jsp", "Hello"); } finally { - distributionRunner.stop(); - distributionRunner.cleanup(); + distributionTester.stop(); + distributionTester.cleanup(); } } diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java index cd7964cd6cf..2462626db7f 100644 --- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java @@ -19,11 +19,9 @@ package org.eclipse.jetty.tests.distribution; import java.io.File; -import java.nio.file.Path; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnJre; -import org.junit.jupiter.api.condition.EnabledOnJre; import org.junit.jupiter.api.condition.JRE; public class JpmsActivatedTests @@ -32,25 +30,25 @@ public class JpmsActivatedTests @DisabledOnJre(JRE.JAVA_8) public void jpms_activated() throws Exception { - DistributionRunner distributionRunner = DistributionRunner.Builder.newInstance() // + DistributionTester distributionTester = DistributionTester.Builder.newInstance() // .jettyVersion(System.getProperty("jetty_version")) // .mavenLocalRepository(System.getProperty("mavenRepoPath")) // .waitStartTime(30) // .build(); // try { - distributionRunner.start("--create-startd", "--approve-all-licenses", "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,jmx-remote,servlet,servlets"); - distributionRunner.stop(); + distributionTester.start("--create-startd", "--approve-all-licenses", "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,jmx-remote,servlet,servlets"); + distributionTester.stop(); - File war = distributionRunner.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + System.getProperty("jetty_version")); - distributionRunner.installWarFile(war, "test"); - distributionRunner.start("--jpms"); - distributionRunner.assertLogsContains("Started @"); - distributionRunner.assertUrlStatus("/test/index.jsp", 200); - distributionRunner.assertUrlContains("/test/index.jsp", "Hello"); + File war = distributionTester.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + System.getProperty("jetty_version")); + distributionTester.installWarFile(war, "test"); + distributionTester.start("--jpms"); + distributionTester.assertLogsContains("Started @"); + distributionTester.assertUrlStatus("/test/index.jsp", 200); + distributionTester.assertUrlContains("/test/index.jsp", "Hello"); } finally { - distributionRunner.stop(); - distributionRunner.cleanup(); + distributionTester.stop(); + distributionTester.cleanup(); } } From cbc9a9cff3ffca45d07d3d8b1e6098328614c07c Mon Sep 17 00:00:00 2001 From: olivier lamy Date: Mon, 11 Feb 2019 21:34:52 +1000 Subject: [PATCH 07/14] apply some comments from review Signed-off-by: olivier lamy --- tests/test-distribution/pom.xml | 2 +- .../distribution/DistributionTester.java | 565 ++++++++++-------- .../tests/distribution/HttpModuleTests.java | 23 +- .../distribution/JpmsActivatedTests.java | 23 +- 4 files changed, 338 insertions(+), 275 deletions(-) diff --git a/tests/test-distribution/pom.xml b/tests/test-distribution/pom.xml index bc9e78b6124..1eb78e8b518 100644 --- a/tests/test-distribution/pom.xml +++ b/tests/test-distribution/pom.xml @@ -11,7 +11,7 @@ jar - ${project.build.outputDirectory}/jetty_home + ${project.groupId}.test_distribution 1.3.1 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 31f74f46e0d..3bd2883fff5 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 @@ -23,6 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.io.BufferedReader; +import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -83,85 +84,71 @@ import org.eclipse.jetty.util.log.Logger; * So API can change without any further notice. *

*/ -public class DistributionTester { - - private Process pid; - - private URI baseUri; - - private String jmxUrl; - - private long waitStartTime = 60; - - private long maxWaitToStop = 60000; - - private TimeUnit timeUnit = TimeUnit.SECONDS; - - private Path jettyBase; - - private File jettyHomeDir; - - private String jettyVersion; - private String jettyHome; - private String mavenLocalRepository = System.getProperty("user.home") + "/.m2/repository"; +public class DistributionTester implements Closeable +{ private static final Logger LOGGER = Log.getLogger(DistributionTester.class); + private Process pid; + private URI baseUri; + private String jmxUrl; + private Config config; + private List consoleStreamers = new ArrayList<>(); private List logs = new ArrayList<>(); - private HttpClient httpClient; - private Map mavenRemoteRepositories = new HashMap<>(); + private static class Config + { + private long waitStartTime = 60; - private DistributionTester(Path jettyBase) - throws Exception { - this.jettyBase = jettyBase; + private long maxWaitToStop = 60000; + + private TimeUnit timeUnit = TimeUnit.SECONDS; + + private Path jettyBase; + + private File jettyHomeDir; + + private String jettyVersion; + private String jettyHome; + private String mavenLocalRepository = System.getProperty("user.home") + "/.m2/repository"; + private Map mavenRemoteRepositories = new HashMap<>(); } - /** - * - * @return DistributionTester setup jettyHome directory and start httpClient. - * @throws Exception - */ - private DistributionTester initialise() throws Exception { - - if (StringUtils.isNotEmpty(jettyHome)) { - jettyHomeDir = Paths.get(jettyHome).toFile(); - } else { - jettyHomeDir = resolveDistribution(this.jettyVersion); - } - - this.httpClient = new HttpClient(); - httpClient.start(); - - return this; + private DistributionTester(Config config) { + this.config = config; } + /** * start the instance with no arguments - * @throws Exception */ - public void start() throws Exception { + public DistributionTester start() throws Exception + { start(Collections.emptyList()); + return this; } /** * start the instance with the arguments + * * @param args arguments to use to start the distribution - * @throws Exception */ - public void start(String... args) throws Exception { + public DistributionTester start(String... args) throws Exception + { start(Arrays.asList(args)); + return this; } /** * start the instance with the arguments + * * @param args arguments to use to start the distribution - * @throws Exception */ - public void start(List args) - throws Exception { + public DistributionTester start(List args) + throws Exception + { // do we want to be sure and use "--testing-mode" to not break surefire with a System.exit ??? @@ -170,20 +157,20 @@ public class DistributionTester { List commands = new ArrayList<>(); commands.add(getJavaBin()); - commands.add("-Djetty.home=" + jettyHomeDir.getAbsolutePath()); - commands.add("-Djetty.base=" + jettyBase.toAbsolutePath().toString()); + commands.add("-Djetty.home=" + config.jettyHomeDir.getAbsolutePath()); + commands.add("-Djetty.base=" + config.jettyBase.toAbsolutePath().toString()); commands.add("-jar"); - commands.add(jettyHomeDir.getAbsolutePath() + "/start.jar"); + commands.add(config.jettyHomeDir.getAbsolutePath() + "/start.jar"); commands.add("jetty.http.port=0"); commands.addAll(args); ProcessBuilder pbCmd = new ProcessBuilder(commands); - pbCmd.directory(jettyHomeDir); + pbCmd.directory(config.jettyHomeDir); LOGGER.info("Executing: {}", commands); - LOGGER.info("Working Dir: {}", jettyHomeDir.getAbsolutePath()); + LOGGER.info("Working Dir: {}", config.jettyHomeDir.getAbsolutePath()); pbCmd = new ProcessBuilder(commands); pid = pbCmd.start(); @@ -194,12 +181,12 @@ public class DistributionTester { List connList = parser.newPattern("[A-Za-z]*Connector@.*\\{.*\\}\\{(.*)\\:([0-9]*)}", 1); - startPump("STDOUT", parser, this.pid.getInputStream()); - startPump("STDERR", parser, this.pid.getErrorStream()); + consoleStreamers.add(startPump("STDOUT", parser, this.pid.getInputStream())); + consoleStreamers.add(startPump("STDERR", parser, this.pid.getErrorStream())); try { long start = System.currentTimeMillis(); - parser.waitForDone(this.waitStartTime, this.timeUnit); + parser.waitForDone(config.waitStartTime, config.timeUnit); LOGGER.info("wait start {}", System.currentTimeMillis() - start); @@ -219,42 +206,169 @@ public class DistributionTester { } catch (InterruptedException e) { pid.destroy(); } + return this; + } + public void installWarFile(File warFile, String context) throws IOException + { + //webapps + Path webapps = Paths.get(config.jettyBase.toString(), "webapps", context); + if (!Files.exists(webapps)) + { + Files.createDirectories(webapps); + } + unzip(warFile, webapps.toFile()); + } + + //--------------------------------------- + // Assert methods + //--------------------------------------- + + public DistributionTester assertLogsContains(String txt) + { + assertTrue(logs.stream().filter(s -> StringUtils.contains(s, txt)).count() > 0); + return this; } - private void startPump(String mode, ConsoleParser parser, InputStream inputStream) { + public DistributionTester assertUrlStatus(String url, int expectedStatus) + { + try + { + ContentResponse contentResponse = httpClient.GET(getBaseUri() + url); + int status = contentResponse.getStatus(); + assertEquals(expectedStatus, status, () -> "status not " + expectedStatus + " but " + status); + } catch (InterruptedException | ExecutionException | TimeoutException e) + { + fail(e.getMessage(), e); + } + return this; + } + + public DistributionTester assertUrlContains(String url, String content) + { + try + { + ContentResponse contentResponse = httpClient.GET(getBaseUri() + url); + String contentResponseStr = contentResponse.getContentAsString(); + assertTrue(StringUtils.contains(contentResponseStr, content), () -> "content not containing '" + content + "'"); + } catch (InterruptedException | ExecutionException | TimeoutException e) + { + fail(e.getMessage(), e); + } + return this; + } + + /** + * @param coordinates :[:[:]]: + * @return the artifact + */ + public File resolveArtifact(String coordinates) throws ArtifactResolutionException + { + RepositorySystem repositorySystem = newRepositorySystem(); + + Artifact artifact = new DefaultArtifact(coordinates); + + RepositorySystemSession session = newRepositorySystemSession(repositorySystem); + + ArtifactRequest artifactRequest = new ArtifactRequest(); + artifactRequest.setArtifact(artifact); + artifactRequest.setRepositories(newRepositories(repositorySystem, newRepositorySystemSession(repositorySystem))); + ArtifactResult artifactResult = repositorySystem.resolveArtifact(session, artifactRequest); + + artifact = artifactResult.getArtifact(); + return artifact.getFile(); + } + + /** + * @return the directory used as JettyBase + */ + public Path getJettyBase() + { + return config.jettyBase; + } + + /** + * @return the {@link URI} to use to access the jetty instance (random port has been detected) + */ + public URI getBaseUri() + { + return baseUri; + } + + /** + * @return the connection to use to access JMX (if configured) + */ + public String getJmxUrl() + { + return jmxUrl; + } + + /** + * @return DistributionTester setup jettyHome directory and start httpClient. + */ + private DistributionTester initialise() throws Exception + { + if (config.jettyBase == null) + { + config.jettyBase = Files.createTempDirectory("jetty_base_test"); + config.jettyBase.toFile().deleteOnExit(); + } + + if (StringUtils.isNotEmpty(config.jettyHome)) + { + config.jettyHomeDir = Paths.get(config.jettyHome).toFile(); + } else + { + config.jettyHomeDir = resolveDistribution(config.jettyVersion); + } + + this.httpClient = new HttpClient(); + httpClient.start(); + return this; + } + + + private ConsoleStreamer startPump(String mode, ConsoleParser parser, InputStream inputStream) + { ConsoleStreamer pump = new ConsoleStreamer(mode, inputStream); pump.setParser(parser); Thread thread = new Thread(pump, "ConsoleStreamer/" + mode); thread.start(); + return pump; } /** * Simple streamer for the console output from a Process */ private class ConsoleStreamer - implements Runnable { + implements Runnable + { private String mode; private BufferedReader reader; private ConsoleParser parser; - public ConsoleStreamer(String mode, InputStream is) { + private volatile boolean stop; + + public ConsoleStreamer(String mode, InputStream is) + { this.mode = mode; this.reader = new BufferedReader(new InputStreamReader(is)); } - public void setParser(ConsoleParser connector) { + public void setParser(ConsoleParser connector) + { this.parser = connector; } @Override - public void run() { + public void run() + { String line; try { - while ((line = reader.readLine()) != (null)) { + while ((line = reader.readLine()) != null && !stop) { if (parser != null) { parser.parse(line); } @@ -271,32 +385,39 @@ public class DistributionTester { } } - private static class ConsoleParser { + private static class ConsoleParser + { private List patterns = new ArrayList<>(); private CountDownLatch latch; private int count; - public List newPattern(String exp, int cnt) { + public List newPattern(String exp, int cnt) + { ConsolePattern pat = new ConsolePattern(exp, cnt); patterns.add(pat); count += cnt; return pat.getMatches(); } - public void parse(String line) { - for (ConsolePattern pat : patterns) { + public void parse(String line) + { + for (ConsolePattern pat : patterns) + { Matcher mat = pat.getMatcher(line); - if (mat.find()) { + if (mat.find()) + { int num = 0, count = mat.groupCount(); String[] match = new String[count]; - while (num++ < count) { + while (num++ < count) + { match[num - 1] = mat.group(num); } pat.getMatches().add(match); - if (pat.getCount() > 0) { + if (pat.getCount() > 0) + { getLatch().countDown(); } } @@ -304,13 +425,17 @@ public class DistributionTester { } public void waitForDone(long timeout, TimeUnit unit) - throws InterruptedException { + throws InterruptedException + { getLatch().await(timeout, unit); } - private CountDownLatch getLatch() { - synchronized (this) { - if (latch == null) { + private CountDownLatch getLatch() + { + synchronized (this) + { + if (latch == null) + { latch = new CountDownLatch(count); } } @@ -318,91 +443,63 @@ public class DistributionTester { } } - private static class ConsolePattern { + private static class ConsolePattern + { private Pattern pattern; private List matches; private int count; - ConsolePattern(String exp, int cnt) { + ConsolePattern(String exp, int cnt) + { pattern = Pattern.compile(exp); matches = new ArrayList<>(); count = cnt; } - public Matcher getMatcher(String line) { + public Matcher getMatcher(String line) + { return pattern.matcher(line); } - public List getMatches() { + public List getMatches() + { return matches; } - public int getCount() { + public int getCount() + { return count; } } - public void installWarFile(File warFile, String context) throws IOException { - //webapps - Path webapps = Paths.get(jettyBase.toString(),"webapps", context); - if (!Files.exists(webapps)) { - Files.createDirectories(webapps); - } - unzip(warFile, webapps.toFile()); - } - - //--------------------------------------- - // Assert methods - //--------------------------------------- - - public void assertLogsContains(String txt){ - assertTrue(logs.stream().filter(s -> StringUtils.contains(s, txt)).count()>0); - } - - - public void assertUrlStatus(String url, int expectedStatus){ - try { - ContentResponse contentResponse = httpClient.GET(getBaseUri() + url); - int status = contentResponse.getStatus(); - assertEquals(expectedStatus, status, () -> "status not " + expectedStatus + " but " + status); - } catch (InterruptedException|ExecutionException|TimeoutException e) { - fail(e.getMessage(),e); - } - } - - public void assertUrlContains(String url, String content){ - try { - ContentResponse contentResponse = httpClient.GET(getBaseUri() + url); - String contentResponseStr = contentResponse.getContentAsString(); - assertTrue(StringUtils.contains(contentResponseStr, content), () -> "content not containing '" + content + "'"); - } catch (InterruptedException|ExecutionException|TimeoutException e) { - fail(e.getMessage(),e); - } - } - - - private void unzip(File zipFile, File output) throws IOException { + private void unzip(File zipFile, File output) throws IOException + { try (InputStream fileInputStream = Files.newInputStream(zipFile.toPath()); - ZipInputStream zipInputStream = new ZipInputStream(fileInputStream)) + ZipInputStream zipInputStream = new ZipInputStream(fileInputStream)) { ZipEntry entry = zipInputStream.getNextEntry(); - while (entry != null) { - if (entry.isDirectory()) { + while (entry != null) + { + if (entry.isDirectory()) + { File dir = new File(output, entry.getName()); if (!Files.exists(dir.toPath())) { Files.createDirectories(dir.toPath()); } - } else { + } else + { // Read zipEntry and write to a file. File file = new File(output, entry.getName()); - if(!Files.exists(file.getParentFile().toPath())){ + if (!Files.exists(file.getParentFile().toPath())) + { Files.createDirectories(file.getParentFile().toPath()); } - try (OutputStream outputStream = Files.newOutputStream(file.toPath())) { - IOUtil.copy(zipInputStream,outputStream); + try (OutputStream outputStream = Files.newOutputStream(file.toPath())) + { + IOUtil.copy(zipInputStream, outputStream); } } // Get next entry @@ -415,29 +512,8 @@ public class DistributionTester { // Maven Utils methods //--------------------------------------- - /** - * - * @param coordinates :[:[:]]: - * @return the artifact - * @throws ArtifactResolutionException - */ - public File resolveArtifact(String coordinates) throws ArtifactResolutionException { - RepositorySystem repositorySystem = newRepositorySystem(); - - Artifact artifact = new DefaultArtifact(coordinates); - - RepositorySystemSession session = newRepositorySystemSession(repositorySystem); - - ArtifactRequest artifactRequest = new ArtifactRequest(); - artifactRequest.setArtifact(artifact); - artifactRequest.setRepositories(newRepositories(repositorySystem, newRepositorySystemSession(repositorySystem))); - ArtifactResult artifactResult = repositorySystem.resolveArtifact(session, artifactRequest); - - artifact = artifactResult.getArtifact(); - return artifact.getFile(); - } - - private File resolveDistribution(String version) throws Exception { + private File resolveDistribution(String version) throws Exception + { File artifactFile = resolveArtifact("org.eclipse.jetty:jetty-distribution:zip:" + version); // create tmp directory to unzip distribution @@ -449,16 +525,18 @@ public class DistributionTester { } - - private RepositorySystem newRepositorySystem() { + private RepositorySystem newRepositorySystem() + { DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator(); locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class); locator.addService(TransporterFactory.class, FileTransporterFactory.class); locator.addService(TransporterFactory.class, HttpTransporterFactory.class); - locator.setErrorHandler(new DefaultServiceLocator.ErrorHandler() { + locator.setErrorHandler(new DefaultServiceLocator.ErrorHandler() + { @Override - public void serviceCreationFailed(Class type, Class impl, Throwable exception) { + public void serviceCreationFailed(Class type, Class impl, Throwable exception) + { LOGGER.warn("Service creation failed for {} implementation {}: {}", type, impl, exception.getMessage(), exception); } @@ -467,24 +545,27 @@ public class DistributionTester { return locator.getService(RepositorySystem.class); } - private List newRepositories(RepositorySystem system, RepositorySystemSession session) { - List remoteRepositories = new ArrayList<>(this.mavenRemoteRepositories.size()+1); - this.mavenRemoteRepositories.entrySet().stream().forEach(stringStringEntry -> { - remoteRepositories.add(new RemoteRepository.Builder(stringStringEntry.getKey(), "default", stringStringEntry.getValue()).build()); - }); + private List newRepositories(RepositorySystem system, RepositorySystemSession session) + { + List remoteRepositories = new ArrayList<>(config.mavenRemoteRepositories.size() + 1); + config.mavenRemoteRepositories.entrySet().stream().forEach( stringStringEntry -> + remoteRepositories.add(new RemoteRepository.Builder(stringStringEntry.getKey(), "default", stringStringEntry.getValue()).build()) + ); remoteRepositories.add(newCentralRepository()); return remoteRepositories; } - private static RemoteRepository newCentralRepository() { + private static RemoteRepository newCentralRepository() + { return new RemoteRepository.Builder("central", "default", "https://repo.maven.apache.org/maven2/").build(); } - private DefaultRepositorySystemSession newRepositorySystemSession(RepositorySystem system) { + private DefaultRepositorySystemSession newRepositorySystemSession(RepositorySystem system) + { DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); - LocalRepository localRepo = new LocalRepository(mavenLocalRepository); + LocalRepository localRepo = new LocalRepository(config.mavenLocalRepository); session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo)); session.setTransferListener(new LogTransferListener()); @@ -493,11 +574,13 @@ public class DistributionTester { return session; } - private static class LogTransferListener extends AbstractTransferListener { + private static class LogTransferListener extends AbstractTransferListener + { // no op } - private static class LogRepositoryListener extends AbstractRepositoryListener { + private static class LogRepositoryListener extends AbstractRepositoryListener + { @Override public void artifactDownloaded(RepositoryEvent event) { @@ -511,12 +594,13 @@ public class DistributionTester { } - - private String getJavaBin() { + private String getJavaBin() + { String javaexes[] = new String[]{"java", "java.exe"}; File javaHomeDir = new File(System.getProperty("java.home")); - for (String javaexe : javaexes) { + for (String javaexe : javaexes) + { File javabin = new File(javaHomeDir, FS.separators("bin/" + javaexe)); if (javabin.exists() && javabin.isFile()) { return javabin.getAbsolutePath(); @@ -527,85 +611,72 @@ public class DistributionTester { /** * Stop the distribution - * @throws Exception */ public void stop() - throws Exception { - + throws IOException + { long start = System.currentTimeMillis(); - while (this.pid.isAlive()&&(System.currentTimeMillis()-start consoleStreamer.stop=true); } /** * 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 - * @throws Exception */ - public void cleanup() throws Exception { + public void close() throws IOException + { stop(); - if(httpClient!=null&&httpClient.isRunning()){ - httpClient.stop(); + if (httpClient != null && httpClient.isRunning()) { + try + { + httpClient.stop(); + } catch (Exception e) + { + throw new IOException(e.getMessage(),e); + } } - if (Files.exists(this.jettyBase)) { + if (Files.exists(config.jettyBase)) + { // cleanup jetty base - IO.delete(this.jettyBase.toFile()); + IO.delete(config.jettyBase.toFile()); } - if (Files.exists(this.jettyHomeDir.toPath())) { + if (Files.exists(config.jettyHomeDir.toPath())) + { // cleanup jetty distribution - IO.delete(this.jettyHomeDir); + IO.delete(config.jettyHomeDir); } } - /** - * - * @return the directory used as JettyBase - */ - public Path getJettyBase() { - return jettyBase; - } - - /** - * - * @return the {@link URI} to use to access the jetty instance (random port has been detected) - */ - public URI getBaseUri() { - return baseUri; - } - - /** - * - * @return the connection to use to access JMX (if configured) - */ - public String getJmxUrl() { - return jmxUrl; - } - //--------------------------------------- // Builder class //--------------------------------------- - public static class Builder { - private Builder() { + public static class Builder + { + private Builder() + { // no op } @@ -621,102 +692,100 @@ public class DistributionTester { private long maxWaitToStop = 60000; - private Map mavenRemoteRepositories = new HashMap<>(); + private Map mavenRemoteRepositories = new HashMap<>(); /** - * * @param jettyVersion the version to use (format: 9.4.14.v20181114 9.4.15-SNAPSHOT). - * The distribution will be downloaded from local repository or remote + * The distribution will be downloaded from local repository or remote * @return the {@link Builder} */ - public Builder jettyVersion(String jettyVersion) { + public Builder jettyVersion(String jettyVersion) + { this.jettyVersion = jettyVersion; return this; } /** - * * @param jettyHome Path to the local exploded jetty distribution * if configured the jettyVersion parameter will not be used * @return the {@link Builder} */ - public Builder jettyHome(String jettyHome) { + public Builder jettyHome(String jettyHome) + { this.jettyHome = jettyHome; return this; } /** - * * @param mavenLocalRepository Path to the local maven repository * @return the {@link Builder} */ - public Builder mavenLocalRepository(String mavenLocalRepository) { + public Builder mavenLocalRepository(String mavenLocalRepository) + { this.mavenLocalRepository = mavenLocalRepository; return this; } /** - * * @param waitStartTime the maximum time in seconds to wait the start of the distribution * @return the {@link Builder} */ - public Builder waitStartTime(long waitStartTime) { + public Builder waitStartTime(long waitStartTime) + { this.waitStartTime = waitStartTime; return this; } /** - * * @param maxWaitToStop the maximum time in seconds to wait after stop the distribution * process before forcing the stop. * @return the {@link Builder} */ - public Builder maxWaitToStop(long maxWaitToStop) { + public Builder maxWaitToStop(long maxWaitToStop) + { this.maxWaitToStop = maxWaitToStop; return this; } /** - * * If needed to resolve JettyDistribtion from another Maven remote repositories + * * @param id the id * @param url the Maven remote repository url * @return the {@link Builder} */ - public Builder addRemoteRepository(String id, String url) { + public Builder addRemoteRepository(String id, String url) + { this.mavenRemoteRepositories.put(id, url); return this; } /** - * * @return an empty instance of {@link Builder} */ - public static Builder newInstance() { + public static Builder newInstance() + { return new Builder(); } /** - * * @return a new configured instance of {@link DistributionTester} - * @throws Exception */ public DistributionTester build() - throws Exception { - if (jettyBase == null) { - this.jettyBase = Files.createTempDirectory("jetty_base_test"); - this.jettyBase.toFile().deleteOnExit(); + throws Exception + { + Config config = new Config(); + config.jettyBase = jettyBase; + config.jettyVersion = jettyVersion; + config.jettyHome = jettyHome; + config.mavenLocalRepository = mavenLocalRepository; + config.waitStartTime = waitStartTime; + config.maxWaitToStop = maxWaitToStop; + if (!this.mavenRemoteRepositories.isEmpty()) + { + config.mavenRemoteRepositories.putAll(this.mavenRemoteRepositories); } - DistributionTester distributionTester = new DistributionTester(jettyBase); - distributionTester.jettyVersion = jettyVersion; - distributionTester.jettyHome = jettyHome; - distributionTester.mavenLocalRepository = mavenLocalRepository; - distributionTester.waitStartTime = waitStartTime; - distributionTester.maxWaitToStop = maxWaitToStop; - if(!this.mavenRemoteRepositories.isEmpty()) { - distributionTester.mavenRemoteRepositories.putAll(this.mavenRemoteRepositories); - } - return distributionTester.initialise(); + return new DistributionTester(config).initialise(); } } } diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java index 08c3ae187a1..a60766fe990 100644 --- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java @@ -27,25 +27,22 @@ public class HttpModuleTests @Test public void http_module() throws Exception { - DistributionTester distributionTester = DistributionTester.Builder.newInstance() // - .jettyVersion(System.getProperty("jetty_version")) // - .mavenLocalRepository(System.getProperty("mavenRepoPath")) // - .waitStartTime(30) // - .build(); // - try + + try(DistributionTester distributionTester = DistributionTester.Builder.newInstance() // + .jettyVersion(System.getProperty("jetty_version")) // + .mavenLocalRepository(System.getProperty("mavenRepoPath")) // + .waitStartTime(30) // + .build()) { distributionTester.start("--create-startd", "--approve-all-licenses", "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,jmx-remote,servlet,servlets"); distributionTester.stop(); File war = distributionTester.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + System.getProperty("jetty_version")); distributionTester.installWarFile(war, "test"); - distributionTester.start(); - distributionTester.assertLogsContains("Started @"); - distributionTester.assertUrlStatus("/test/index.jsp", 200); - distributionTester.assertUrlContains("/test/index.jsp", "Hello"); - } finally { - distributionTester.stop(); - distributionTester.cleanup(); + distributionTester.start() // + .assertLogsContains("Started @") // + .assertUrlStatus("/test/index.jsp", 200) // + .assertUrlContains("/test/index.jsp", "Hello"); } } diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java index 2462626db7f..fcf8300b7f9 100644 --- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java @@ -30,25 +30,22 @@ public class JpmsActivatedTests @DisabledOnJre(JRE.JAVA_8) public void jpms_activated() throws Exception { - DistributionTester distributionTester = DistributionTester.Builder.newInstance() // - .jettyVersion(System.getProperty("jetty_version")) // - .mavenLocalRepository(System.getProperty("mavenRepoPath")) // - .waitStartTime(30) // - .build(); // - try + + try(DistributionTester distributionTester = DistributionTester.Builder.newInstance() // + .jettyVersion(System.getProperty("jetty_version")) // + .mavenLocalRepository(System.getProperty("mavenRepoPath")) // + .waitStartTime(30) // + .build()) { distributionTester.start("--create-startd", "--approve-all-licenses", "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,jmx-remote,servlet,servlets"); distributionTester.stop(); File war = distributionTester.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + System.getProperty("jetty_version")); distributionTester.installWarFile(war, "test"); - distributionTester.start("--jpms"); - distributionTester.assertLogsContains("Started @"); - distributionTester.assertUrlStatus("/test/index.jsp", 200); - distributionTester.assertUrlContains("/test/index.jsp", "Hello"); - } finally { - distributionTester.stop(); - distributionTester.cleanup(); + distributionTester.start("--jpms") // + .assertLogsContains("Started @") // + .assertUrlStatus("/test/index.jsp", 200) + .assertUrlContains("/test/index.jsp", "Hello"); } } From cb6b9d4a39afae2fdaf761c61ea120ef9fe503da Mon Sep 17 00:00:00 2001 From: Richard Bradley Date: Mon, 11 Feb 2019 13:39:05 +0000 Subject: [PATCH 08/14] Include Vary:Origin on all responses Signed-off-by: Richard Bradley --- .../java/org/eclipse/jetty/servlets/CrossOriginFilter.java | 3 +-- .../java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java index d25f3f44d65..692be858f1c 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/CrossOriginFilter.java @@ -400,8 +400,7 @@ public class CrossOriginFilter implements Filter { response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, origin); //W3C CORS spec http://www.w3.org/TR/cors/#resource-implementation - if (!anyOriginAllowed) - response.addHeader("Vary", ORIGIN_HEADER); + response.addHeader("Vary", ORIGIN_HEADER); if (allowCredentials) response.setHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER, "true"); if (!exposedHeaders.isEmpty()) diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java index d55bfcfafee..37a5aeb6771 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java @@ -135,7 +135,7 @@ public class CrossOriginFilterTest Set fieldNames = response.getFieldNamesCollection(); assertThat(response.toString(), CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, isIn(fieldNames)); assertThat(response.toString(), CrossOriginFilter.ACCESS_CONTROL_ALLOW_CREDENTIALS_HEADER, isIn(fieldNames)); - assertThat(response.toString(), "Vary", not(isIn(fieldNames))); + assertThat(response.toString(), "Vary", isIn(fieldNames)); assertTrue(latch.await(1, TimeUnit.SECONDS)); } From b0207dd90d99010fa207105a3b9df55f50bea34e Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 11 Feb 2019 19:37:49 +0100 Subject: [PATCH 09/14] Issue #3343 - Add an API/tools to be able to test Jetty Distribution. Reworked the implementation. Deleted unused stuff. Written more tests. Signed-off-by: Simone Bordet --- tests/test-distribution/pom.xml | 55 +- .../distribution/DistributionTester.java | 690 ++++++------------ .../AbstractDistributionTest.java | 29 + .../tests/distribution/DistributionTests.java | 210 ++++++ .../tests/distribution/HttpModuleTests.java | 49 -- .../distribution/JpmsActivatedTests.java | 52 -- .../src/test/resources/index.html | 1 - .../test/resources/jetty-logging.properties | 2 + .../src/test/resources/static_content.xml | 11 - 9 files changed, 486 insertions(+), 613 deletions(-) create mode 100644 tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/AbstractDistributionTest.java create mode 100644 tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DistributionTests.java delete mode 100644 tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java delete mode 100644 tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java delete mode 100644 tests/test-distribution/src/test/resources/index.html create mode 100644 tests/test-distribution/src/test/resources/jetty-logging.properties delete mode 100644 tests/test-distribution/src/test/resources/static_content.xml diff --git a/tests/test-distribution/pom.xml b/tests/test-distribution/pom.xml index 1eb78e8b518..a2e8a386e72 100644 --- a/tests/test-distribution/pom.xml +++ b/tests/test-distribution/pom.xml @@ -11,41 +11,28 @@ jar - ${project.groupId}.test_distribution + ${project.groupId}.tests.distribution 1.3.1 - - org.eclipse.jetty - jetty-client - ${project.version} - - - org.eclipse.jetty - jetty-distribution - ${project.version} - zip - - - org.eclipse.jetty - jetty-start - ${project.version} - org.slf4j slf4j-simple - ${slf4j.version} - org.apache.maven - maven-resolver-provider - 3.6.0 + org.eclipse.jetty + jetty-util + ${project.version} org.apache.maven maven-artifact - 3.6.0 + + + org.apache.maven + maven-resolver-provider + ${maven.version} org.apache.maven.resolver @@ -62,18 +49,33 @@ maven-resolver-transport-http ${mavenResolver.version} + - org.junit.jupiter - junit-jupiter-api - ${junit.version} + org.eclipse.jetty + jetty-client + ${project.version} + test + + + org.eclipse.jetty.http2 + http2-http-client-transport + ${project.version} + test org.eclipse.jetty.tests test-simple-webapp ${project.version} war + test + + + org.eclipse.jetty.toolchain + jetty-test-helper + test + @@ -82,10 +84,11 @@ ${settings.localRepository} - ${project.version} + ${project.version} + 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 3bd2883fff5..3a29dff86fa 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 @@ -18,10 +18,6 @@ package org.eclipse.jetty.tests.distribution; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - import java.io.BufferedReader; import java.io.Closeable; import java.io.File; @@ -29,28 +25,21 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; -import java.net.URI; +import java.net.InetSocketAddress; +import java.net.ServerSocket; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; -import org.apache.commons.lang3.StringUtils; import org.apache.maven.repository.internal.MavenRepositorySystemUtils; -import org.codehaus.plexus.util.FileUtils; import org.codehaus.plexus.util.IOUtil; import org.eclipse.aether.AbstractRepositoryListener; import org.eclipse.aether.DefaultRepositorySystemSession; @@ -71,142 +60,76 @@ import org.eclipse.aether.spi.connector.transport.TransporterFactory; import org.eclipse.aether.transfer.AbstractTransferListener; import org.eclipse.aether.transport.file.FileTransporterFactory; import org.eclipse.aether.transport.http.HttpTransporterFactory; -import org.eclipse.jetty.client.HttpClient; -import org.eclipse.jetty.client.api.ContentResponse; -import org.eclipse.jetty.start.FS; import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; /** - *

- * Please note this class is use for Jetty Distribution testing. - * So API can change without any further notice. - *

+ *

Helper class to test the Jetty Distribution

. + *

API can change without any further notice.

*/ -public class DistributionTester implements Closeable +public class DistributionTester { - private static final Logger LOGGER = Log.getLogger(DistributionTester.class); - private Process pid; - private URI baseUri; - private String jmxUrl; private Config config; private List consoleStreamers = new ArrayList<>(); private List logs = new ArrayList<>(); - private HttpClient httpClient; - private static class Config + private DistributionTester(Config config) { - private long waitStartTime = 60; - - private long maxWaitToStop = 60000; - - private TimeUnit timeUnit = TimeUnit.SECONDS; - - private Path jettyBase; - - private File jettyHomeDir; - - private String jettyVersion; - private String jettyHome; - private String mavenLocalRepository = System.getProperty("user.home") + "/.m2/repository"; - private Map mavenRemoteRepositories = new HashMap<>(); - } - - - private DistributionTester(Config config) { this.config = config; } - /** - * start the instance with no arguments - */ - public DistributionTester start() throws Exception - { - start(Collections.emptyList()); - return this; - } - - /** - * start the instance with the arguments + * Starts the instance with the given arguments * * @param args arguments to use to start the distribution */ - public DistributionTester start(String... args) throws Exception + public DistributionTester.Run start(String... args) throws Exception { - start(Arrays.asList(args)); - return this; + return start(Arrays.asList(args)); } /** - * start the instance with the arguments + * Start the instance with the arguments * * @param args arguments to use to start the distribution */ - public DistributionTester start(List args) - throws Exception + 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(getJavaBin()); - - commands.add("-Djetty.home=" + config.jettyHomeDir.getAbsolutePath()); - commands.add("-Djetty.base=" + config.jettyBase.toAbsolutePath().toString()); - + commands.add(getJavaExecutable()); commands.add("-jar"); - commands.add(config.jettyHomeDir.getAbsolutePath() + "/start.jar"); - commands.add("jetty.http.port=0"); - + commands.add(config.jettyHome.toAbsolutePath() + "/start.jar"); commands.addAll(args); - ProcessBuilder pbCmd = new ProcessBuilder(commands); - pbCmd.directory(config.jettyHomeDir); - + File workingDir = config.jettyBase.toFile(); LOGGER.info("Executing: {}", commands); - LOGGER.info("Working Dir: {}", config.jettyHomeDir.getAbsolutePath()); + LOGGER.info("Working Dir: {}", workingDir.getAbsolutePath()); - pbCmd = new ProcessBuilder(commands); - pid = pbCmd.start(); + ProcessBuilder pbCmd = new ProcessBuilder(commands); + pbCmd.directory(workingDir); + Process process = pbCmd.start(); - ConsoleParser parser = new ConsoleParser(); - List jmxList = parser.newPattern("JMX Remote URL: (.*)", 0); - // Started ServerConnector@76f2bbc1{HTTP/1.1,[http/1.1]}{0.0.0.0:50214} - List connList = - parser.newPattern("[A-Za-z]*Connector@.*\\{.*\\}\\{(.*)\\:([0-9]*)}", 1); + consoleStreamers.add(startPump("STDOUT", process.getInputStream())); + consoleStreamers.add(startPump("STDERR", process.getErrorStream())); - consoleStreamers.add(startPump("STDOUT", parser, this.pid.getInputStream())); - consoleStreamers.add(startPump("STDERR", parser, this.pid.getErrorStream())); + return new Run(process); + } - try { - long start = System.currentTimeMillis(); - parser.waitForDone(config.waitStartTime, config.timeUnit); - LOGGER.info("wait start {}", System.currentTimeMillis() - start); - - - if (!jmxList.isEmpty()) { - this.jmxUrl = jmxList.get(0)[0]; - LOGGER.info("## Found JMX connector at {}", this.jmxUrl); - } - - if (!connList.isEmpty()) { - String[] params = connList.get(0); - if (params.length == 2) { - this.baseUri = URI.create("http://localhost:" + params[1]); - } - LOGGER.info("## Found Jetty connector at port: {}", params[1]); - } - - } catch (InterruptedException e) { - pid.destroy(); + public int randomPort() throws IOException + { + try (ServerSocket server = new ServerSocket()) + { + server.setReuseAddress(true); + server.bind(new InetSocketAddress("localhost", 0)); + return server.getLocalPort(); } - return this; } public void installWarFile(File warFile, String context) throws IOException @@ -214,51 +137,10 @@ public class DistributionTester implements Closeable //webapps Path webapps = Paths.get(config.jettyBase.toString(), "webapps", context); if (!Files.exists(webapps)) - { Files.createDirectories(webapps); - } unzip(warFile, webapps.toFile()); } - //--------------------------------------- - // Assert methods - //--------------------------------------- - - public DistributionTester assertLogsContains(String txt) - { - assertTrue(logs.stream().filter(s -> StringUtils.contains(s, txt)).count() > 0); - return this; - } - - - public DistributionTester assertUrlStatus(String url, int expectedStatus) - { - try - { - ContentResponse contentResponse = httpClient.GET(getBaseUri() + url); - int status = contentResponse.getStatus(); - assertEquals(expectedStatus, status, () -> "status not " + expectedStatus + " but " + status); - } catch (InterruptedException | ExecutionException | TimeoutException e) - { - fail(e.getMessage(), e); - } - return this; - } - - public DistributionTester assertUrlContains(String url, String content) - { - try - { - ContentResponse contentResponse = httpClient.GET(getBaseUri() + url); - String contentResponseStr = contentResponse.getContentAsString(); - assertTrue(StringUtils.contains(contentResponseStr, content), () -> "content not containing '" + content + "'"); - } catch (InterruptedException | ExecutionException | TimeoutException e) - { - fail(e.getMessage(), e); - } - return this; - } - /** * @param coordinates :[:[:]]: * @return the artifact @@ -273,208 +155,50 @@ public class DistributionTester implements Closeable ArtifactRequest artifactRequest = new ArtifactRequest(); artifactRequest.setArtifact(artifact); - artifactRequest.setRepositories(newRepositories(repositorySystem, newRepositorySystemSession(repositorySystem))); + artifactRequest.setRepositories(newRepositories()); ArtifactResult artifactResult = repositorySystem.resolveArtifact(session, artifactRequest); artifact = artifactResult.getArtifact(); return artifact.getFile(); } - /** - * @return the directory used as JettyBase - */ - public Path getJettyBase() + private void init() throws Exception { - return config.jettyBase; - } + if (config.jettyHome == null) + config.jettyHome = resolveDistribution(config.jettyVersion); - /** - * @return the {@link URI} to use to access the jetty instance (random port has been detected) - */ - public URI getBaseUri() - { - return baseUri; - } - - /** - * @return the connection to use to access JMX (if configured) - */ - public String getJmxUrl() - { - return jmxUrl; - } - - /** - * @return DistributionTester setup jettyHome directory and start httpClient. - */ - private DistributionTester initialise() throws Exception - { if (config.jettyBase == null) { - config.jettyBase = Files.createTempDirectory("jetty_base_test"); - config.jettyBase.toFile().deleteOnExit(); + config.jettyBase = Files.createTempDirectory("jetty_base_"); } - - if (StringUtils.isNotEmpty(config.jettyHome)) + else { - config.jettyHomeDir = Paths.get(config.jettyHome).toFile(); - } else - { - config.jettyHomeDir = resolveDistribution(config.jettyVersion); + if (!config.jettyBase.isAbsolute()) + config.jettyBase = config.jettyHome.resolve(config.jettyBase); } - - this.httpClient = new HttpClient(); - httpClient.start(); - return this; } - - private ConsoleStreamer startPump(String mode, ConsoleParser parser, InputStream inputStream) + private String getJavaExecutable() { - ConsoleStreamer pump = new ConsoleStreamer(mode, inputStream); - pump.setParser(parser); + String[] javaExecutables = new String[]{"java", "java.exe"}; + File javaHomeDir = new File(System.getProperty("java.home")); + for (String javaExecutable : javaExecutables) + { + File javaFile = new File(javaHomeDir, "bin" + File.separator + javaExecutable); + if (javaFile.exists() && javaFile.isFile()) + return javaFile.getAbsolutePath(); + } + 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; } - /** - * Simple streamer for the console output from a Process - */ - private class ConsoleStreamer - implements Runnable - { - private String mode; - - private BufferedReader reader; - - private ConsoleParser parser; - - private volatile boolean stop; - - public ConsoleStreamer(String mode, InputStream is) - { - this.mode = mode; - this.reader = new BufferedReader(new InputStreamReader(is)); - } - - public void setParser(ConsoleParser connector) - { - this.parser = connector; - } - - @Override - public void run() - { - String line; - try { - while ((line = reader.readLine()) != null && !stop) { - if (parser != null) { - parser.parse(line); - } - // using LOGGER generates too long lines.. - //LOGGER.info("[{}] {}",mode, line); - System.out.println("[" + mode + "] " + line); - DistributionTester.this.logs.add(line); - } - } catch (IOException ignore) { - // ignore - } finally { - IO.close(reader); - } - } - } - - private static class ConsoleParser - { - private List patterns = new ArrayList<>(); - - private CountDownLatch latch; - - private int count; - - public List newPattern(String exp, int cnt) - { - ConsolePattern pat = new ConsolePattern(exp, cnt); - patterns.add(pat); - count += cnt; - return pat.getMatches(); - } - - public void parse(String line) - { - for (ConsolePattern pat : patterns) - { - Matcher mat = pat.getMatcher(line); - if (mat.find()) - { - int num = 0, count = mat.groupCount(); - String[] match = new String[count]; - while (num++ < count) - { - match[num - 1] = mat.group(num); - } - pat.getMatches().add(match); - - if (pat.getCount() > 0) - { - getLatch().countDown(); - } - } - } - } - - public void waitForDone(long timeout, TimeUnit unit) - throws InterruptedException - { - getLatch().await(timeout, unit); - } - - private CountDownLatch getLatch() - { - synchronized (this) - { - if (latch == null) - { - latch = new CountDownLatch(count); - } - } - return latch; - } - } - - private static class ConsolePattern - { - private Pattern pattern; - - private List matches; - - private int count; - - ConsolePattern(String exp, int cnt) - { - pattern = Pattern.compile(exp); - matches = new ArrayList<>(); - count = cnt; - } - - public Matcher getMatcher(String line) - { - return pattern.matcher(line); - } - - public List getMatches() - { - return matches; - } - - public int getCount() - { - return count; - } - } - - private void unzip(File zipFile, File output) throws IOException { try (InputStream fileInputStream = Files.newInputStream(zipFile.toPath()); @@ -486,10 +210,12 @@ public class DistributionTester implements Closeable if (entry.isDirectory()) { File dir = new File(output, entry.getName()); - if (!Files.exists(dir.toPath())) { + if (!Files.exists(dir.toPath())) + { Files.createDirectories(dir.toPath()); } - } else + } + else { // Read zipEntry and write to a file. File file = new File(output, entry.getName()); @@ -508,23 +234,19 @@ public class DistributionTester implements Closeable } } - //--------------------------------------- - // Maven Utils methods - //--------------------------------------- - - private File resolveDistribution(String version) throws Exception + private Path resolveDistribution(String version) throws Exception { File artifactFile = resolveArtifact("org.eclipse.jetty:jetty-distribution:zip:" + version); // create tmp directory to unzip distribution - Path tmp = Files.createTempDirectory("jetty_test"); - tmp.toFile().deleteOnExit(); + Path tmp = Files.createTempDirectory("jetty_home_"); + File tmpFile = tmp.toFile(); - unzip(artifactFile, tmp.toFile()); - return new File(tmp.toFile(), "jetty-distribution-" + version); + unzip(artifactFile, tmpFile); + + return tmp.resolve("jetty-distribution-" + version); } - private RepositorySystem newRepositorySystem() { DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator(); @@ -545,12 +267,10 @@ public class DistributionTester implements Closeable return locator.getService(RepositorySystem.class); } - private List newRepositories(RepositorySystem system, RepositorySystemSession session) + private List newRepositories() { List remoteRepositories = new ArrayList<>(config.mavenRemoteRepositories.size() + 1); - config.mavenRemoteRepositories.entrySet().stream().forEach( stringStringEntry -> - remoteRepositories.add(new RemoteRepository.Builder(stringStringEntry.getKey(), "default", stringStringEntry.getValue()).build()) - ); + config.mavenRemoteRepositories.forEach((key, value) -> remoteRepositories.add(new RemoteRepository.Builder(key, "default", value).build())); remoteRepositories.add(newCentralRepository()); return remoteRepositories; } @@ -564,7 +284,6 @@ public class DistributionTester implements Closeable { DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); - LocalRepository localRepo = new LocalRepository(config.mavenLocalRepository); session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo)); @@ -574,6 +293,62 @@ public class DistributionTester implements Closeable return session; } + public Path getJettyHome() + { + return config.jettyHome; + } + + private static class Config + { + private Path jettyBase; + private Path jettyHome; + private String jettyVersion; + private String mavenLocalRepository = System.getProperty("user.home") + "/.m2/repository"; + private Map mavenRemoteRepositories = new HashMap<>(); + } + + /** + * 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); + } + } + private static class LogTransferListener extends AbstractTransferListener { // no op @@ -581,138 +356,136 @@ public class DistributionTester implements Closeable private static class LogRepositoryListener extends AbstractRepositoryListener { - @Override - public void artifactDownloaded(RepositoryEvent event) { + public void artifactDownloaded(RepositoryEvent event) + { LOGGER.debug("distribution downloaded to {}", event.getFile()); } @Override - public void artifactResolved(RepositoryEvent event) { + public void artifactResolved(RepositoryEvent event) + { LOGGER.debug("distribution resolved to {}", event.getFile()); } } - - private String getJavaBin() + public class Run implements Closeable { - String javaexes[] = new String[]{"java", "java.exe"}; + private final Process process; - File javaHomeDir = new File(System.getProperty("java.home")); - for (String javaexe : javaexes) + public Run(Process process) { - File javabin = new File(javaHomeDir, FS.separators("bin/" + javaexe)); - if (javabin.exists() && javabin.isFile()) { - return javabin.getAbsolutePath(); - } + this.process = process; } - return "java"; - } - /** - * Stop the distribution - */ - public void stop() - throws IOException - { - long start = System.currentTimeMillis(); - while (this.pid.isAlive() && (System.currentTimeMillis() - start < config.maxWaitToStop)) + /** + * Waits for the given time for the distribution to stop. + * + * @param time the time to wait + * @param unit the unit of time + * @return true if the distribution process is terminated, false if the timeout elapsed + * @throws InterruptedException if the wait is interrupted + */ + public boolean awaitFor(long time, TimeUnit unit) throws InterruptedException { - this.pid.destroy(); - if (this.pid.isAlive()) - { - // wait a bit to try again - try - { - Thread.sleep(500); - } catch (InterruptedException e) - { - throw new IOException(e.getMessage(),e); - } - } + boolean result = process.waitFor(time, unit); + if (result) + stopConsoleStreamers(); + return result; } - // still alive so force stop - if (this.pid.isAlive()) - { - LOGGER.info("still alive so force destroy process"); - this.pid.destroyForcibly(); - } - consoleStreamers.forEach(consoleStreamer -> consoleStreamer.stop=true); - } - /** - * 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 - */ - public void close() throws IOException - { - stop(); - if (httpClient != null && httpClient.isRunning()) { - try + public int getExitValue() + { + return process.exitValue(); + } + + /** + * Stops the distribution. + * + * @see #awaitFor(long, TimeUnit) + */ + public void stop() + { + process.destroy(); + stopConsoleStreamers(); + } + + public void destroy() + { + process.destroyForcibly(); + stopConsoleStreamers(); + } + + private void stopConsoleStreamers() + { + consoleStreamers.forEach(ConsoleStreamer::stop); + } + + /** + * 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 + */ + @Override + public void close() + { + destroy(); + } + + public boolean awaitConsoleLogsFor(String txt, long time, TimeUnit unit) throws InterruptedException + { + long end = System.nanoTime() + unit.toNanos(time); + while (System.nanoTime() < end) { - httpClient.stop(); - } catch (Exception e) - { - throw new IOException(e.getMessage(),e); + boolean result = logs.stream().anyMatch(s -> s.contains(txt)); + if (result) + return true; + Thread.sleep(250); } - } - if (Files.exists(config.jettyBase)) - { - // cleanup jetty base - IO.delete(config.jettyBase.toFile()); - } - if (Files.exists(config.jettyHomeDir.toPath())) - { - // cleanup jetty distribution - IO.delete(config.jettyHomeDir); + return false; } } - - //--------------------------------------- - // Builder class - //--------------------------------------- public static class Builder { + private Config config = new Config(); + private Builder() { - // no op } - private Path jettyBase; - - private String jettyVersion; - - private String jettyHome; - - private String mavenLocalRepository; - - private long waitStartTime = 60; - - private long maxWaitToStop = 60000; - - private Map mavenRemoteRepositories = new HashMap<>(); - /** * @param jettyVersion the version to use (format: 9.4.14.v20181114 9.4.15-SNAPSHOT). - * The distribution will be downloaded from local repository or remote + * The distribution will be downloaded from local repository or remote * @return the {@link Builder} */ public Builder jettyVersion(String jettyVersion) { - this.jettyVersion = jettyVersion; + config.jettyVersion = jettyVersion; return this; } /** * @param jettyHome Path to the local exploded jetty distribution - * if configured the jettyVersion parameter will not be used + * if configured the jettyVersion parameter will not be used * @return the {@link Builder} */ - public Builder jettyHome(String jettyHome) + public Builder jettyHome(Path jettyHome) { - this.jettyHome = jettyHome; + config.jettyHome = jettyHome; + return this; + } + + /** + *

Sets the path for the Jetty Base directory.

+ *

If the path is relative, it will be resolved against the Jetty Home directory.

+ * + * @param jettyBase Path to the local Jetty Base directory + * @return the {@link Builder} + */ + public Builder jettyBase(Path jettyBase) + { + config.jettyBase = jettyBase; return this; } @@ -722,41 +495,20 @@ public class DistributionTester implements Closeable */ public Builder mavenLocalRepository(String mavenLocalRepository) { - this.mavenLocalRepository = mavenLocalRepository; + config.mavenLocalRepository = mavenLocalRepository; return this; } /** - * @param waitStartTime the maximum time in seconds to wait the start of the distribution - * @return the {@link Builder} - */ - public Builder waitStartTime(long waitStartTime) - { - this.waitStartTime = waitStartTime; - return this; - } - - /** - * @param maxWaitToStop the maximum time in seconds to wait after stop the distribution - * process before forcing the stop. - * @return the {@link Builder} - */ - public Builder maxWaitToStop(long maxWaitToStop) - { - this.maxWaitToStop = maxWaitToStop; - return this; - } - - /** - * If needed to resolve JettyDistribtion from another Maven remote repositories + * If needed to resolve the Jetty distribution from another Maven remote repositories * - * @param id the id + * @param id the id * @param url the Maven remote repository url * @return the {@link Builder} */ public Builder addRemoteRepository(String id, String url) { - this.mavenRemoteRepositories.put(id, url); + config.mavenRemoteRepositories.put(id, url); return this; } @@ -771,21 +523,11 @@ public class DistributionTester implements Closeable /** * @return a new configured instance of {@link DistributionTester} */ - public DistributionTester build() - throws Exception + public DistributionTester build() throws Exception { - Config config = new Config(); - config.jettyBase = jettyBase; - config.jettyVersion = jettyVersion; - config.jettyHome = jettyHome; - config.mavenLocalRepository = mavenLocalRepository; - config.waitStartTime = waitStartTime; - config.maxWaitToStop = maxWaitToStop; - if (!this.mavenRemoteRepositories.isEmpty()) - { - config.mavenRemoteRepositories.putAll(this.mavenRemoteRepositories); - } - return new DistributionTester(config).initialise(); + DistributionTester tester = new DistributionTester(config); + tester.init(); + return tester; } } } diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/AbstractDistributionTest.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/AbstractDistributionTest.java new file mode 100644 index 00000000000..f345b53e846 --- /dev/null +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/AbstractDistributionTest.java @@ -0,0 +1,29 @@ +package org.eclipse.jetty.tests.distribution; + +import java.util.function.Supplier; + +import org.eclipse.jetty.client.HttpClient; +import org.junit.jupiter.api.AfterEach; + +public class AbstractDistributionTest +{ + protected HttpClient client; + + protected void startHttpClient() throws Exception + { + startHttpClient(HttpClient::new); + } + + protected void startHttpClient(Supplier supplier) throws Exception + { + client = supplier.get(); + client.start(); + } + + @AfterEach + public void dispose() throws Exception + { + if (client != null) + client.stop(); + } +} 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 new file mode 100644 index 00000000000..131336218ae --- /dev/null +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/DistributionTests.java @@ -0,0 +1,210 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.tests.distribution; + +import java.io.File; +import java.nio.file.Paths; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.client.api.ContentResponse; +import org.eclipse.jetty.http.HttpStatus; +import org.eclipse.jetty.http2.client.HTTP2Client; +import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledOnJre; +import org.junit.jupiter.api.condition.JRE; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class DistributionTests extends AbstractDistributionTest +{ + @Test + public void testStartStop() throws Exception + { + String jettyVersion = System.getProperty("jettyVersion"); + DistributionTester distribution = DistributionTester.Builder.newInstance() + .jettyVersion(jettyVersion) + .mavenLocalRepository(System.getProperty("mavenRepoPath")) + .build(); + + try (DistributionTester.Run run1 = distribution.start("--add-to-start=http")) + { + assertTrue(run1.awaitFor(5, TimeUnit.SECONDS)); + assertEquals(0, run1.getExitValue()); + + int port = distribution.randomPort(); + try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port)) + { + assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); + + startHttpClient(); + ContentResponse response = client.GET("http://localhost:" + port); + assertEquals(HttpStatus.NOT_FOUND_404, response.getStatus()); + + run2.stop(); + assertTrue(run2.awaitFor(5, TimeUnit.SECONDS)); + } + } + } + + @Test + public void testSimpleWebAppWithJSP() throws Exception + { + String jettyVersion = System.getProperty("jettyVersion"); + DistributionTester distribution = DistributionTester.Builder.newInstance() + .jettyVersion(jettyVersion) + .mavenLocalRepository(System.getProperty("mavenRepoPath")) + .build(); + + String[] args1 = { + "--create-startd", + "--approve-all-licenses", + "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,servlet,servlets" + }; + try (DistributionTester.Run run1 = distribution.start(args1)) + { + assertTrue(run1.awaitFor(5, TimeUnit.SECONDS)); + assertEquals(0, run1.getExitValue()); + + File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + jettyVersion); + distribution.installWarFile(war, "test"); + + int port = distribution.randomPort(); + try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port)) + { + assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); + + startHttpClient(); + ContentResponse response = client.GET("http://localhost:" + port + "/test/index.jsp"); + assertEquals(HttpStatus.OK_200, response.getStatus()); + assertThat(response.getContentAsString(), containsString("Hello")); + assertThat(response.getContentAsString(), not(containsString("<%"))); + } + } + } + + @Test + @DisabledOnJre(JRE.JAVA_8) + public void testSimpleWebAppWithJSPOnModulePath() throws Exception + { + String jettyVersion = System.getProperty("jettyVersion"); + DistributionTester distribution = DistributionTester.Builder.newInstance() + .jettyVersion(jettyVersion) + .mavenLocalRepository(System.getProperty("mavenRepoPath")) + .build(); + + String[] args1 = { + "--create-startd", + "--approve-all-licenses", + "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,servlet,servlets" + }; + try (DistributionTester.Run run1 = distribution.start(args1)) + { + assertTrue(run1.awaitFor(5, TimeUnit.SECONDS)); + assertEquals(0, run1.getExitValue()); + + File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + jettyVersion); + distribution.installWarFile(war, "test"); + + int port = distribution.randomPort(); + String[] args2 = { + "--jpms", + "jetty.http.port=" + port + }; + try (DistributionTester.Run run2 = distribution.start(args2)) + { + assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); + + startHttpClient(); + ContentResponse response = client.GET("http://localhost:" + port + "/test/index.jsp"); + assertEquals(HttpStatus.OK_200, response.getStatus()); + assertThat(response.getContentAsString(), containsString("Hello")); + assertThat(response.getContentAsString(), not(containsString("<%"))); + } + } + } + + @Test + @DisabledOnJre(JRE.JAVA_8) + public void testSimpleWebAppWithJSPOverH2C() throws Exception + { + String jettyVersion = System.getProperty("jettyVersion"); + DistributionTester distribution = DistributionTester.Builder.newInstance() + .jettyVersion(jettyVersion) + .mavenLocalRepository(System.getProperty("mavenRepoPath")) + .build(); + + String[] args1 = { + "--create-startd", + "--add-to-start=http2c,jsp,deploy" + }; + try (DistributionTester.Run run1 = distribution.start(args1)) + { + assertTrue(run1.awaitFor(5, TimeUnit.SECONDS)); + assertEquals(0, run1.getExitValue()); + + File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + jettyVersion); + distribution.installWarFile(war, "test"); + + int port = distribution.randomPort(); + try (DistributionTester.Run run2 = distribution.start("jetty.http.port=" + port)) + { + assertTrue(run2.awaitConsoleLogsFor("Started @", 10, TimeUnit.SECONDS)); + + HTTP2Client h2Client = new HTTP2Client(); + startHttpClient(() -> new HttpClient(new HttpClientTransportOverHTTP2(h2Client), null)); + ContentResponse response = client.GET("http://localhost:" + port + "/test/index.jsp"); + assertEquals(HttpStatus.OK_200, response.getStatus()); + assertThat(response.getContentAsString(), containsString("Hello")); + assertThat(response.getContentAsString(), not(containsString("<%"))); + } + } + } + + @Test + public void testDemoBase() throws Exception + { + String jettyVersion = System.getProperty("jettyVersion"); + DistributionTester distribution = DistributionTester.Builder.newInstance() + .jettyVersion(jettyVersion) + .jettyBase(Paths.get("demo-base")) + .mavenLocalRepository(System.getProperty("mavenRepoPath")) + .build(); + + int port = distribution.randomPort(); + String[] args1 = { + "jetty.http.port=" + port + }; + try (DistributionTester.Run run1 = distribution.start(args1)) + { + assertTrue(run1.awaitConsoleLogsFor("Started @", 20, TimeUnit.SECONDS)); + + startHttpClient(); + ContentResponse response = client.GET("http://localhost:" + port + "/test/jsp/dump.jsp"); + assertEquals(HttpStatus.OK_200, response.getStatus()); + assertThat(response.getContentAsString(), containsString("PathInfo")); + assertThat(response.getContentAsString(), not(containsString("<%"))); + } + } +} diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java deleted file mode 100644 index a60766fe990..00000000000 --- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/HttpModuleTests.java +++ /dev/null @@ -1,49 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.tests.distribution; - -import org.junit.jupiter.api.Test; - -import java.io.File; - -public class HttpModuleTests -{ - @Test - public void http_module() throws Exception - { - - try(DistributionTester distributionTester = DistributionTester.Builder.newInstance() // - .jettyVersion(System.getProperty("jetty_version")) // - .mavenLocalRepository(System.getProperty("mavenRepoPath")) // - .waitStartTime(30) // - .build()) - { - distributionTester.start("--create-startd", "--approve-all-licenses", "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,jmx-remote,servlet,servlets"); - distributionTester.stop(); - - File war = distributionTester.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + System.getProperty("jetty_version")); - distributionTester.installWarFile(war, "test"); - distributionTester.start() // - .assertLogsContains("Started @") // - .assertUrlStatus("/test/index.jsp", 200) // - .assertUrlContains("/test/index.jsp", "Hello"); - } - - } -} diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java deleted file mode 100644 index fcf8300b7f9..00000000000 --- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/JpmsActivatedTests.java +++ /dev/null @@ -1,52 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.tests.distribution; - -import java.io.File; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledOnJre; -import org.junit.jupiter.api.condition.JRE; - -public class JpmsActivatedTests -{ - @Test - @DisabledOnJre(JRE.JAVA_8) - public void jpms_activated() throws Exception - { - - try(DistributionTester distributionTester = DistributionTester.Builder.newInstance() // - .jettyVersion(System.getProperty("jetty_version")) // - .mavenLocalRepository(System.getProperty("mavenRepoPath")) // - .waitStartTime(30) // - .build()) - { - distributionTester.start("--create-startd", "--approve-all-licenses", "--add-to-start=resources,server,http,webapp,deploy,jsp,jmx,jmx-remote,servlet,servlets"); - distributionTester.stop(); - - File war = distributionTester.resolveArtifact("org.eclipse.jetty.tests:test-simple-webapp:war:" + System.getProperty("jetty_version")); - distributionTester.installWarFile(war, "test"); - distributionTester.start("--jpms") // - .assertLogsContains("Started @") // - .assertUrlStatus("/test/index.jsp", 200) - .assertUrlContains("/test/index.jsp", "Hello"); - } - - } -} diff --git a/tests/test-distribution/src/test/resources/index.html b/tests/test-distribution/src/test/resources/index.html deleted file mode 100644 index 97fa4767509..00000000000 --- a/tests/test-distribution/src/test/resources/index.html +++ /dev/null @@ -1 +0,0 @@ -Some content here \ No newline at end of file diff --git a/tests/test-distribution/src/test/resources/jetty-logging.properties b/tests/test-distribution/src/test/resources/jetty-logging.properties new file mode 100644 index 00000000000..d96a696f82e --- /dev/null +++ b/tests/test-distribution/src/test/resources/jetty-logging.properties @@ -0,0 +1,2 @@ +org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog +#org.eclipse.jetty.LEVEL=DEBUG diff --git a/tests/test-distribution/src/test/resources/static_content.xml b/tests/test-distribution/src/test/resources/static_content.xml deleted file mode 100644 index 87312cdbaac..00000000000 --- a/tests/test-distribution/src/test/resources/static_content.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - /scratch - - - - true - - - \ No newline at end of file From 3c665dfc1c0df47613982d94fd6854ad64ccbc96 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 11 Feb 2019 21:36:14 +0100 Subject: [PATCH 10/14] Issue #3343 - Add an API/tools to be able to test Jetty Distribution. Added missing license header. Signed-off-by: Simone Bordet --- .../distribution/AbstractDistributionTest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/AbstractDistributionTest.java b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/AbstractDistributionTest.java index f345b53e846..1050918ed13 100644 --- a/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/AbstractDistributionTest.java +++ b/tests/test-distribution/src/test/java/org/eclipse/jetty/tests/distribution/AbstractDistributionTest.java @@ -1,3 +1,21 @@ +// +// ======================================================================== +// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + package org.eclipse.jetty.tests.distribution; import java.util.function.Supplier; From 9c59db6fdd917bc7b50af9a72db06b062edc357d Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Mon, 11 Feb 2019 21:41:29 +0100 Subject: [PATCH 11/14] Issue #3343 - Add an API/tools to be able to test Jetty Distribution. Updated maven.version to 3.6.0. Signed-off-by: Simone Bordet --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 618abf07342..a2f6ebbe413 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 1.2.0 1.1.5 5.3.1 - 3.5.0 + 3.6.0 3.1.0 2.4.5.Final 1.0.5 From a1a02d99420ede9af8af956414a04a4c399a6636 Mon Sep 17 00:00:00 2001 From: olivier lamy Date: Tue, 12 Feb 2019 12:25:57 +1000 Subject: [PATCH 12/14] fix CI test, distribution must be build first as we want to use a fresh build of the distro Signed-off-by: olivier lamy --- tests/test-distribution/pom.xml | 6 ++++++ .../jetty/tests/distribution/DistributionTester.java | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/tests/test-distribution/pom.xml b/tests/test-distribution/pom.xml index a2e8a386e72..81887312760 100644 --- a/tests/test-distribution/pom.xml +++ b/tests/test-distribution/pom.xml @@ -16,6 +16,12 @@ + + org.eclipse.jetty + jetty-distribution + ${project.version} + zip + org.slf4j slf4j-simple 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 3a29dff86fa..64ea31fac53 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 @@ -305,6 +305,14 @@ public class DistributionTester private String jettyVersion; private String mavenLocalRepository = System.getProperty("user.home") + "/.m2/repository"; private Map mavenRemoteRepositories = new HashMap<>(); + + @Override + public String toString() + { + return "Config{" + "jettyBase=" + jettyBase + ", jettyHome=" + jettyHome + ", jettyVersion='" + jettyVersion + + '\'' + ", mavenLocalRepository='" + mavenLocalRepository + '\'' + ", mavenRemoteRepositories=" + + mavenRemoteRepositories + '}'; + } } /** From 2d88b3b9597b3b5ffea80b60a421b0fdf948a128 Mon Sep 17 00:00:00 2001 From: Simone Bordet Date: Tue, 12 Feb 2019 09:04:45 +0100 Subject: [PATCH 13/14] Issue #3343 - Add an API/tools to be able to test Jetty Distribution. Refactored streamers into class Run. Added javadocs. Moved "maven.resolver.version" to main POM for consistency. Signed-off-by: Simone Bordet --- pom.xml | 1 + tests/test-distribution/pom.xml | 7 +- .../distribution/DistributionTester.java | 216 +++++++++++------- .../tests/distribution/DistributionTests.java | 15 +- 4 files changed, 148 insertions(+), 91 deletions(-) diff --git a/pom.xml b/pom.xml index a2f6ebbe413..8a9f39dab55 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,7 @@ 1.1.5 5.3.1 3.6.0 + 1.3.1 3.1.0 2.4.5.Final 1.0.5 diff --git a/tests/test-distribution/pom.xml b/tests/test-distribution/pom.xml index 81887312760..3a938007a0c 100644 --- a/tests/test-distribution/pom.xml +++ b/tests/test-distribution/pom.xml @@ -12,7 +12,6 @@ ${project.groupId}.tests.distribution - 1.3.1 @@ -43,17 +42,17 @@ org.apache.maven.resolver maven-resolver-connector-basic - ${mavenResolver.version} + ${maven.resolver.version} org.apache.maven.resolver maven-resolver-transport-file - ${mavenResolver.version} + ${maven.resolver.version} org.apache.maven.resolver maven-resolver-transport-http - ${mavenResolver.version} + ${maven.resolver.version} 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)); From 265cc79225faa47bd638961e98e5f7850ac686d2 Mon Sep 17 00:00:00 2001 From: olivier lamy Date: Tue, 12 Feb 2019 18:22:39 +1000 Subject: [PATCH 14/14] jetty-distribution is test scope Signed-off-by: olivier lamy --- tests/test-distribution/pom.xml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/test-distribution/pom.xml b/tests/test-distribution/pom.xml index 3a938007a0c..84002f6b15c 100644 --- a/tests/test-distribution/pom.xml +++ b/tests/test-distribution/pom.xml @@ -15,12 +15,6 @@ - - org.eclipse.jetty - jetty-distribution - ${project.version} - zip - org.slf4j slf4j-simple @@ -55,6 +49,13 @@ ${maven.resolver.version} + + org.eclipse.jetty + jetty-distribution + ${project.version} + zip + test + org.eclipse.jetty jetty-client