Merged branch 'jetty-9.4.x' into 'jetty-10.0.x'.
Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
commit
5ce3d1bd61
|
@ -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())
|
||||
|
|
|
@ -135,7 +135,7 @@ public class CrossOriginFilterTest
|
|||
Set<String> 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));
|
||||
}
|
||||
|
||||
|
|
3
pom.xml
3
pom.xml
|
@ -36,7 +36,8 @@
|
|||
<tycho-version>1.2.0</tycho-version>
|
||||
<cbi-plugins.version>1.1.5</cbi-plugins.version>
|
||||
<junit.version>5.3.1</junit.version>
|
||||
<maven.version>3.5.0</maven.version>
|
||||
<maven.version>3.6.0</maven.version>
|
||||
<maven.resolver.version>1.3.1</maven.resolver.version>
|
||||
<weld.version>2.4.5.Final</weld.version>
|
||||
<jetty.perf-helper.version>1.0.5</jetty.perf-helper.version>
|
||||
<unix.socket.tmp></unix.socket.tmp>
|
||||
|
|
|
@ -68,5 +68,6 @@
|
|||
<module>test-quickstart</module>
|
||||
<module>test-jmx</module>
|
||||
<module>test-http-client-transport</module>
|
||||
<module>test-distribution</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>tests-parent</artifactId>
|
||||
<version>10.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>test-distribution</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.tests.distribution</bundle-symbolic-name>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-artifact</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven</groupId>
|
||||
<artifactId>maven-resolver-provider</artifactId>
|
||||
<version>${maven.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>maven-resolver-connector-basic</artifactId>
|
||||
<version>${maven.resolver.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>maven-resolver-transport-file</artifactId>
|
||||
<version>${maven.resolver.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.resolver</groupId>
|
||||
<artifactId>maven-resolver-transport-http</artifactId>
|
||||
<version>${maven.resolver.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-distribution</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>zip</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.http2</groupId>
|
||||
<artifactId>http2-http-client-transport</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-simple-webapp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<mavenRepoPath>${settings.localRepository}</mavenRepoPath>
|
||||
<jettyVersion>${project.version}</jettyVersion>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,601 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.BufferedReader;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
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.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
|
||||
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.util.IO;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/**
|
||||
* <p>Helper class to test the Jetty Distribution</p>.
|
||||
* <p>API can change without any further notice.</p>
|
||||
* <p>Usage:</p>
|
||||
* <pre>
|
||||
* // 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());
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public class DistributionTester
|
||||
{
|
||||
private static final Logger LOGGER = Log.getLogger(DistributionTester.class);
|
||||
|
||||
private Config config;
|
||||
|
||||
private DistributionTester(Config config)
|
||||
{
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the distribution with the given arguments
|
||||
*
|
||||
* @param args arguments to use to start the distribution
|
||||
*/
|
||||
public DistributionTester.Run start(String... args) throws Exception
|
||||
{
|
||||
return start(Arrays.asList(args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the distribution with the arguments
|
||||
*
|
||||
* @param args arguments to use to start the distribution
|
||||
*/
|
||||
public DistributionTester.Run start(List<String> args) throws Exception
|
||||
{
|
||||
List<String> commands = new ArrayList<>();
|
||||
commands.add(getJavaExecutable());
|
||||
commands.add("-jar");
|
||||
commands.add(config.jettyHome.toAbsolutePath() + "/start.jar");
|
||||
commands.addAll(args);
|
||||
|
||||
File workingDir = config.jettyBase.toFile();
|
||||
LOGGER.info("Executing: {}", commands);
|
||||
LOGGER.info("Working Dir: {}", workingDir.getAbsolutePath());
|
||||
|
||||
ProcessBuilder pbCmd = new ProcessBuilder(commands);
|
||||
pbCmd.directory(workingDir);
|
||||
Process process = pbCmd.start();
|
||||
|
||||
return new Run(process);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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())
|
||||
{
|
||||
server.setReuseAddress(true);
|
||||
server.bind(new InetSocketAddress("localhost", 0));
|
||||
return server.getLocalPort();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
Path webapps = Paths.get(config.jettyBase.toString(), "webapps", context);
|
||||
if (!Files.exists(webapps))
|
||||
Files.createDirectories(webapps);
|
||||
unzip(warFile, webapps.toFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves an artifact given its Maven coordinates.
|
||||
*
|
||||
* @param coordinates <groupId>:<artifactId>[:<extension>[:<classifier>]]:<version>
|
||||
* @return the artifact
|
||||
* @see #installWarFile(File, String)
|
||||
*/
|
||||
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());
|
||||
ArtifactResult artifactResult = repositorySystem.resolveArtifact(session, artifactRequest);
|
||||
|
||||
artifact = artifactResult.getArtifact();
|
||||
return artifact.getFile();
|
||||
}
|
||||
|
||||
private void init() throws Exception
|
||||
{
|
||||
if (config.jettyHome == null)
|
||||
config.jettyHome = resolveDistribution(config.jettyVersion);
|
||||
|
||||
if (config.jettyBase == null)
|
||||
{
|
||||
config.jettyBase = Files.createTempDirectory("jetty_base_");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!config.jettyBase.isAbsolute())
|
||||
config.jettyBase = config.jettyHome.resolve(config.jettyBase);
|
||||
}
|
||||
}
|
||||
|
||||
private String getJavaExecutable()
|
||||
{
|
||||
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 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_home_");
|
||||
File tmpFile = tmp.toFile();
|
||||
|
||||
unzip(artifactFile, tmpFile);
|
||||
|
||||
return tmp.resolve("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<RemoteRepository> newRepositories()
|
||||
{
|
||||
List<RemoteRepository> remoteRepositories = new ArrayList<>(config.mavenRemoteRepositories.size() + 1);
|
||||
config.mavenRemoteRepositories.forEach((key, value) -> remoteRepositories.add(new RemoteRepository.Builder(key, "default", value).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)
|
||||
{
|
||||
DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
|
||||
|
||||
LocalRepository localRepo = new LocalRepository(config.mavenLocalRepository);
|
||||
session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo));
|
||||
|
||||
session.setTransferListener(new LogTransferListener());
|
||||
session.setRepositoryListener(new LogRepositoryListener());
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
private static class Config
|
||||
{
|
||||
private Path jettyBase;
|
||||
private Path jettyHome;
|
||||
private String jettyVersion;
|
||||
private String mavenLocalRepository = System.getProperty("user.home") + "/.m2/repository";
|
||||
private Map<String, String> mavenRemoteRepositories = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s@%x{jettyBase=%s, jettyHome=%s, jettyVersion=%s, mavenLocalRepository=%s, mavenRemoteRepositories=%s}",
|
||||
getClass().getSimpleName(),
|
||||
hashCode(),
|
||||
jettyBase,
|
||||
jettyHome,
|
||||
jettyVersion,
|
||||
mavenLocalRepository,
|
||||
mavenRemoteRepositories);
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A distribution run wraps the process that started the Jetty distribution.
|
||||
*/
|
||||
public static class Run implements Closeable
|
||||
{
|
||||
private final Process process;
|
||||
private final List<ConsoleStreamer> consoleStreamers = new ArrayList<>();
|
||||
private final List<String> logs = new ArrayList<>();
|
||||
|
||||
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 process 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
|
||||
{
|
||||
boolean result = process.waitFor(time, unit);
|
||||
if (result)
|
||||
stopConsoleStreamers();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 process.
|
||||
*
|
||||
* @see #awaitFor(long, TimeUnit)
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
process.destroy();
|
||||
stopConsoleStreamers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forcibly destroys the distribution process.
|
||||
*/
|
||||
public void destroy()
|
||||
{
|
||||
process.destroyForcibly();
|
||||
stopConsoleStreamers();
|
||||
}
|
||||
|
||||
private void stopConsoleStreamers()
|
||||
{
|
||||
consoleStreamers.forEach(ConsoleStreamer::stop);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #destroy()
|
||||
*/
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
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);
|
||||
while (System.nanoTime() < end)
|
||||
{
|
||||
boolean result = logs.stream().anyMatch(s -> s.contains(txt));
|
||||
if (result)
|
||||
return true;
|
||||
Thread.sleep(250);
|
||||
}
|
||||
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
|
||||
{
|
||||
private Config config = new Config();
|
||||
|
||||
private Builder()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
config.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(Path jettyHome)
|
||||
{
|
||||
config.jettyHome = jettyHome;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Sets the path for the Jetty Base directory.</p>
|
||||
* <p>If the path is relative, it will be resolved against the Jetty Home directory.</p>
|
||||
*
|
||||
* @param jettyBase Path to the local Jetty Base directory
|
||||
* @return the {@link Builder}
|
||||
*/
|
||||
public Builder jettyBase(Path jettyBase)
|
||||
{
|
||||
config.jettyBase = jettyBase;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mavenLocalRepository Path to the local maven repository
|
||||
* @return the {@link Builder}
|
||||
*/
|
||||
public Builder mavenLocalRepository(String mavenLocalRepository)
|
||||
{
|
||||
config.mavenLocalRepository = mavenLocalRepository;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If needed to resolve the Jetty distribution 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)
|
||||
{
|
||||
config.mavenRemoteRepositories.put(id, url);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return an empty instance of {@link Builder}
|
||||
*/
|
||||
public static Builder newInstance()
|
||||
{
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a new configured instance of {@link DistributionTester}
|
||||
*/
|
||||
public DistributionTester build() throws Exception
|
||||
{
|
||||
DistributionTester tester = new DistributionTester(config);
|
||||
tester.init();
|
||||
return tester;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
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<HttpClient> supplier) throws Exception
|
||||
{
|
||||
client = supplier.get();
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void dispose() throws Exception
|
||||
{
|
||||
if (client != null)
|
||||
client.stop();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.freePort();
|
||||
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.freePort();
|
||||
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.freePort();
|
||||
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.freePort();
|
||||
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.freePort();
|
||||
try (DistributionTester.Run run1 = distribution.start("jetty.http.port=" + port))
|
||||
{
|
||||
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("<%")));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
#org.eclipse.jetty.LEVEL=DEBUG
|
|
@ -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";
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ import org.junit.jupiter.api.Disabled;
|
|||
public class TestableJettyServer
|
||||
{
|
||||
private List<URL> _xmlConfigurations;
|
||||
private final Map<String,String> _properties = new HashMap<String, String>();
|
||||
private final Map<String,String> _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<URL>();
|
||||
_xmlConfigurations = new ArrayList<>();
|
||||
Properties properties = new Properties();
|
||||
|
||||
/* Establish Popular Directories */
|
||||
|
|
|
@ -39,5 +39,6 @@
|
|||
<module>test-jaas-webapp</module>
|
||||
<module>test-jndi-webapp</module>
|
||||
<module>test-http2-webapp</module>
|
||||
<module>test-simple-webapp</module>
|
||||
</modules>
|
||||
</project>
|
||||
</project>
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty.tests</groupId>
|
||||
<artifactId>test-webapps-parent</artifactId>
|
||||
<version>10.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>test-simple-webapp</artifactId>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<name>Test :: Jetty Test Simple Webapp</name>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app
|
||||
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||
metadata-complete="false"
|
||||
version="3.1">
|
||||
|
||||
<display-name>Very Simple Web Application</display-name>
|
||||
</web-app>
|
|
@ -0,0 +1,5 @@
|
|||
<html>
|
||||
<body>
|
||||
<h2>Hello World!</h2>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue