Reorganized and refactored JettyHomeTester to introduce JPMSTester. (#11228)

* Renamed module "jetty-home-tester" to "jetty-testers".
* Moved JettyHomeTester to module jetty-testers.
* Introduced JPMSTester, refactoring common code with JettyHomeTester.
* Changed File-based APIs in favor of Path APIs.
* Introduced ProcessWrapper to simplify process forking.
* Refactored tests to follow refactoring changes.

Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
Simone Bordet 2024-01-24 18:56:27 +01:00 committed by GitHub
parent 3853628074
commit ce928e5ff1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 1431 additions and 1193 deletions

View File

@ -37,7 +37,7 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>jetty-home-tester</artifactId>
<artifactId>jetty-testers</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>

View File

@ -29,7 +29,7 @@ import org.asciidoctor.ast.Document;
import org.asciidoctor.extension.IncludeProcessor;
import org.asciidoctor.extension.PreprocessorReader;
import org.asciidoctor.jruby.extension.spi.ExtensionRegistry;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
/**
* <p>Asciidoctor <em>include</em> extension that includes into

View File

@ -873,12 +873,12 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>jetty-home-tester</artifactId>
<artifactId>jetty-test-session-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>jetty-test-session-common</artifactId>
<artifactId>jetty-testers</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>

View File

@ -1,100 +0,0 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>tests</artifactId>
<version>12.0.6-SNAPSHOT</version>
</parent>
<artifactId>jetty-home-tester</artifactId>
<packaging>jar</packaging>
<name>Tests :: Home Tester</name>
<properties>
<bundle-symbolic-name>${project.groupId}.hometester</bundle-symbolic-name>
</properties>
<dependencies>
<dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
<version>1.0.5</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-resolver-provider</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-api</artifactId>
<version>${maven.resolver.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-impl</artifactId>
<version>${maven.resolver.version}</version>
<exclusions>
<!-- Used when running in SISU container to manage beans lifecycle (of locking factories) -->
<exclusion>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-spi</artifactId>
<version>${maven.resolver.version}</version>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-supplier</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.apache.maven.resolver</groupId>
<artifactId>maven-resolver-util</artifactId>
<version>${maven.resolver.version}</version>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,838 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.tests.hometester;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.URI;
import java.nio.file.CopyOption;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
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.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import org.apache.maven.model.building.ModelBuilder;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
import org.awaitility.core.ConditionTimeoutException;
import org.codehaus.plexus.util.StringUtils;
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.impl.RemoteRepositoryManager;
import org.eclipse.aether.impl.UpdatePolicyAnalyzer;
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.checksum.ChecksumPolicyProvider;
import org.eclipse.aether.supplier.RepositorySystemSupplier;
import org.eclipse.aether.transfer.AbstractTransferListener;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.IO;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.awaitility.Awaitility.await;
/**
* <p>Helper class to test the Jetty Distribution</p>.
* <p>API can change without any further notice.</p>
* <p>Usage:</p>
* <pre>{@code
* // 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-start-ini", "--add-modules=http2c,jsp,deploy"))
* {
* assertTrue(run1.awaitFor(5, TimeUnit.SECONDS));
* assertEquals(0, run1.getExitValue());
*
* // Install a web application.
* File war = distribution.resolveArtifact("org.eclipse.jetty.demos:demo-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 an HTTP request to the web application.
* HttpClient client = new HttpClient();
* client.start();
* ContentResponse response = client.GET("http://localhost:" + port + "/test/index.html");
* assertEquals(HttpStatus.OK_200, response.getStatus());
* }
* }
* }</pre>
*/
public class JettyHomeTester
{
private static final Logger LOGGER = LoggerFactory.getLogger(JettyHomeTester.class);
private static final CopyOption[] EMPTY_OPTIONS = new CopyOption[]{};
private final Config config;
private JettyHomeTestsRepositorySystemSupplier jettyHomeTestsRepositorySystemSupplier = new JettyHomeTestsRepositorySystemSupplier();
private JettyHomeTester(Config config)
{
this.config = config;
}
/**
* Starts the distribution with the given arguments
*
* @param args arguments to use to start the distribution
*/
public JettyHomeTester.Run start(String... args) throws Exception
{
return start(Arrays.asList(args));
}
public Path getJettyBase()
{
return config.getJettyBase();
}
public Path getJettyHome()
{
return config.getJettyHome();
}
/**
* Start the distribution with the arguments
*
* @param args arguments to use to start the distribution
*/
public JettyHomeTester.Run start(List<String> args) throws Exception
{
File jettyBaseDir = getJettyBase().toFile();
Path workDir = Files.createDirectories(jettyBaseDir.toPath().resolve("work"));
List<String> commands = new ArrayList<>();
commands.add(getJavaExecutable());
commands.addAll(config.getJVMArgs());
commands.add("-Djava.io.tmpdir=" + workDir.toAbsolutePath());
int debugPort = Integer.getInteger("distribution.debug.port", 0);
if (debugPort > 0)
{
commands.add("-Xdebug");
commands.add("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=" + debugPort);
}
commands.add("-jar");
commands.add(config.jettyHome.toAbsolutePath() + "/start.jar");
args = new ArrayList<>(args);
String mavenLocalRepository = config.getMavenLocalRepository();
if (StringUtils.isNotBlank(mavenLocalRepository))
mavenLocalRepository = System.getProperty("mavenRepoPath");
if (StringUtils.isNotBlank(mavenLocalRepository))
args.add("maven.local.repo=" + mavenLocalRepository);
// if this JVM has `maven.repo.uri` defined, make sure to propagate it to child
String remoteRepoUri = System.getProperty("maven.repo.uri");
if (remoteRepoUri != null)
{
args.add("maven.repo.uri=" + remoteRepoUri);
}
commands.addAll(args);
LOGGER.info("Executing: {}", commands);
LOGGER.info("Working Dir: {}", jettyBaseDir.getAbsolutePath());
ProcessBuilder pbCmd = new ProcessBuilder(commands);
pbCmd.directory(jettyBaseDir);
pbCmd.environment().putAll(config.env);
Process process = pbCmd.start();
return new Run(config, 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 testResourcePath the location of the source file in {@code src/test/resources}
* @param baseResourcePath the location of the destination file in {@code ${jetty.base}}
* @param options optional CopyOption
* @throws IOException if the installation fails
*/
public void installBaseResource(String testResourcePath, String baseResourcePath, CopyOption... options) throws IOException
{
Path srcFile = MavenTestingUtils.getTestResourcePath(testResourcePath);
Path destFile = config.jettyBase.resolve(baseResourcePath);
Files.deleteIfExists(destFile);
if (!Files.exists(destFile.getParent()))
Files.createDirectories(destFile.getParent());
Files.copy(srcFile, destFile, options);
}
/**
* 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
* @return the path to the installed webapp exploded directory
* @throws IOException if the installation fails
*/
public Path installWarFile(File warFile, String context) throws IOException
{
//webapps
Path webapps = config.jettyBase.resolve("webapps").resolve(context);
if (!Files.exists(webapps))
Files.createDirectories(webapps);
unzip(warFile.toPath(), webapps);
return webapps;
}
/**
* Resolves an artifact given its Maven coordinates.
*
* @param coordinates &lt;groupId>:&lt;artifactId>[:&lt;extension>[:&lt;classifier>]]:&lt;version>
* @return the artifact
* @see #installWarFile(File, String)
*/
public File resolveArtifact(String coordinates) throws ArtifactResolutionException
{
RepositorySystem repositorySystem = this.jettyHomeTestsRepositorySystemSupplier.get();
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 = resolveHomeArtifact(config.getJettyVersion());
if (config.jettyBase == null)
{
Path bases = MavenTestingUtils.getTargetTestingPath("bases");
FS.ensureDirExists(bases);
config.jettyBase = Files.createTempDirectory(bases, "jetty_base_");
}
else
{
if (!config.jettyBase.isAbsolute())
{
throw new IllegalStateException("Jetty Base is not an absolute path: " + config.jettyBase);
}
}
}
private String getJavaExecutable()
{
String[] javaExecutables = new String[]{"java", "java.exe"};
Path javaBinDir = Paths.get(System.getProperty("java.home")).resolve("bin");
for (String javaExecutable : javaExecutables)
{
Path javaFile = javaBinDir.resolve(javaExecutable);
if (Files.exists(javaFile) && Files.isRegularFile(javaFile))
return javaFile.toAbsolutePath().toString();
}
return "java";
}
public static synchronized void unzip(Path archive, Path outputDir) throws IOException
{
if (!Files.exists(outputDir))
throw new FileNotFoundException("Directory does not exist: " + outputDir);
if (!Files.isDirectory(outputDir))
throw new FileNotFoundException("Not a directory: " + outputDir);
Map<String, String> env = new HashMap<>();
env.put("releaseVersion", null); // no MultiRelease Jar file behaviors
URI outputDirURI = outputDir.toUri();
URI archiveURI = URI.create("jar:" + archive.toUri().toASCIIString());
try (FileSystem fs = FileSystems.newFileSystem(archiveURI, env))
{
Path root = fs.getPath("/");
int archiveURISubIndex = root.toUri().toASCIIString().indexOf("!/") + 2;
try (Stream<Path> entriesStream = Files.walk(root))
{
// ensure proper unpack order (eg: directories before files)
List<Path> sorted = entriesStream
.sorted()
.toList();
for (Path path : sorted)
{
URI entryURI = path.toUri();
String subURI = entryURI.toASCIIString().substring(archiveURISubIndex);
URI outputPathURI = outputDirURI.resolve(subURI);
Path outputPath = Path.of(outputPathURI);
if (Files.isDirectory(path))
{
if (!Files.exists(outputPath))
Files.createDirectory(outputPath);
}
else
{
Files.copy(path, outputPath);
}
}
}
}
catch (FileAlreadyExistsException e)
{
LOGGER.warn("ignore FileAlreadyExistsException: archiveURI {}, outputDir {}", archiveURI, outputDir);
}
}
private Path resolveHomeArtifact(String version) throws Exception
{
Path artifactFile = resolveArtifact("org.eclipse.jetty:jetty-home:zip:" + version).toPath();
// create tmp directory to unzip distribution
Path homes = MavenTestingUtils.getTargetTestingPath("homes");
FS.ensureDirExists(homes);
Path tmp = Files.createDirectories(homes.resolve(Long.toString(artifactFile.toFile().lastModified())));
Path home = tmp.resolve("jetty-home-" + version);
if (!Files.exists(home))
{
unzip(artifactFile, tmp);
}
return home;
}
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;
}
public static class Config
{
private final Map<String, String> mavenRemoteRepositories = new HashMap<>();
private Path jettyBase;
private Path jettyHome;
private String jettyVersion;
private String mavenLocalRepository = System.getProperty("mavenRepoPath", System.getProperty("user.home") + "/.m2/repository");
private List<String> jvmArgs = new ArrayList<>();
private Map<String, String> env = new HashMap<>();
public Path getJettyBase()
{
return jettyBase;
}
public Path getJettyHome()
{
return jettyHome;
}
public String getJettyVersion()
{
return jettyVersion;
}
public String getMavenLocalRepository()
{
return mavenLocalRepository;
}
public List<String> getJVMArgs()
{
return Collections.unmodifiableList(jvmArgs);
}
public Map<String, String> getEnv()
{
return Collections.unmodifiableMap(env);
}
@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 Config config;
private final Process process;
private final List<ConsoleStreamer> consoleStreamers = new ArrayList<>();
private final Queue<String> logs = new ConcurrentLinkedQueue<>();
private Run(Config config, Process process)
{
this.config = config;
this.process = process;
consoleStreamers.add(startPump("STDOUT", process.getInputStream()));
consoleStreamers.add(startPump("STDERR", process.getErrorStream()));
}
public Config getConfig()
{
return config;
}
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);
}
@Override
public void close()
{
stop();
// delete the content of temporary base and home?
//IO.delete(this.config.getJettyBase());
//IO.delete(this.config.getJettyHome().getParent());
}
/**
* 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
{
try
{
await().atMost(time, unit).until(() -> logs.stream().anyMatch(s -> s.contains(txt)));
return true;
}
catch (ConditionTimeoutException e)
{
return false;
}
}
/**
* Awaits the logs file to contain the given text, for the given amount of time.
*
* @param logFile the log file to test
* @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 awaitLogsFileFor(Path logFile, String txt, long time, TimeUnit unit) throws InterruptedException
{
LogFileStreamer logFileStreamer = new LogFileStreamer(logFile);
Thread thread = new Thread(logFileStreamer, "LogFileStreamer/" + logFile);
thread.start();
try
{
await().atMost(time, unit).until(() -> logs.stream().anyMatch(s -> s.contains(txt)));
return true;
}
catch (ConditionTimeoutException e)
{
return false;
}
finally
{
logFileStreamer.stop();
}
}
/**
* 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);
}
}
private class LogFileStreamer implements Runnable
{
private RandomAccessFile inputFile;
private volatile boolean stop;
private final Path logFile;
public LogFileStreamer(Path logFile)
{
this.logFile = logFile;
}
@Override
public void run()
{
String currentLine;
long pos = 0;
while (!stop)
{
try
{
inputFile = new RandomAccessFile(logFile.toFile(), "r");
inputFile.seek(pos);
if ((currentLine = inputFile.readLine()) != null)
{
logs.add(currentLine);
}
pos = inputFile.getFilePointer();
}
catch (IOException e)
{
//ignore
}
finally
{
IO.close(inputFile);
}
}
}
public void stop()
{
stop = true;
IO.close(inputFile);
}
}
public Queue<String> getLogs()
{
return logs;
}
}
public static class Builder
{
private final 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 this 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 this 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 this Builder
*/
public Builder jettyBase(Path jettyBase)
{
config.jettyBase = jettyBase;
return this;
}
/**
* @param mavenLocalRepository Path to the local maven repository
* @return this Builder
*/
public Builder mavenLocalRepository(String mavenLocalRepository)
{
if (StringUtils.isBlank(mavenLocalRepository))
return this;
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 this Builder
*/
public Builder addRemoteRepository(String id, String url)
{
config.mavenRemoteRepositories.put(id, url);
return this;
}
/**
* @param jvmArgs the jvm args to add
* @return this Builder
*/
public Builder jvmArgs(List<String> jvmArgs)
{
config.jvmArgs = jvmArgs;
return this;
}
/**
* @param env the env to add
* @return this Builder
*/
public Builder env(Map<String, String> env)
{
config.env = env;
return this;
}
/**
* @return an empty instance of Builder
*/
public static Builder newInstance()
{
return new Builder();
}
/**
* @return a new configured instance of {@link JettyHomeTester}
*/
public JettyHomeTester build() throws Exception
{
JettyHomeTester tester = new JettyHomeTester(config);
tester.init();
return tester;
}
}
private static class JettyHomeTestsRepositorySystemSupplier extends RepositorySystemSupplier
{
ModelBuilder modelBuilder;
RemoteRepositoryManager remoteRepositoryManager;
@Override
protected ModelBuilder getModelBuilder()
{
modelBuilder = super.getModelBuilder();
return modelBuilder;
}
@Override
protected RemoteRepositoryManager getRemoteRepositoryManager(
UpdatePolicyAnalyzer updatePolicyAnalyzer, ChecksumPolicyProvider checksumPolicyProvider)
{
remoteRepositoryManager = super.getRemoteRepositoryManager(updatePolicyAnalyzer, checksumPolicyProvider);
return remoteRepositoryManager;
}
}
}

View File

@ -0,0 +1,42 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>tests</artifactId>
<version>12.0.6-SNAPSHOT</version>
</parent>
<artifactId>jetty-testers</artifactId>
<packaging>jar</packaging>
<name>Tests :: Testers</name>
<properties>
<bundle-symbolic-name>${project.groupId}.testers</bundle-symbolic-name>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-supplier</artifactId>
<version>${maven.resolver.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-xml</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,351 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.tests.testers;
import java.io.File;
import java.io.IOException;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.IO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <p>Helper class to test JPMS applications, that will be run in
* a forked JVM with the parameters specified to {@link Builder}.</p>
* <p>APIs can change without any further notice.</p>
* <p>Usage:</p>
* <pre>{@code
* String jettyVersion = "12.0.0";
* try (JPMSTester app = new JPMSTester.Builder(workDirPath)
* .jvmArgs("-Xmx1G")
* // Your application module-info source, will be compiled on-the-fly.
* .moduleInfo("""
* module app
* {
* requires ...;
* exports ...;
* }
* """)
* // Add the JPMS module dependencies required by your application.
* .addToModulePath("org.eclipse.jetty:jetty-jetty-client:" + jettyVersion)
* .mainClass(Main.class)
* .args(networkPort)
* .build())
* {
* // Your main class will run and produce some output in console.
* assertTrue(app.awaitConsoleLogsFor("DONE", Duration.ofSeconds(10)));
* }
* }</pre>
*/
public class JPMSTester extends ProcessWrapper
{
private static final Logger LOG = LoggerFactory.getLogger(JPMSTester.class);
private final Config config;
private JPMSTester(Config config, Process process)
{
super(process);
this.config = config;
}
/**
* @return the configuration of this instance
*/
public Config getConfig()
{
return config;
}
/**
* <p>The configuration of a {@link JPMSTester}.</p>
*/
public static class Config
{
private Path workDir;
private List<String> jvmArgs;
private String moduleInfo;
private final List<Path> modulePaths = new ArrayList<>();
private final List<Path> classPaths = new ArrayList<>();
private Class<?> mainClass;
private List<String> args;
public List<String> getJVMArgs()
{
return jvmArgs == null ? List.of() : jvmArgs;
}
public Path getWorkingDirectory()
{
return workDir;
}
public String getModuleInfo()
{
return moduleInfo;
}
public List<Path> getModulePaths()
{
return modulePaths;
}
public List<Path> getClassPaths()
{
return classPaths;
}
public Class<?> getMainClass()
{
return mainClass;
}
public List<String> getArgs()
{
return args == null ? List.of() : args;
}
}
/**
* <p>A builder for {@link JPMSTester}.</p>
*/
public static class Builder
{
private final MavenHelper mavenHelper = new MavenHelper();
private final Config config = new Config();
private Path classesDir;
/**
* <p>Creates a new instance with the specified root directory.</p>
* <p>The root directory will be the root of possibly many application modules,
* and will be used to create an application-specific subdirectory for each
* JPMS applications, so that for example a client and a server JPMS applications
* are grouped under the same root directory.</p>
*
* @param rootDir the root directory
* @throws IOException if the application-specific subdirectory cannot be created
* @see #build()
*/
public Builder(Path rootDir) throws IOException
{
FS.ensureDirExists(rootDir);
config.workDir = Files.createTempDirectory(rootDir, "jpms");
}
/**
* @param jvmArgs the JVM arguments
* @return this instance
*/
public Builder jvmArgs(String... jvmArgs)
{
config.jvmArgs = List.of(jvmArgs);
return this;
}
/**
* @param classesDir the root directory of the compiles classes of this application
* @return this instance
*/
public Builder classesDirectory(Path classesDir)
{
this.classesDir = classesDir;
return this;
}
/**
* @param moduleInfo the source of this application {@code module-info.java}
* @return this instance
*/
public Builder moduleInfo(String moduleInfo)
{
config.moduleInfo = moduleInfo;
return this;
}
/**
* <p>Adds to the module-path the given Maven artifact.</p>
*
* @param mavenCoordinate the Maven coordinates of the artifact
* @return this instance
* @throws ArtifactResolutionException if the Maven artifact cannot be resolved
*/
public Builder addToModulePath(String mavenCoordinate) throws ArtifactResolutionException
{
return addToModulePath(mavenHelper.resolveArtifact(mavenCoordinate));
}
/**
* <p>Adds to the module-path the given path, either a directory or a jar file.</p>
*
* @param path the path or jar to add to the module-path
* @return this instance
*/
public Builder addToModulePath(Path path)
{
config.modulePaths.add(path);
return this;
}
/**
* <p>Adds to the class-path the given Maven artifact.</p>
*
* @param mavenCoordinate the Maven coordinates of the artifact
* @return this instance
* @throws ArtifactResolutionException if the Maven artifact cannot be resolved
*/
public Builder addToClassPath(String mavenCoordinate) throws ArtifactResolutionException
{
return addToClassPath(mavenHelper.resolveArtifact(mavenCoordinate));
}
/**
* <p>Adds to the class-path the given path, either a directory or a jar file.</p>
*
* @param path the path or jar to add to the class-path
* @return this instance
*/
public Builder addToClassPath(Path path)
{
config.classPaths.add(path);
return this;
}
/**
* <p>Specifies the main class of the JPMS application.</p>
* <p>The main class must be in the module specified by
* {@link #moduleInfo(String)} and publicly exported.</p>
*
* @param mainClass the JPMS application main class
* @return this instance
*/
public Builder mainClass(Class<?> mainClass)
{
config.mainClass = mainClass;
return this;
}
/**
* @param args the application arguments
* @return this instance
*/
public Builder args(String... args)
{
config.args = List.of(args);
return this;
}
/**
* <p>Builds a {@link JPMSTester} instance, forking a JVM with the parameters specified in this instance.</p>
* <p>The {@code module-info.java} source specified via {@link #moduleInfo(String)} will be compiled and
* saved in the application-specific subdirectory (see {@link #Builder(Path)}).</p>
* <p>The forked JVM working directory will be the application-specific subdirectory.</p>
*
* @return a {@link JPMSTester} instance
* @throws Exception in case of failures to either compile {@code module-info.java} or fork of the JVM
*/
public JPMSTester build() throws Exception
{
if (config.getModuleInfo() == null)
throw new IllegalArgumentException("missing module-info");
if (classesDir == null)
throw new IllegalArgumentException("missing classes directory");
if (config.getMainClass() == null)
throw new IllegalArgumentException("missing main class");
Path workDir = config.getWorkingDirectory();
IO.copyDir(classesDir, workDir);
String modulePath = config.getModulePaths().stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator));
if (!modulePath.isEmpty())
modulePath += File.pathSeparator;
modulePath += workDir.toString();
String classPath = config.getClassPaths().stream().map(Path::toString).collect(Collectors.joining(File.pathSeparator));
ModuleReference module = compileModuleInfo(modulePath, classPath);
List<String> commands = new ArrayList<>();
commands.add(Tester.getJavaExecutable("java"));
commands.addAll(config.getJVMArgs());
commands.add("--module-path");
commands.add(modulePath);
if (!classPath.isEmpty())
{
commands.add("--class-path");
commands.add(classPath);
}
commands.add("--module");
commands.add("%s/%s".formatted(module.descriptor().name(), config.getMainClass().getName()));
commands.addAll(config.getArgs());
LOG.info("executing: " + String.join(" ", commands));
ProcessBuilder processBuilder = new ProcessBuilder(commands);
processBuilder.directory(workDir.toFile());
return new JPMSTester(config, processBuilder.start());
}
private ModuleReference compileModuleInfo(String modulePath, String classPath) throws Exception
{
List<String> commands = new ArrayList<>();
commands.add(Tester.getJavaExecutable("javac"));
commands.add("--module-path");
commands.add(modulePath);
if (!classPath.isEmpty())
{
commands.add("--class-path");
commands.add(classPath);
}
Path workDir = config.getWorkingDirectory();
Path moduleInfoPath = workDir.resolve("module-info.java");
Files.writeString(moduleInfoPath, config.getModuleInfo(), StandardCharsets.US_ASCII, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);
commands.add(moduleInfoPath.toString());
// This additional class is necessary to be able to compile module-info.java.
// There should be one additional class for every exported package, but just
// use the one derived from the main class for now.
String packageName = config.getMainClass().getPackageName();
Path bogusClassPath = workDir.resolve(packageName.replace('.', '/')).resolve("Bogus.java");
Files.writeString(bogusClassPath, "package %s; class Bogus {}".formatted(packageName), StandardCharsets.US_ASCII, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE);
commands.add(bogusClassPath.toString());
LOG.info("executing: " + String.join(" ", commands));
ProcessBuilder processBuilder = new ProcessBuilder(commands);
try (ProcessWrapper javac = new ProcessWrapper(processBuilder.start()))
{
javac.whenExit().orTimeout(10, TimeUnit.SECONDS).get();
}
if (!Files.exists(workDir.resolve("module-info.class")))
throw new IllegalStateException("could not compile module-info");
return ModuleFinder.of(workDir).findAll().stream().findAny().orElseThrow();
}
}
}

View File

@ -0,0 +1,450 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.tests.testers;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.nio.file.CopyOption;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
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.stream.Stream;
import org.codehaus.plexus.util.StringUtils;
import org.eclipse.aether.resolution.ArtifactResolutionException;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <p>Helper class to test the Jetty Distribution</p>.
* <p>API can change without any further notice.</p>
* <p>Usage:</p>
* <pre>{@code
* // Create the distribution.
* String jettyVersion = "12.0.0";
* JettyHomeTester distribution = JettyHomeTester.Builder.newInstance()
* .jettyVersion(jettyVersion)
* .jettyBase(Paths.get("demo-base"))
* .build();
*
* // The first run initializes the Jetty Base.
* try (JettyHomeTester.Run run1 = distribution.start("--create-start-ini", "--add-modules=http2c,jsp,deploy"))
* {
* assertTrue(run1.awaitFor(5, TimeUnit.SECONDS));
* assertEquals(0, run1.getExitValue());
*
* // Install a web application.
* Path war = distribution.resolveArtifact("org.eclipse.jetty.demos:demo-simple-webapp:war:" + jettyVersion);
* distribution.installWar(war, "test");
*
* // The second run starts the distribution.
* int port = 9090;
* try (JettyHomeTester.Run run = distribution.start("jetty.http.port=" + port))
* {
* // Wait for Jetty to be fully started.
* assertTrue(run1.awaitConsoleLogsFor("Started @", 20, TimeUnit.SECONDS));
*
* // Make an HTTP request to the web application.
* HttpClient client = new HttpClient();
* client.start();
* ContentResponse response = client.GET("http://localhost:" + port + "/test/index.html");
* assertEquals(HttpStatus.OK_200, response.getStatus());
* }
* }
* }</pre>
*/
public class JettyHomeTester
{
private static final Logger LOG = LoggerFactory.getLogger(JettyHomeTester.class);
private final MavenHelper mavenHelper = new MavenHelper();
private final Config config;
private JettyHomeTester(Config config)
{
this.config = config;
}
/**
* Starts the distribution with the given arguments
*
* @param args arguments to use to start the distribution
*/
public JettyHomeTester.Run start(String... args) throws Exception
{
return start(Arrays.asList(args));
}
public Path getJettyBase()
{
return config.getJettyBase();
}
public Path getJettyHome()
{
return config.getJettyHome();
}
/**
* Start the distribution with the arguments
*
* @param args arguments to use to start the distribution
*/
public JettyHomeTester.Run start(List<String> args) throws Exception
{
File jettyBaseDir = getJettyBase().toFile();
Path workDir = Files.createDirectories(jettyBaseDir.toPath().resolve("work"));
List<String> commands = new ArrayList<>();
commands.add(Tester.getJavaExecutable("java"));
commands.addAll(config.getJVMArgs());
commands.add("-Djava.io.tmpdir=" + workDir.toAbsolutePath());
int debugPort = Integer.getInteger("distribution.debug.port", 0);
if (debugPort > 0)
{
commands.add("-Xdebug");
commands.add("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=" + debugPort);
}
commands.add("-jar");
commands.add(config.jettyHome.toAbsolutePath() + "/start.jar");
args = new ArrayList<>(args);
String mavenLocalRepository = config.getMavenLocalRepository();
if (StringUtils.isNotBlank(mavenLocalRepository))
mavenLocalRepository = System.getProperty("mavenRepoPath");
if (StringUtils.isNotBlank(mavenLocalRepository))
args.add("maven.local.repo=" + mavenLocalRepository);
// if this JVM has `maven.repo.uri` defined, make sure to propagate it to child
String remoteRepoUri = System.getProperty("maven.repo.uri");
if (remoteRepoUri != null)
{
args.add("maven.repo.uri=" + remoteRepoUri);
}
commands.addAll(args);
LOG.info("Executing: {}", commands);
LOG.info("Working Dir: {}", jettyBaseDir.getAbsolutePath());
ProcessBuilder pbCmd = new ProcessBuilder(commands);
pbCmd.directory(jettyBaseDir);
pbCmd.environment().putAll(config.env);
Process process = pbCmd.start();
return new Run(process, config);
}
/**
* Installs in {@code ${jetty.base}/webapps} the given war file under the given context path.
*
* @param testResourcePath the location of the source file in {@code src/test/resources}
* @param baseResourcePath the location of the destination file in {@code ${jetty.base}}
* @param options optional CopyOption
* @throws IOException if the installation fails
*/
public void installBaseResource(String testResourcePath, String baseResourcePath, CopyOption... options) throws IOException
{
Path srcFile = MavenTestingUtils.getTestResourcePath(testResourcePath);
Path destFile = config.jettyBase.resolve(baseResourcePath);
Files.deleteIfExists(destFile);
if (!Files.exists(destFile.getParent()))
Files.createDirectories(destFile.getParent());
Files.copy(srcFile, destFile, options);
}
/**
* Installs in {@code ${jetty.base}/webapps} the given war file under the given context path.
*
* @param warPath the war file to install
* @param context the context path
* @return the path to the installed webapp exploded directory
* @throws IOException if the installation fails
*/
public Path installWar(Path warPath, String context) throws IOException
{
//webapps
Path webapps = config.jettyBase.resolve("webapps").resolve(context);
if (!Files.exists(webapps))
Files.createDirectories(webapps);
unzip(warPath, webapps);
return webapps;
}
public Path resolveArtifact(String mavenCoordinate) throws ArtifactResolutionException
{
return mavenHelper.resolveArtifact(mavenCoordinate);
}
private void init() throws Exception
{
if (config.jettyHome == null)
config.jettyHome = resolveHomeArtifact(config.getJettyVersion());
if (config.jettyBase == null)
{
Path bases = MavenTestingUtils.getTargetTestingPath("bases");
FS.ensureDirExists(bases);
config.jettyBase = Files.createTempDirectory(bases, "jetty_base_");
}
else
{
if (!config.jettyBase.isAbsolute())
{
throw new IllegalStateException("Jetty Base is not an absolute path: " + config.jettyBase);
}
}
}
public static void unzip(Path archive, Path outputDir) throws IOException
{
if (!Files.exists(outputDir))
throw new FileNotFoundException("Directory does not exist: " + outputDir);
if (!Files.isDirectory(outputDir))
throw new FileNotFoundException("Not a directory: " + outputDir);
Map<String, String> env = new HashMap<>();
env.put("releaseVersion", null); // no MultiRelease Jar file behaviors
URI outputDirURI = outputDir.toUri();
URI archiveURI = URI.create("jar:" + archive.toUri().toASCIIString());
try (FileSystem fs = FileSystems.newFileSystem(archiveURI, env))
{
Path root = fs.getPath("/");
int archiveURISubIndex = root.toUri().toASCIIString().indexOf("!/") + 2;
try (Stream<Path> entriesStream = Files.walk(root))
{
// ensure proper unpack order (eg: directories before files)
List<Path> sorted = entriesStream
.sorted()
.toList();
for (Path path : sorted)
{
URI entryURI = path.toUri();
String subURI = entryURI.toASCIIString().substring(archiveURISubIndex);
URI outputPathURI = outputDirURI.resolve(subURI);
Path outputPath = Path.of(outputPathURI);
if (Files.isDirectory(path))
{
if (!Files.exists(outputPath))
Files.createDirectory(outputPath);
}
else
{
Files.copy(path, outputPath);
}
}
}
}
catch (FileAlreadyExistsException e)
{
LOG.warn("ignore FileAlreadyExistsException: archiveURI {}, outputDir {}", archiveURI, outputDir);
}
}
private Path resolveHomeArtifact(String version) throws Exception
{
Path artifactFile = mavenHelper.resolveArtifact("org.eclipse.jetty:jetty-home:zip:" + version);
Path homes = MavenTestingUtils.getTargetTestingPath("homes");
FS.ensureDirExists(homes);
Path tmp = Files.createDirectories(homes.resolve(Long.toString(artifactFile.toFile().lastModified())));
Path home = tmp.resolve("jetty-home-" + version);
if (!Files.exists(home))
unzip(artifactFile, tmp);
return home;
}
public static class Config
{
private Path jettyBase;
private Path jettyHome;
private String jettyVersion;
private String mavenLocalRepository = System.getProperty("mavenRepoPath", System.getProperty("user.home") + "/.m2/repository");
private List<String> jvmArgs = new ArrayList<>();
private Map<String, String> env = new HashMap<>();
public Path getJettyBase()
{
return jettyBase;
}
public Path getJettyHome()
{
return jettyHome;
}
public String getJettyVersion()
{
return jettyVersion;
}
public String getMavenLocalRepository()
{
return mavenLocalRepository;
}
public List<String> getJVMArgs()
{
return Collections.unmodifiableList(jvmArgs);
}
public Map<String, String> getEnv()
{
return Collections.unmodifiableMap(env);
}
@Override
public String toString()
{
return String.format("%s@%x{jettyBase=%s, jettyHome=%s, jettyVersion=%s, mavenLocalRepository=%s}",
getClass().getSimpleName(),
hashCode(),
jettyBase,
jettyHome,
jettyVersion,
mavenLocalRepository);
}
}
/**
* A distribution run wraps the process that started the Jetty distribution.
*/
public static class Run extends ProcessWrapper
{
private final Config config;
private Run(Process process, Config config)
{
super(process);
this.config = config;
}
public Config getConfig()
{
return config;
}
}
public static class Builder
{
private final 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 this 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 this 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 this Builder
*/
public Builder jettyBase(Path jettyBase)
{
config.jettyBase = jettyBase;
return this;
}
/**
* @param mavenLocalRepository Path to the local maven repository
* @return this Builder
*/
public Builder mavenLocalRepository(String mavenLocalRepository)
{
if (StringUtils.isBlank(mavenLocalRepository))
return this;
config.mavenLocalRepository = mavenLocalRepository;
return this;
}
/**
* @param jvmArgs the jvm args to add
* @return this Builder
*/
public Builder jvmArgs(List<String> jvmArgs)
{
config.jvmArgs = jvmArgs;
return this;
}
/**
* @param env the env to add
* @return this Builder
*/
public Builder env(Map<String, String> env)
{
config.env = env;
return this;
}
/**
* @return an empty instance of Builder
*/
public static Builder newInstance()
{
return new Builder();
}
/**
* @return a new configured instance of {@link JettyHomeTester}
*/
public JettyHomeTester build() throws Exception
{
JettyHomeTester tester = new JettyHomeTester(config);
tester.init();
return tester;
}
}
}

View File

@ -0,0 +1,97 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.tests.testers;
import java.nio.file.Path;
import java.util.List;
import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
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.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.supplier.RepositorySystemSupplier;
import org.eclipse.aether.transfer.AbstractTransferListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class MavenHelper
{
private static final Logger LOG = LoggerFactory.getLogger(MavenHelper.class);
private final RepositorySystemSupplier repositorySystem = new RepositorySystemSupplier();
public Path resolveArtifact(String coordinates) throws ArtifactResolutionException
{
RepositorySystem repositorySystem = this.repositorySystem.get();
Artifact artifact = new DefaultArtifact(coordinates);
RepositorySystemSession session = newRepositorySystemSession(repositorySystem);
ArtifactRequest artifactRequest = new ArtifactRequest();
artifactRequest.setArtifact(artifact);
artifactRequest.setRepositories(List.of(newCentralRepository()));
ArtifactResult artifactResult = repositorySystem.resolveArtifact(session, artifactRequest);
artifact = artifactResult.getArtifact();
return artifact.getFile().toPath();
}
private DefaultRepositorySystemSession newRepositorySystemSession(RepositorySystem system)
{
DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
String mavenLocalRepository = System.getProperty("mavenRepoPath", System.getProperty("user.home") + "/.m2/repository");
LocalRepository localRepository = new LocalRepository(mavenLocalRepository);
session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepository));
session.setTransferListener(new LogTransferListener());
session.setRepositoryListener(new LogRepositoryListener());
return session;
}
private static RemoteRepository newCentralRepository()
{
return new RemoteRepository.Builder("central", "default", "https://repo.maven.apache.org/maven2/").build();
}
private static class LogTransferListener extends AbstractTransferListener
{
}
private static class LogRepositoryListener extends AbstractRepositoryListener
{
@Override
public void artifactDownloaded(RepositoryEvent event)
{
LOG.debug("downloaded {}", event.getFile());
}
@Override
public void artifactResolved(RepositoryEvent event)
{
LOG.debug("artifact resolved {}", event.getFile());
}
}
}

View File

@ -0,0 +1,218 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.tests.testers;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.time.Duration;
import java.util.Collection;
import java.util.Queue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.toolchain.test.IO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* <p>A useful wrapper of {@link Process} instances.</p>
* <p>The process output and error streams are captured each by a thread
* associated with this instance, and and exposed via {@link #getLogs()}
* and {@link #awaitConsoleLogsFor(String, Duration)}.</p>
* <p>Process termination can be handled asynchronously via {@link #whenExit()}.</p>
*/
public class ProcessWrapper implements AutoCloseable
{
private static final Logger LOG = LoggerFactory.getLogger(ProcessWrapper.class);
private final Queue<String> logs = new ConcurrentLinkedQueue<>();
private final Process process;
private final ConsoleStreamer stdOut;
private final ConsoleStreamer stdErr;
public ProcessWrapper(Process process)
{
this.process = process;
this.stdOut = startConsoleStreamer("out", process.getInputStream());
this.stdErr = startConsoleStreamer("err", process.getErrorStream());
}
public Process getProcess()
{
return process;
}
/**
* @return a collection of the logs emitted on the process output and error streams
*/
public Collection<String> getLogs()
{
return logs;
}
/**
* <p>Returns a {@link CompletableFuture} that completes when the process exits
* and when the threads capturing the process output and error stream exit.</p>
* <p>The returned {@link CompletableFuture} can be used to wait for a timeout
* via {@code processWrapper.whenExit().orTimeout(5, TimeUnit.SECONDS)}.</p>
*
* @return a CompletableFuture that completes when the process exits
*/
public CompletableFuture<Process> whenExit()
{
return getProcess().onExit().thenCombine(joinConsoleStreamers(), (p, v) -> p);
}
/**
* <p>Same as {@link Process#waitFor(long, TimeUnit)}.</p>
* <p>Use this method for simple assertions in test
* code, when it is known that the process will exit.</p>
*
* @param time the time to wait
* @param unit the unit of time
* @return {@code true} if the process has exited and {@code false} if the time elapsed before the process has exited
* @throws InterruptedException if the current thread is interrupted while waiting
*/
public boolean awaitFor(long time, TimeUnit unit) throws InterruptedException
{
return getProcess().waitFor(time, unit);
}
public boolean awaitFor(Duration duration) throws InterruptedException
{
return awaitFor(duration.toMillis(), TimeUnit.MILLISECONDS);
}
/**
* <p>Polls the console log lines derived from the
* process output and error streams for the given text.</p>
*
* @param txt the text to search in the log lines
* @param time the time to wait
* @param unit the unit of time
* @return {@code true} if the text was found in a log line,
* {@code false} if the text was not found within the given time
* @throws InterruptedException if the current thread is interrupted while waiting
*/
public boolean awaitConsoleLogsFor(String txt, long time, TimeUnit unit) throws InterruptedException
{
long poll = 50;
long millis = unit.toMillis(time);
while (millis > 0)
{
millis -= poll;
Thread.sleep(poll);
if (getLogs().stream().anyMatch(s -> s.contains(txt)))
return true;
}
return false;
}
public boolean awaitConsoleLogsFor(String txt, Duration duration) throws InterruptedException
{
return awaitConsoleLogsFor(txt, duration.toMillis(), TimeUnit.MILLISECONDS);
}
/**
* <p>Same as {@link Process#exitValue()}.</p>
*
* @return the process exit value
* @throws IllegalThreadStateException if the process has not exited
*/
public int getExitValue() throws IllegalThreadStateException
{
return getProcess().exitValue();
}
/**
* <p>Stops the process by calling {@link Process#destroy()}, and returns {@link #whenExit()}.</p>
*
* @return a CompletableFuture that completes when the process exits
*/
public CompletableFuture<Process> stop()
{
getProcess().destroy();
return whenExit();
}
/**
* <p>Calls {@link #stop()} and blocks via
* {@link CompletableFuture#join()} until the process has exited.</p>
*/
@Override
public void close()
{
stop().join();
}
private ConsoleStreamer startConsoleStreamer(String mode, InputStream stream)
{
ConsoleStreamer streamer = new ConsoleStreamer(mode, stream);
streamer.start();
return streamer;
}
private CompletableFuture<Void> joinConsoleStreamers()
{
return CompletableFuture.allOf(stdOut.join(), stdErr.join());
}
private class ConsoleStreamer implements Runnable
{
private final CompletableFuture<Void> completable = new CompletableFuture<>();
private final Thread thread;
private final BufferedReader reader;
private ConsoleStreamer(String mode, InputStream stream)
{
this.thread = new Thread(this, "process/" + mode);
this.reader = new BufferedReader(new InputStreamReader(stream));
}
private void start()
{
thread.start();
}
private CompletableFuture<Void> join()
{
return completable;
}
@Override
public void run()
{
try
{
String line;
while ((line = reader.readLine()) != null)
{
LOG.info(line);
logs.add(line);
}
}
catch (Throwable x)
{
LOG.trace("", x);
}
finally
{
IO.close(reader);
completable.complete(null);
}
}
}
}

View File

@ -0,0 +1,57 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.tests.testers;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public interface Tester
{
/**
* @return a free port chosen by the OS that can be used to listen to
* @throws IOException if a free port is not available
*/
static int freePort() throws IOException
{
try (ServerSocket server = new ServerSocket())
{
server.setReuseAddress(true);
server.bind(new InetSocketAddress("localhost", 0));
return server.getLocalPort();
}
}
/**
* <p>Returns a Java executable under the {@code $JAVA_HOME/bin} directory.</p>
*
* @param command the Java command to search for (for example, "java", "javac", "jstack", etc.)
* @return the Java command
*/
static String getJavaExecutable(String command)
{
String[] javaExecutables = new String[]{command, command + ".exe"};
Path javaBinDir = Paths.get(System.getProperty("java.home")).resolve("bin");
for (String javaExecutable : javaExecutables)
{
Path javaFile = javaBinDir.resolve(javaExecutable);
if (Files.exists(javaFile) && Files.isRegularFile(javaFile))
return javaFile.toAbsolutePath().toString();
}
return command;
}
}

View File

@ -11,13 +11,12 @@
<packaging>pom</packaging>
<name>Tests</name>
<modules>
<module>jetty-home-tester</module>
<module>jetty-testers</module>
<module>jetty-jmh</module>
<module>jetty-test-session-common</module>
<module>test-distribution</module>
<module>test-integration</module>
<!-- TODO -->
<!-- module>test-jpms</module -->
<!--<module>test-jpms</module>-->
</modules>
<properties>
<maven.deploy.skip>true</maven.deploy.skip>

View File

@ -79,11 +79,13 @@
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>jetty-home-tester</artifactId>
<artifactId>jetty-testers</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -94,9 +94,8 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>jetty-home-tester</artifactId>
<artifactId>jetty-testers</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
@ -114,6 +113,11 @@
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>

View File

@ -13,13 +13,14 @@
package org.eclipse.jetty.tests.distribution;
import java.io.File;
import java.net.URI;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.eclipse.jetty.websocket.core.client.WebSocketCoreClient;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
@ -57,15 +58,15 @@ public class BadAppTests extends AbstractJettyHomeTest
{
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertThat(run1.getExitValue(), is(0));
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-badinit-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "badapp");
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-badinit-webapp:war:" + jettyVersion);
distribution.installWar(war, "badapp");
// Setup webapps directory
distribution.installBaseResource("badapp-" + env + "/badapp_throwonunavailable_true.xml",
"webapps/badapp.xml");
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitFor(START_TIMEOUT, TimeUnit.SECONDS), "Should have exited");
@ -96,14 +97,14 @@ public class BadAppTests extends AbstractJettyHomeTest
{
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertThat(run1.getExitValue(), is(0));
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-badinit-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "badapp");
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-badinit-webapp:war:" + jettyVersion);
distribution.installWar(war, "badapp");
distribution.installBaseResource("badapp-" + env + "/badapp_throwonunavailable_false.xml",
"webapps/badapp.xml");
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -138,11 +139,11 @@ public class BadAppTests extends AbstractJettyHomeTest
{
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertThat(run1.getExitValue(), is(0));
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-badinit-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "badapp");
int port = distribution.freePort();
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-badinit-webapp:war:" + jettyVersion);
distribution.installWar(war, "badapp");
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port, "jetty.server.dumpAfterStart=true"))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -182,10 +183,10 @@ public class BadAppTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File badWebApp = distribution.resolveArtifact("org.eclipse.jetty." + env + ":" + "jetty-" + env + "-test-bad-websocket-webapp:war:" + jettyVersion);
distribution.installWarFile(badWebApp, "test");
Path badWebApp = distribution.resolveArtifact("org.eclipse.jetty." + env + ":" + "jetty-" + env + "-test-bad-websocket-webapp:war:" + jettyVersion);
distribution.installWar(badWebApp, "test");
int port = distribution.freePort();
int port = Tester.freePort();
String[] args2 = {"jetty.http.port=" + port};
try (JettyHomeTester.Run run2 = distribution.start(args2))

View File

@ -13,7 +13,6 @@
package org.eclipse.jetty.tests.distribution;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@ -26,7 +25,8 @@ import java.util.stream.Stream;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.eclipse.jetty.util.StringUtil;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@ -104,14 +104,14 @@ public class CDITests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-" + integration + "-cdi-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "demo");
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-" + integration + "-cdi-webapp:war:" + jettyVersion);
distribution.installWar(war, "demo");
distribution.installBaseResource("jetty-logging.properties", "resources/jetty-logging.properties", StandardCopyOption.REPLACE_EXISTING);
if (configure != null)
configure.accept(distribution);
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));

View File

@ -23,7 +23,8 @@ import java.util.stream.Stream;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.FormRequestContent;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
import org.eclipse.jetty.util.Fields;
import org.junit.jupiter.api.Tag;
@ -61,8 +62,8 @@ public class DemoModulesTests extends AbstractJettyHomeTest
.jettyBase(jettyBase)
.build();
int httpPort = distribution.freePort();
int sslPort = distribution.freePort();
int httpPort = Tester.freePort();
int sslPort = Tester.freePort();
String[] argsConfig = {
"--add-modules=http," + toEnvironment("demos", env)
@ -148,8 +149,8 @@ public class DemoModulesTests extends AbstractJettyHomeTest
.jettyBase(jettyBase)
.build();
int httpPort = distribution.freePort();
int sslPort = distribution.freePort();
int httpPort = Tester.freePort();
int sslPort = Tester.freePort();
String[] argsConfig = {
"--add-modules=http," + toEnvironment("demo-jsp", env)
@ -194,8 +195,8 @@ public class DemoModulesTests extends AbstractJettyHomeTest
.jettyBase(jettyBase)
.build();
int httpPort = distribution.freePort();
int sslPort = distribution.freePort();
int httpPort = Tester.freePort();
int sslPort = Tester.freePort();
String[] argsConfig = {
"--add-modules=http," + toEnvironment("demo-jaas", env)
@ -241,8 +242,8 @@ public class DemoModulesTests extends AbstractJettyHomeTest
.jettyBase(jettyBase)
.build();
int httpPort = distribution.freePort();
int sslPort = distribution.freePort();
int httpPort = Tester.freePort();
int sslPort = Tester.freePort();
String[] argsConfig = {
"--add-modules=http," + toEnvironment("demo-jsp", env)
@ -290,8 +291,8 @@ public class DemoModulesTests extends AbstractJettyHomeTest
.jettyBase(jettyBase)
.build();
int httpPort = distribution.freePort();
int sslPort = distribution.freePort();
int httpPort = Tester.freePort();
int sslPort = Tester.freePort();
String[] argsConfig = {
"--add-modules=http," + toEnvironment("demo-async-rest", env)
@ -346,8 +347,8 @@ public class DemoModulesTests extends AbstractJettyHomeTest
.jettyBase(jettyBase)
.build();
int httpPort = distribution.freePort();
int sslPort = distribution.freePort();
int httpPort = Tester.freePort();
int sslPort = Tester.freePort();
String[] argsConfig = {
"--add-modules=http," + toEnvironment("demos", env)
@ -402,8 +403,8 @@ public class DemoModulesTests extends AbstractJettyHomeTest
.jettyBase(jettyBase)
.build();
int httpPort = distribution.freePort();
int sslPort = distribution.freePort();
int httpPort = Tester.freePort();
int sslPort = Tester.freePort();
String[] argsConfig = {
"--add-modules=http," + toEnvironment("demos", env)
@ -459,8 +460,8 @@ public class DemoModulesTests extends AbstractJettyHomeTest
assertTrue(runConfig.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, runConfig.getExitValue());
int httpPort = distribution.freePort();
int sslPort = distribution.freePort();
int httpPort = Tester.freePort();
int sslPort = Tester.freePort();
String[] argsStart = {
"jetty.http.port=" + httpPort,
"jetty.ssl.port=" + sslPort
@ -526,8 +527,8 @@ public class DemoModulesTests extends AbstractJettyHomeTest
assertTrue(runConfig.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, runConfig.getExitValue());
int httpPort = distribution.freePort();
int sslPort = distribution.freePort();
int httpPort = Tester.freePort();
int sslPort = Tester.freePort();
String[] argsStart = {
"jetty.http.port=" + httpPort,
@ -561,8 +562,8 @@ public class DemoModulesTests extends AbstractJettyHomeTest
.jettyBase(jettyBase)
.build();
int httpPort = distribution.freePort();
int sslPort = distribution.freePort();
int httpPort = Tester.freePort();
int sslPort = Tester.freePort();
String[] argsConfig = {
"--add-modules=http,demo-handler"
@ -604,8 +605,8 @@ public class DemoModulesTests extends AbstractJettyHomeTest
.jettyBase(jettyBase)
.build();
int httpPort = distribution.freePort();
int sslPort = distribution.freePort();
int httpPort = Tester.freePort();
int sslPort = Tester.freePort();
String[] argsConfig =
{
@ -666,8 +667,8 @@ public class DemoModulesTests extends AbstractJettyHomeTest
.jettyBase(jettyBase)
.build();
int httpPort = distribution.freePort();
int sslPort = distribution.freePort();
int httpPort = Tester.freePort();
int sslPort = Tester.freePort();
String[] argsConfig = {
"--add-modules=http," + toEnvironment("demos", env)

View File

@ -28,12 +28,13 @@ import java.nio.file.StandardOpenOption;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.HttpClient;
@ -51,7 +52,8 @@ import org.eclipse.jetty.http3.client.transport.HttpClientTransportOverHTTP3;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.io.content.ByteBufferContentSource;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.PathMatchers;
import org.eclipse.jetty.util.BlockingArrayQueue;
@ -96,7 +98,7 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -128,7 +130,7 @@ public class DistributionTests extends AbstractJettyHomeTest
Path pidfile = run1.getConfig().getJettyBase().resolve("jetty.pid");
Path statefile = run1.getConfig().getJettyBase().resolve("jetty.state");
int port = distribution.freePort();
int port = Tester.freePort();
List<String> args = new ArrayList<>();
args.add("jetty.http.port=" + port);
@ -191,7 +193,7 @@ public class DistributionTests extends AbstractJettyHomeTest
String jettyVersion = System.getProperty("jettyVersion");
JettyHomeTester distribution = JettyHomeTester.Builder.newInstance()
.jettyVersion(jettyVersion)
.jettyBase(jettyBase)
.jettyBase(jettyBase)
.build();
String mods = String.join(",",
@ -207,8 +209,8 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-jsp-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "test");
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-jsp-webapp:war:" + jettyVersion);
distribution.installWar(war, "test");
try (JettyHomeTester.Run run2 = distribution.start("jetty.quickstart.mode=GENERATE"))
{
@ -221,7 +223,7 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(Files.exists(quickstartWebXml));
assertNotEquals(0, Files.size(quickstartWebXml));
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run3 = distribution.start("jetty.http.port=" + port, "jetty.quickstart.mode=QUICKSTART"))
{
@ -245,7 +247,7 @@ public class DistributionTests extends AbstractJettyHomeTest
String jettyVersion = System.getProperty("jettyVersion");
JettyHomeTester distribution = JettyHomeTester.Builder.newInstance()
.jettyVersion(jettyVersion)
.jettyBase(jettyBase)
.jettyBase(jettyBase)
.build();
String mods = String.join(",",
@ -263,10 +265,10 @@ public class DistributionTests extends AbstractJettyHomeTest
// Verify that --create-start-ini works
assertTrue(Files.exists(distribution.getJettyBase().resolve("start.ini")));
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-jsp-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "test");
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-jsp-webapp:war:" + jettyVersion);
distribution.installWar(war, "test");
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -306,10 +308,10 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-jsp-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "test");
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-jsp-webapp:war:" + jettyVersion);
distribution.installWar(war, "test");
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("--jpms", "jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -362,10 +364,10 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-jsp-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "test");
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-jsp-webapp:war:" + jettyVersion);
distribution.installWar(war, "test");
int port = distribution.freePort();
int port = Tester.freePort();
String portProp = ssl ? "jetty.ssl.port" : "jetty.http.port";
try (JettyHomeTester.Run run2 = distribution.start(portProp + "=" + port))
{
@ -407,10 +409,10 @@ public class DistributionTests extends AbstractJettyHomeTest
assertEquals(0, run1.getExitValue());
assertTrue(Files.exists(distribution.getJettyBase().resolve("resources/log4j2.xml")));
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-jsp-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "test");
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-jsp-webapp:war:" + jettyVersion);
distribution.installWar(war, "test");
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -451,10 +453,10 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File webApp = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-websocket-client-provided-webapp:war:" + jettyVersion);
distribution.installWarFile(webApp, "test");
Path webApp = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-websocket-client-provided-webapp:war:" + jettyVersion);
distribution.installWar(webApp, "test");
int port = distribution.freePort();
int port = Tester.freePort();
List<String> args = new ArrayList<>();
args.add(ssl ? "jetty.ssl.port=" + port : "jetty.http.port=" + port);
if (Boolean.parseBoolean(jpms))
@ -500,10 +502,10 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File webApp = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-websocket-client-webapp:war:" + jettyVersion);
distribution.installWarFile(webApp, "test");
Path webApp = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-websocket-client-webapp:war:" + jettyVersion);
distribution.installWar(webApp, "test");
int port = distribution.freePort();
int port = Tester.freePort();
List<String> args = new ArrayList<>();
args.add(ssl ? "jetty.ssl.port=" + port : "jetty.http.port=" + port);
if (Boolean.parseBoolean(jpms))
@ -566,15 +568,15 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-proxy-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "proxy");
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-proxy-webapp:war:" + jettyVersion);
distribution.installWar(war, "proxy");
Path loggingProps = distribution.getJettyBase().resolve("resources/jetty-logging.properties");
String loggingConfig = """
# Default for everything is INFO
org.eclipse.jetty.LEVEL=INFO
# to see full logger names
# to see full logger names
# org.eclipse.jetty.logging.appender.NAME_CONDENSE=false
# to see CR LF as-is (not escaped) in output (useful for DEBUG of request/response headers)
org.eclipse.jetty.logging.appender.MESSAGE_ESCAPE=false
@ -584,7 +586,7 @@ public class DistributionTests extends AbstractJettyHomeTest
Files.writeString(loggingProps, loggingConfig, StandardCharsets.UTF_8, StandardOpenOption.TRUNCATE_EXISTING);
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("--jpms", "jetty.http.port=" + port, "jetty.server.dumpAfterStart=true"))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -630,11 +632,11 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(10, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File webApp = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-websocket-webapp:war:" + jettyVersion);
distribution.installWarFile(webApp, "test1");
distribution.installWarFile(webApp, "test2");
Path webApp = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-websocket-webapp:war:" + jettyVersion);
distribution.installWar(webApp, "test1");
distribution.installWar(webApp, "test2");
int port = distribution.freePort();
int port = Tester.freePort();
List<String> args2 = new ArrayList<>();
args2.add("jetty.http.port=" + port);
if (Boolean.parseBoolean(jpms))
@ -710,12 +712,18 @@ public class DistributionTests extends AbstractJettyHomeTest
distribution.getJettyBase().resolve("resources").resolve("log4j2.xml"),
StandardCopyOption.REPLACE_EXISTING);
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitLogsFileFor(
distribution.getJettyBase().resolve("logs").resolve("jetty.log"),
"Started oejs.Server@", 10, TimeUnit.SECONDS));
Path logFile = distribution.getJettyBase().resolve("logs").resolve("jetty.log");
await().atMost(10, TimeUnit.SECONDS).until(() -> Files.exists(logFile));
await().atMost(10, TimeUnit.SECONDS).until(() ->
{
try (Stream<String> lines = Files.lines(logFile))
{
return lines.anyMatch(line -> line.contains("Started oejs.Server@"));
}
});
startHttpClient();
ContentResponse response = client.GET("http://localhost:" + port);
@ -746,7 +754,7 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(Files.exists(julConfig));
Files.write(julConfig, Arrays.asList(System.lineSeparator(), "org.eclipse.jetty.level=FINE"), StandardOpenOption.APPEND);
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -788,17 +796,17 @@ public class DistributionTests extends AbstractJettyHomeTest
String loggerName = getClass().getName();
String message = "test-log-line";
String xml = "" +
"<?xml version=\"1.0\"?>" +
"<!DOCTYPE Configure PUBLIC \"-//Jetty//Configure//EN\" \"https://eclipse.dev/jetty/configure_10_0.dtd\">" +
"<Configure>" +
" <Call name=\"getLogger\" class=\"java.util.logging.Logger\">" +
" <Arg>" + loggerName + "</Arg>" +
" <Call name=\"log\">" +
" <Arg><Get class=\"java.util.logging.Level\" name=\"FINE\" /></Arg>" +
" <Arg>" + message + "</Arg>" +
" </Call>" +
" </Call>" +
"</Configure>";
"<?xml version=\"1.0\"?>" +
"<!DOCTYPE Configure PUBLIC \"-//Jetty//Configure//EN\" \"https://eclipse.dev/jetty/configure_10_0.dtd\">" +
"<Configure>" +
" <Call name=\"getLogger\" class=\"java.util.logging.Logger\">" +
" <Arg>" + loggerName + "</Arg>" +
" <Call name=\"log\">" +
" <Arg><Get class=\"java.util.logging.Level\" name=\"FINE\" /></Arg>" +
" <Arg>" + message + "</Arg>" +
" </Call>" +
" </Call>" +
"</Configure>";
Files.write(julXML, List.of(xml), StandardOpenOption.CREATE);
Path julIni = jettyBase.resolve("start.d/logging-jul-capture.ini");
@ -808,7 +816,7 @@ public class DistributionTests extends AbstractJettyHomeTest
Path jettyLogConfig = jettyBase.resolve("resources/jetty-logging.properties");
Files.write(jettyLogConfig, List.of(loggerName + ".LEVEL=DEBUG"), StandardOpenOption.TRUNCATE_EXISTING);
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -892,12 +900,12 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run2.awaitFor(START_TIMEOUT, TimeUnit.SECONDS), String.join("", run2.getLogs()));
assertEquals(0, run2.getExitValue());
int port = distribution.freePort();
int sslPort = distribution.freePort();
int port = Tester.freePort();
int sslPort = Tester.freePort();
try (JettyHomeTester.Run run3 = distribution.start("jetty.http.port=" + port, "jetty.ssl.port=" + sslPort))
{
assertTrue(run3.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS),
String.join("", run3.getLogs()));
String.join("", run3.getLogs()));
// Check for the protocol order: fcgi must be after ssl and before http.
assertTrue(run3.getLogs().stream()
@ -1000,8 +1008,8 @@ public class DistributionTests extends AbstractJettyHomeTest
Files.createDirectories(jettyBaseModules);
Path execModule = jettyBaseModules.resolve("exec.mod");
String module = "" +
"[exec]\n" +
"--show-version";
"[exec]\n" +
"--show-version";
Files.write(execModule, List.of(module), StandardOpenOption.CREATE);
try (JettyHomeTester.Run run1 = distribution.start(List.of("--add-modules=http,exec")))
@ -1009,7 +1017,7 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -1035,11 +1043,11 @@ public class DistributionTests extends AbstractJettyHomeTest
// Create module with an [ini] section with an invalid password,
// which should be overridden on the command line at startup.
String module = "" +
"[depends]\n" +
"ssl\n" +
"\n" +
"[ini]\n" +
"" + pathProperty + "=modbased\n";
"[depends]\n" +
"ssl\n" +
"\n" +
"[ini]\n" +
"" + pathProperty + "=modbased\n";
Files.writeString(jettyBaseModules.resolve("ssl-ini.mod"), module, StandardOpenOption.CREATE);
try (JettyHomeTester.Run run1 = distribution.start("--add-module=https,test-keystore,ssl-ini"))
@ -1048,7 +1056,7 @@ public class DistributionTests extends AbstractJettyHomeTest
assertEquals(0, run1.getExitValue());
// Override the property on the command line with the correct password.
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start(pathProperty + "=cmdline", "jetty.ssl.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -1087,7 +1095,7 @@ public class DistributionTests extends AbstractJettyHomeTest
fileWriter.write(testFileContent);
}
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -1141,7 +1149,7 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run1.getLogs().stream().anyMatch(log -> log.contains("WARN") && log.contains(reason)));
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -1167,8 +1175,8 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
int h2Port = distribution.freePort();
int h3Port = distribution.freePort();
int h2Port = Tester.freePort();
int h3Port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start(List.of("jetty.ssl.selectors=1", "jetty.ssl.port=" + h2Port, "jetty.quic.port=" + h3Port)))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -1205,9 +1213,9 @@ public class DistributionTests extends AbstractJettyHomeTest
try (JettyHomeTester.Run run2 = distribution.start("--dry-run"))
{
run2.awaitFor(START_TIMEOUT, TimeUnit.SECONDS);
Queue<String> logs = run2.getLogs();
Collection<String> logs = run2.getLogs();
assertThat(logs.size(), equalTo(1));
assertThat(logs.poll(), not(containsString("${jetty.home.uri}")));
assertThat(logs.iterator().next(), not(containsString("${jetty.home.uri}")));
}
}
}
@ -1237,7 +1245,7 @@ public class DistributionTests extends AbstractJettyHomeTest
);
Files.write(requestLogIni, lines, StandardCharsets.UTF_8, StandardOpenOption.TRUNCATE_EXISTING);
int port = distribution.freePort();
int port = Tester.freePort();
String[] args2 = {
"jetty.http.port=" + port,
};
@ -1280,7 +1288,7 @@ public class DistributionTests extends AbstractJettyHomeTest
assertEquals(0, run1.getExitValue());
// Add a FastCGI connector to simulate, for example, php-fpm.
int fcgiPort = distribution.freePort();
int fcgiPort = Tester.freePort();
//Path jettyBase = distribution.getJettyBase();
Path jettyBaseEtc = jettyBase.resolve("etc");
Files.createDirectories(jettyBaseEtc);
@ -1352,7 +1360,7 @@ public class DistributionTests extends AbstractJettyHomeTest
</Configure>
""".replace("$P", String.valueOf(fcgiPort)), StandardOpenOption.CREATE);
int httpPort = distribution.freePort();
int httpPort = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + httpPort, "etc/fcgi-connector.xml"))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -1395,7 +1403,7 @@ public class DistributionTests extends AbstractJettyHomeTest
Files.writeString(jettyLogging, loggingConfig, StandardOpenOption.TRUNCATE_EXISTING);
// Add a FastCGI connector to simulate, for example, php-fpm.
int fcgiPort = distribution.freePort();
int fcgiPort = Tester.freePort();
Path jettyBaseEtc = jettyBase.resolve("etc");
Files.createDirectories(jettyBaseEtc);
Path fcgiConnectorXML = jettyBaseEtc.resolve("fcgi-connector.xml");
@ -1476,7 +1484,7 @@ public class DistributionTests extends AbstractJettyHomeTest
environment=$ENV
""".replace("$ENV", env), StandardOpenOption.CREATE);
int httpPort = distribution.freePort();
int httpPort = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + httpPort, "etc/fcgi-connector.xml"))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -1507,7 +1515,7 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(10, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
int httpPort = distribution.freePort();
int httpPort = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start(List.of("jetty.http.selectors=1", "jetty.http.port=" + httpPort)))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", 10, TimeUnit.SECONDS));
@ -1537,7 +1545,7 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
int httpPort = distribution.freePort();
int httpPort = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start(List.of("jetty.http.selectors=1", "jetty.http.port=" + httpPort)))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
@ -1580,7 +1588,7 @@ public class DistributionTests extends AbstractJettyHomeTest
""";
Files.writeString(jettyLogging, loggingConfig, StandardOpenOption.TRUNCATE_EXISTING);
int httpPort = distribution.freePort();
int httpPort = Tester.freePort();
String contextPath = "/" + toEnvironment("demo-simple", env);
try (JettyHomeTester.Run run2 = distribution.start(List.of("jetty.http.selectors=1", "jetty.http.port=" + httpPort)))
{
@ -1618,7 +1626,7 @@ public class DistributionTests extends AbstractJettyHomeTest
.jettyBase(jettyBase)
.build();
int httpPort = distribution.freePort();
int httpPort = Tester.freePort();
String[] argsConfig = {
"--add-modules=http," + toEnvironment("deploy", env) + "," + toEnvironment("webapp", env)
@ -1635,11 +1643,11 @@ public class DistributionTests extends AbstractJettyHomeTest
};
// Put war into ${jetty.base}/wars/ directory
File srcWar = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-simple-webapp:war:" + jettyVersion);
Path srcWar = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-simple-webapp:war:" + jettyVersion);
Path warsDir = jettyBase.resolve("wars");
FS.ensureDirExists(warsDir);
Path destWar = warsDir.resolve("demo.war");
Files.copy(srcWar.toPath(), destWar);
Files.copy(srcWar, destWar);
// Create XML for deployable
String xml = """
@ -1702,7 +1710,7 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(10, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
int httpPort = distribution.freePort();
int httpPort = Tester.freePort();
List<String> args = List.of(
"jetty.inetaccess.exclude=|/excludedPath/*",
"jetty.http.port=" + httpPort);
@ -1739,7 +1747,7 @@ public class DistributionTests extends AbstractJettyHomeTest
run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS);
assertThat(run1.getExitValue(), is(0));
int httpPort1 = distribution.freePort();
int httpPort1 = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start(List.of("jetty.http.port=" + httpPort1)))
{
assertThat(run2.awaitConsoleLogsFor("Started oejs.Server", START_TIMEOUT, TimeUnit.SECONDS), is(true));
@ -1756,7 +1764,7 @@ public class DistributionTests extends AbstractJettyHomeTest
assertTrue(response.getHeaders().contains(HttpHeader.ACCESS_CONTROL_ALLOW_ORIGIN));
}
int httpPort2 = distribution.freePort();
int httpPort2 = Tester.freePort();
List<String> args = List.of(
"jetty.http.port=" + httpPort2,
// Allow a different origin.

View File

@ -18,7 +18,8 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
@ -53,7 +54,7 @@ public class DynamicListenerTests extends AbstractJettyHomeTest
assertEquals(0, run1.getExitValue());
}
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));

View File

@ -13,14 +13,14 @@
package org.eclipse.jetty.tests.distribution;
import java.io.File;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
@ -46,7 +46,7 @@ public class GzipModuleTests extends AbstractJettyHomeTest
.jettyBase(jettyBase)
.build();
int httpPort = distribution.freePort();
int httpPort = Tester.freePort();
String[] argsConfig = {
"--add-modules=http,gzip," + toEnvironment("deploy", env) + "," + toEnvironment("webapp", env)
@ -61,8 +61,8 @@ public class GzipModuleTests extends AbstractJettyHomeTest
"jetty.http.port=" + httpPort
};
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-simple-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "demo");
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-simple-webapp:war:" + jettyVersion);
distribution.installWar(war, "demo");
try (JettyHomeTester.Run runStart = distribution.start(argsStart))
{
@ -88,7 +88,7 @@ public class GzipModuleTests extends AbstractJettyHomeTest
.jettyBase(jettyBase)
.build();
int httpPort = distribution.freePort();
int httpPort = Tester.freePort();
String[] argsConfig = {
"--add-modules=gzip,http," + toEnvironment("deploy", env) + "," + toEnvironment("webapp", env)
@ -103,8 +103,8 @@ public class GzipModuleTests extends AbstractJettyHomeTest
"jetty.http.port=" + httpPort
};
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-simple-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "demo");
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + "-demo-simple-webapp:war:" + jettyVersion);
distribution.installWar(war, "demo");
try (JettyHomeTester.Run runStart = distribution.start(argsStart))
{
@ -131,7 +131,7 @@ public class GzipModuleTests extends AbstractJettyHomeTest
.jettyBase(jettyBase)
.build();
int httpPort = distribution.freePort();
int httpPort = Tester.freePort();
String[] argsConfig = {
"--add-modules=gzip,http," + toEnvironment("deploy", env) + "," + toEnvironment("webapp", env)
@ -147,8 +147,8 @@ public class GzipModuleTests extends AbstractJettyHomeTest
"jetty.gzip.excludedMimeTypeList=image/vnd.microsoft.icon"
};
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + " .demos:jetty-" + env + "-demo-simple-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "demo");
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + " .demos:jetty-" + env + "-demo-simple-webapp:war:" + jettyVersion);
distribution.installWar(war, "demo");
try (JettyHomeTester.Run runStart = distribution.start(argsStart))
{

View File

@ -13,7 +13,6 @@
package org.eclipse.jetty.tests.distribution;
import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
@ -24,7 +23,8 @@ import java.util.stream.Stream;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
@ -169,10 +169,10 @@ public class LoggingOptionsTests extends AbstractJettyHomeTest
}
}
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + ".demo-jsp-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "test");
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ".demos:jetty-" + env + ".demo-jsp-webapp:war:" + jettyVersion);
distribution.installWar(war, "test");
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run requestRun = distribution.start("jetty.http.port=" + port))
{
assertTrue(requestRun.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));

View File

@ -18,7 +18,7 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.logging.JettyLevel;
import org.eclipse.jetty.logging.JettyLogger;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

View File

@ -13,12 +13,13 @@
package org.eclipse.jetty.tests.distribution;
import java.io.File;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
@ -52,10 +53,10 @@ public class OsgiAppTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File war = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-felix-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "test");
Path war = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-felix-webapp:war:" + jettyVersion);
distribution.installWar(war, "test");
int port = distribution.freePort();
int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));

View File

@ -25,7 +25,8 @@ import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.util.ajax.JSON;
import org.junit.jupiter.api.Disabled;
@ -69,7 +70,7 @@ public class StatsTests extends AbstractJettyHomeTest
distribution.installBaseResource("stats-webapp-" + env + "/index.html", "webapps/demo/index.html");
distribution.installBaseResource("stats-webapp-" + env + "/WEB-INF/web.xml", "webapps/demo/WEB-INF/web.xml");
int port = distribution.freePort();
int port = Tester.freePort();
String[] args2 = {
"jetty.http.port=" + port
};

View File

@ -17,7 +17,7 @@ import java.io.File;
import java.nio.file.Path;
import java.util.function.Consumer;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.testcontainers.images.builder.dockerfile.DockerfileBuilder;
public abstract class ImageOS extends ImageFromDSL

View File

@ -14,7 +14,6 @@
package org.eclipse.jetty.tests.distribution.session;
import java.io.BufferedWriter;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@ -29,7 +28,8 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.distribution.AbstractJettyHomeTest;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
@ -87,11 +87,11 @@ public abstract class AbstractSessionDistributionTests extends AbstractJettyHome
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File war = jettyHomeTester.resolveArtifact("org.eclipse.jetty." + environment +
Path war = jettyHomeTester.resolveArtifact("org.eclipse.jetty." + environment +
":" + "jetty-" + environment + "-test-simple-session-webapp:war:" + jettyVersion);
jettyHomeTester.installWarFile(war, "test");
jettyHomeTester.installWar(war, "test");
int port = jettyHomeTester.freePort();
int port = Tester.freePort();
args = new ArrayList<>(Collections.singletonList("jetty.http.port=" + port));
args.addAll(getSecondStartExtraArgs());
argsStart = args.toArray(new String[0]);

View File

@ -13,7 +13,6 @@
package org.eclipse.jetty.tests.distribution.session;
import java.io.File;
import java.io.OutputStream;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
@ -29,7 +28,8 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
@ -161,10 +161,10 @@ public class HazelcastSessionDistributionTests extends AbstractSessionDistributi
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-simple-session-webapp:war:" + jettyVersion);
distribution.installWarFile(war, "test");
Path war = distribution.resolveArtifact("org.eclipse.jetty.tests:test-simple-session-webapp:war:" + jettyVersion);
distribution.installWar(war, "test");
int port = distribution.freePort();
int port = Tester.freePort();
List<String> argsStart = Arrays.asList(
"jetty.http.port=" + port,
"jetty.session.hazelcast.onlyClient=false",

View File

@ -13,41 +13,9 @@
<properties>
<bundle-symbolic-name>${project.groupId}.ee10.distribution</bundle-symbolic-name>
<!-- jetty-home is creating some issues with upperbound -->
<enforcer.skip>true</enforcer.skip>
</properties>
<dependencyManagement>
<dependencies>
<!-- doesn't work with partial build -->
<!-- <dependency>-->
<!-- <groupId>org.eclipse.jetty.ee10</groupId>-->
<!-- <artifactId>jetty-ee10-bom</artifactId>-->
<!-- <version>${project.version}</version>-->
<!-- <scope>import</scope>-->
<!-- <type>pom</type>-->
<!-- </dependency>-->
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-distribution-common</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
@ -56,14 +24,11 @@
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-openid</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
@ -79,6 +44,11 @@
<type>war</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>jetty-testers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-distribution-common</artifactId>

View File

@ -13,7 +13,6 @@
package org.eclipse.jetty.ee10.tests.distribution;
import java.io.File;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
@ -21,7 +20,8 @@ import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.ee10.tests.distribution.openid.OpenIdProvider;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.distribution.AbstractJettyHomeTest;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -56,10 +56,10 @@ public class OpenIdTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File webApp = distribution.resolveArtifact("org.eclipse.jetty.ee10:jetty-ee10-test-openid-webapp:war:" + jettyVersion);
distribution.installWarFile(webApp, "test");
Path webApp = distribution.resolveArtifact("org.eclipse.jetty.ee10:jetty-ee10-test-openid-webapp:war:" + jettyVersion);
distribution.installWar(webApp, "test");
int port = distribution.freePort();
int port = Tester.freePort();
openIdProvider.addRedirectUri("http://localhost:" + port + "/test/j_security_check");
openIdProvider.start();
String[] args2 = {

View File

@ -13,40 +13,9 @@
<properties>
<bundle-symbolic-name>${project.groupId}.ee9.distribution</bundle-symbolic-name>
<!-- jetty-home is creating some issues with upperbound -->
<!-- <enforcer.skip>true</enforcer.skip>-->
</properties>
<dependencyManagement>
<dependencies>
<!-- doesn't work with partial build -->
<!-- <dependency>-->
<!-- <groupId>org.eclipse.jetty.ee9</groupId>-->
<!-- <artifactId>jetty-ee9-bom</artifactId>-->
<!-- <version>${project.version}</version>-->
<!-- <scope>import</scope>-->
<!-- <type>pom</type>-->
<!-- </dependency>-->
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-distribution-common</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
@ -55,7 +24,6 @@
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
@ -77,6 +45,11 @@
<type>war</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>jetty-testers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-distribution-common</artifactId>

View File

@ -13,7 +13,6 @@
package org.eclipse.jetty.ee9.tests.distribution;
import java.io.File;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
@ -21,7 +20,8 @@ import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.ee9.tests.distribution.openid.OpenIdProvider;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.distribution.AbstractJettyHomeTest;
import org.eclipse.jetty.tests.hometester.JettyHomeTester;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@ -59,10 +59,10 @@ public class OpenIdTests extends AbstractJettyHomeTest
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
File webApp = distribution.resolveArtifact("org.eclipse.jetty.ee9:jetty-ee9-test-openid-webapp:war:" + jettyVersion);
distribution.installWarFile(webApp, "test");
Path webApp = distribution.resolveArtifact("org.eclipse.jetty.ee9:jetty-ee9-test-openid-webapp:war:" + jettyVersion);
distribution.installWar(webApp, "test");
int port = distribution.freePort();
int port = Tester.freePort();
openIdProvider.addRedirectUri("http://localhost:" + port + "/test/j_security_check");
openIdProvider.start();
String[] args2 = {