|
|
|
@ -0,0 +1,874 @@
|
|
|
|
|
//
|
|
|
|
|
// ========================================================================
|
|
|
|
|
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
|
// All rights reserved. This program and the accompanying materials
|
|
|
|
|
// are made available under the terms of the Eclipse Public License v1.0
|
|
|
|
|
// and Apache License v2.0 which accompanies this distribution.
|
|
|
|
|
//
|
|
|
|
|
// The Eclipse Public License is available at
|
|
|
|
|
// http://www.eclipse.org/legal/epl-v10.html
|
|
|
|
|
//
|
|
|
|
|
// The Apache License v2.0 is available at
|
|
|
|
|
// http://www.opensource.org/licenses/apache2.0.php
|
|
|
|
|
//
|
|
|
|
|
// You may elect to redistribute this code under either of these licenses.
|
|
|
|
|
// ========================================================================
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
package org.eclipse.jetty.test.support;
|
|
|
|
|
//
|
|
|
|
|
//========================================================================
|
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
|
//All rights reserved. This program and the accompanying materials
|
|
|
|
|
//are made available under the terms of the Eclipse Public License v1.0
|
|
|
|
|
//and Apache License v2.0 which accompanies this distribution.
|
|
|
|
|
//
|
|
|
|
|
// The Eclipse Public License is available at
|
|
|
|
|
// http://www.eclipse.org/legal/epl-v10.html
|
|
|
|
|
//
|
|
|
|
|
// The Apache License v2.0 is available at
|
|
|
|
|
// http://www.opensource.org/licenses/apache2.0.php
|
|
|
|
|
//
|
|
|
|
|
//You may elect to redistribute this code under either of these licenses.
|
|
|
|
|
//========================================================================
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import java.io.BufferedReader;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.FileFilter;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
|
import java.io.InputStreamReader;
|
|
|
|
|
import java.net.URI;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.concurrent.CountDownLatch;
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
import java.util.regex.Matcher;
|
|
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
|
|
|
|
|
import org.eclipse.jetty.toolchain.test.FS;
|
|
|
|
|
import org.eclipse.jetty.toolchain.test.IO;
|
|
|
|
|
import org.eclipse.jetty.toolchain.test.JAR;
|
|
|
|
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
|
|
|
|
import org.eclipse.jetty.toolchain.test.OS;
|
|
|
|
|
import org.eclipse.jetty.toolchain.test.PathAssert;
|
|
|
|
|
import org.eclipse.jetty.toolchain.test.TestingDir;
|
|
|
|
|
import org.junit.Assert;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Basic process based executor for using the Jetty Distribution along with custom configurations to perform basic
|
|
|
|
|
* <p>
|
|
|
|
|
* Allows for a test specific directory, that is a copied jetty-distribution, and then modified for the test specific testing required.
|
|
|
|
|
* <p>
|
|
|
|
|
* Requires that you setup the maven-dependency-plugin appropriately for the base distribution you want to use, along with any other dependencies (wars, libs,
|
|
|
|
|
* etc..) that you may need from other maven projects.
|
|
|
|
|
* <p>
|
|
|
|
|
* Maven Dependency Plugin Setup:
|
|
|
|
|
*
|
|
|
|
|
* <pre>
|
|
|
|
|
* <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/maven-v4_0_0.xsd">
|
|
|
|
|
*
|
|
|
|
|
* <!-- Common Destination Directories -->
|
|
|
|
|
*
|
|
|
|
|
* <properties>
|
|
|
|
|
* <test-wars-dir>${project.build.directory}/test-wars</test-wars-dir>
|
|
|
|
|
* <test-libs-dir>${project.build.directory}/test-libs</test-libs-dir>
|
|
|
|
|
* <test-distro-dir>${project.build.directory}/test-dist</test-distro-dir>
|
|
|
|
|
* </properties>
|
|
|
|
|
*
|
|
|
|
|
* <build>
|
|
|
|
|
* <plugins>
|
|
|
|
|
* <plugin>
|
|
|
|
|
* <groupId>org.apache.maven.plugins</groupId>
|
|
|
|
|
* <artifactId>maven-dependency-plugin</artifactId>
|
|
|
|
|
* <version>2.1</version>
|
|
|
|
|
* <executions>
|
|
|
|
|
*
|
|
|
|
|
* <!-- Copy LIB and WAR dependencies into place that JettyDistro can use them -->
|
|
|
|
|
*
|
|
|
|
|
* <execution>
|
|
|
|
|
* <id>test-lib-war-copy</id>
|
|
|
|
|
* <phase>process-test-resources</phase>
|
|
|
|
|
* <goals>
|
|
|
|
|
* <goal>copy</goal>
|
|
|
|
|
* </goals>
|
|
|
|
|
* <configuration>
|
|
|
|
|
* <artifactItems>
|
|
|
|
|
* <artifactItem>
|
|
|
|
|
* <groupId>org.mortbay.jetty.testwars</groupId>
|
|
|
|
|
* <artifactId>test-war-java_util_logging</artifactId>
|
|
|
|
|
* <version>7.3.0</version>
|
|
|
|
|
* <type>war</type>
|
|
|
|
|
* <outputDirectory>${test-wars-dir}</outputDirectory>
|
|
|
|
|
* </artifactItem>
|
|
|
|
|
* <artifactItem>
|
|
|
|
|
* <groupId>org.mortbay.jetty</groupId>
|
|
|
|
|
* <artifactId>jetty-aspect-servlet-api-2.5</artifactId>
|
|
|
|
|
* <version>7.3.0</version>
|
|
|
|
|
* <type>jar</type>
|
|
|
|
|
* <outputDirectory>${test-libs-dir}</outputDirectory>
|
|
|
|
|
* </artifactItem>
|
|
|
|
|
* </artifactItems>
|
|
|
|
|
* <overWriteIfNewer>true</overWriteIfNewer>
|
|
|
|
|
* <overWrite>true</overWrite>
|
|
|
|
|
* <stripVersion>true</stripVersion>
|
|
|
|
|
* </configuration>
|
|
|
|
|
* </execution>
|
|
|
|
|
*
|
|
|
|
|
* <!-- Extract Jetty DISTRIBUTION into place that JettyDistro can use it -->
|
|
|
|
|
*
|
|
|
|
|
* <execution>
|
|
|
|
|
* <id>unpack-test-dist</id>
|
|
|
|
|
* <phase>process-test-resources</phase>
|
|
|
|
|
* <goals>
|
|
|
|
|
* <goal>unpack</goal>
|
|
|
|
|
* </goals>
|
|
|
|
|
* <configuration>
|
|
|
|
|
* <artifactItems>
|
|
|
|
|
* <artifactItem>
|
|
|
|
|
* <groupId>org.eclipse.jetty</groupId>
|
|
|
|
|
* <artifactId>jetty-distribution</artifactId>
|
|
|
|
|
* <version>7.3.0</version>
|
|
|
|
|
* <type>zip</type>
|
|
|
|
|
* <overWrite>true</overWrite>
|
|
|
|
|
* </artifactItem>
|
|
|
|
|
* </artifactItems>
|
|
|
|
|
* <outputAbsoluteArtifactFilename>true</outputAbsoluteArtifactFilename>
|
|
|
|
|
* <outputDirectory>${test-distro-dir}</outputDirectory>
|
|
|
|
|
* <overWriteSnapshots>true</overWriteSnapshots>
|
|
|
|
|
* <overWriteIfNewer>true</overWriteIfNewer>
|
|
|
|
|
* </configuration>
|
|
|
|
|
* </execution>
|
|
|
|
|
* </executions>
|
|
|
|
|
* </plugin>
|
|
|
|
|
* </plugins>
|
|
|
|
|
* </build>
|
|
|
|
|
*
|
|
|
|
|
* </project>
|
|
|
|
|
* </pre>
|
|
|
|
|
* <p>
|
|
|
|
|
* If you have a specific configuration you want to setup, you'll want to prepare this configuration in an overlay directory underneath the
|
|
|
|
|
* <code>src/test/resources/</code> directory. <br>
|
|
|
|
|
* Notes:
|
|
|
|
|
* <ol>
|
|
|
|
|
* <li>The {@link JettyDistro} sets up a unique test directory (based on the constructor {@link #JettyDistro(Class)} or {@link #JettyDistro(TestingDir)}), by
|
|
|
|
|
* ensuring the directory is empty, then copying the <code>target/test-dist</code> directory into this new testing directory prior to the test specific changes
|
|
|
|
|
* to the configuration.<br>
|
|
|
|
|
* Note: this testing directory is a complete jetty distribution, suitable for executing via the command line for additional testing needs.</li>
|
|
|
|
|
* <li>The directory name you choose in <code>src/test/resources</code> will be the name you use in the {@link #overlayConfig(String)} method to provide
|
|
|
|
|
* replacement configurations for the Jetty Distribution.</li>
|
|
|
|
|
* <li>You'll want to {@link #delete(String)} any files and/or directories from the standard distribution prior to using the {@link #overlayConfig(String)}
|
|
|
|
|
* method.</li>
|
|
|
|
|
* <li>Use the {@link #copyLib(String, String)} method to copy JAR files from the <code>target/test-libs</code> directory (created and managed above using the
|
|
|
|
|
* <code>maven-dependency-plugin</code>) to copy the lib into the test specific.</li>
|
|
|
|
|
* <li>Use the {@link #copyTestWar(String)} method to copy WAR files from the <code>target/test-wars</code> directory (created and managed above using the
|
|
|
|
|
* <code>maven-dependency-plugin</code>) to copy the WAR into the test specific directory.</li>
|
|
|
|
|
* </ol>
|
|
|
|
|
* <p>
|
|
|
|
|
* Next you'll want to use Junit 4.8+ and the <code>@BeforeClass</code> and <code>@AfterClass</code> annotations to setup the <code>JettyDistro</code>
|
|
|
|
|
* class for setting up your testing configuration.
|
|
|
|
|
* <p>
|
|
|
|
|
* Example Test Case using {@link JettyDistro} class
|
|
|
|
|
*
|
|
|
|
|
* <pre>
|
|
|
|
|
* public class MySampleTest
|
|
|
|
|
* {
|
|
|
|
|
* private static JettyDistro jetty;
|
|
|
|
|
*
|
|
|
|
|
* @BeforeClass
|
|
|
|
|
* public static void initJetty() throws Exception
|
|
|
|
|
* {
|
|
|
|
|
* jetty = new JettyDistro(MySampleTest.class);
|
|
|
|
|
*
|
|
|
|
|
* jetty.copyTestWar("test-war-java_util_logging.war");
|
|
|
|
|
* jetty.copyTestWar("test-war-policy.war");
|
|
|
|
|
*
|
|
|
|
|
* jetty.delete("webapps/test.war");
|
|
|
|
|
* jetty.delete("contexts/test.d");
|
|
|
|
|
* jetty.delete("contexts/javadoc.xml");
|
|
|
|
|
* jetty.delete("contexts/test.xml");
|
|
|
|
|
*
|
|
|
|
|
* jetty.overlayConfig("no_security");
|
|
|
|
|
*
|
|
|
|
|
* jetty.setDebug(true);
|
|
|
|
|
*
|
|
|
|
|
* jetty.start();
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* @AfterClass
|
|
|
|
|
* public static void shutdownJetty() throws Exception
|
|
|
|
|
* {
|
|
|
|
|
* if (jetty != null)
|
|
|
|
|
* {
|
|
|
|
|
* jetty.stop();
|
|
|
|
|
* }
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* @Test
|
|
|
|
|
* public void testRequest() throws Exception
|
|
|
|
|
* {
|
|
|
|
|
* SimpleRequest request = new SimpleRequest(jetty.getBaseUri());
|
|
|
|
|
* String path = "/test-war-policy/security/PRACTICAL/testFilsystem");
|
|
|
|
|
* String response = request.getString(path);
|
|
|
|
|
* Assert.assertEquals("Success", response);
|
|
|
|
|
* }
|
|
|
|
|
* }
|
|
|
|
|
* </pre>
|
|
|
|
|
*/
|
|
|
|
|
public class JettyDistro
|
|
|
|
|
{
|
|
|
|
|
private String artifactName = "jetty-distribution";
|
|
|
|
|
private long startTime = 60;
|
|
|
|
|
private TimeUnit timeUnit = TimeUnit.SECONDS;
|
|
|
|
|
|
|
|
|
|
private File jettyHomeDir;
|
|
|
|
|
private Process pid;
|
|
|
|
|
private URI baseUri;
|
|
|
|
|
|
|
|
|
|
private String jmxUrl;
|
|
|
|
|
|
|
|
|
|
private boolean _debug = false;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Setup the JettyHome as belonging in a testing directory associated with a testing clazz.
|
|
|
|
|
*
|
|
|
|
|
* @param clazz
|
|
|
|
|
* the testing class using this JettyDistro
|
|
|
|
|
* @throws IOException
|
|
|
|
|
* if unable to copy unpacked distribution into place for the provided testing directory
|
|
|
|
|
*/
|
|
|
|
|
public JettyDistro(Class<?> clazz) throws IOException
|
|
|
|
|
{
|
|
|
|
|
this(clazz,null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Setup the JettyHome as belonging in a testing directory associated with a testing clazz.
|
|
|
|
|
*
|
|
|
|
|
* @param clazz
|
|
|
|
|
* the testing class using this JettyDistro
|
|
|
|
|
* @param artifact
|
|
|
|
|
* name of jetty distribution artifact
|
|
|
|
|
* @throws IOException
|
|
|
|
|
* if unable to copy unpacked distribution into place for the provided testing directory
|
|
|
|
|
*/
|
|
|
|
|
public JettyDistro(Class<?> clazz, String artifact) throws IOException
|
|
|
|
|
{
|
|
|
|
|
this.jettyHomeDir = MavenTestingUtils.getTargetTestingDir(clazz,"jettyHome");
|
|
|
|
|
if (artifact != null)
|
|
|
|
|
{
|
|
|
|
|
this.artifactName = artifact;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
copyBaseDistro();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Setup the JettyHome as belonging to a specific testing method directory
|
|
|
|
|
*
|
|
|
|
|
* @param testdir
|
|
|
|
|
* the testing directory to use as the JettyHome for this JettyDistro
|
|
|
|
|
* @throws IOException
|
|
|
|
|
* if unable to copy unpacked distribution into place for the provided testing directory
|
|
|
|
|
*/
|
|
|
|
|
public JettyDistro(TestingDir testdir) throws IOException
|
|
|
|
|
{
|
|
|
|
|
this.jettyHomeDir = testdir.getDir();
|
|
|
|
|
copyBaseDistro();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Setup the JettyHome as belonging to a specific testing method directory
|
|
|
|
|
*
|
|
|
|
|
* @param testdir
|
|
|
|
|
* the testing directory to use as the JettyHome for this JettyDistro
|
|
|
|
|
* @param artifact
|
|
|
|
|
* name of jetty distribution artifact
|
|
|
|
|
* @throws IOException
|
|
|
|
|
* if unable to copy unpacked distribution into place for the provided testing directory
|
|
|
|
|
*/
|
|
|
|
|
public JettyDistro(TestingDir testdir, String artifact) throws IOException
|
|
|
|
|
{
|
|
|
|
|
this.jettyHomeDir = testdir.getDir();
|
|
|
|
|
if (artifact != null)
|
|
|
|
|
{
|
|
|
|
|
this.artifactName = artifact;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
copyBaseDistro();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
*
|
|
|
|
|
* @throws IOException
|
|
|
|
|
* if unable to copy unpacked distribution into place for the provided testing directory
|
|
|
|
|
*/
|
|
|
|
|
private void copyBaseDistro() throws IOException
|
|
|
|
|
{
|
|
|
|
|
// The outputDirectory for the maven side dependency:unpack goal.
|
|
|
|
|
File distroUnpackDir = MavenTestingUtils.getTargetFile("test-dist");
|
|
|
|
|
PathAssert.assertDirExists(artifactName + " dependency:unpack",distroUnpackDir);
|
|
|
|
|
|
|
|
|
|
// The actual jetty-distribution-${version} directory is under this directory.
|
|
|
|
|
// Lets find it.
|
|
|
|
|
File subdirs[] = distroUnpackDir.listFiles(new FileFilter()
|
|
|
|
|
{
|
|
|
|
|
public boolean accept(File path)
|
|
|
|
|
{
|
|
|
|
|
if (!path.isDirectory())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return path.getName().startsWith(artifactName + "-");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (subdirs.length == 0)
|
|
|
|
|
{
|
|
|
|
|
// No jetty-distribution found.
|
|
|
|
|
StringBuilder err = new StringBuilder();
|
|
|
|
|
err.append("No target/test-dist/");
|
|
|
|
|
err.append(artifactName);
|
|
|
|
|
err.append("-${version} directory found.");
|
|
|
|
|
err.append("\n To fix this, run 'mvn process-test-resources' to create the directory.");
|
|
|
|
|
throw new IOException(err.toString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (subdirs.length != 1)
|
|
|
|
|
{
|
|
|
|
|
// Too many jetty-distributions found.
|
|
|
|
|
StringBuilder err = new StringBuilder();
|
|
|
|
|
err.append("Too many target/test-dist/");
|
|
|
|
|
err.append(artifactName);
|
|
|
|
|
err.append("-${version} directories found.");
|
|
|
|
|
for (File dir : subdirs)
|
|
|
|
|
{
|
|
|
|
|
err.append("\n ").append(dir.getAbsolutePath());
|
|
|
|
|
}
|
|
|
|
|
err.append("\n To fix this, run 'mvn clean process-test-resources' to recreate the target/test-dist directory.");
|
|
|
|
|
throw new IOException(err.toString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
File distroSrcDir = subdirs[0];
|
|
|
|
|
FS.ensureEmpty(jettyHomeDir);
|
|
|
|
|
System.out.printf("Copying Jetty Distribution: %s%n",distroSrcDir.getAbsolutePath());
|
|
|
|
|
System.out.printf(" To Testing Dir: %s%n",jettyHomeDir.getAbsolutePath());
|
|
|
|
|
IO.copyDir(distroSrcDir,jettyHomeDir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the $(jetty.home) directory being used for this JettyDistro
|
|
|
|
|
*
|
|
|
|
|
* @return the jetty.home directory being used
|
|
|
|
|
*/
|
|
|
|
|
public File getJettyHomeDir()
|
|
|
|
|
{
|
|
|
|
|
return this.jettyHomeDir;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Copy a war file from ${project.basedir}/target/test-wars/${testWarFilename} into the ${jetty.home}/webapps/ directory
|
|
|
|
|
*
|
|
|
|
|
* @param testWarFilename
|
|
|
|
|
* the war file to copy (must exist)
|
|
|
|
|
* @throws IOException
|
|
|
|
|
* if unable to copy the war file.
|
|
|
|
|
*/
|
|
|
|
|
public void copyTestWar(String testWarFilename) throws IOException
|
|
|
|
|
{
|
|
|
|
|
File srcWar = MavenTestingUtils.getTargetFile("test-wars/" + testWarFilename);
|
|
|
|
|
File destWar = new File(jettyHomeDir,OS.separators("webapps/" + testWarFilename));
|
|
|
|
|
FS.ensureDirExists(destWar.getParentFile());
|
|
|
|
|
IO.copyFile(srcWar,destWar);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Copy an arbitrary file from <code>src/test/resources/${resourcePath}</code> to the testing directory.
|
|
|
|
|
*
|
|
|
|
|
* @param resourcePath
|
|
|
|
|
* the relative path for file content within the <code>src/test/resources</code> directory.
|
|
|
|
|
* @param outputPath
|
|
|
|
|
* the testing directory relative output path for the file output (will result in a file with the outputPath name being created)
|
|
|
|
|
* @throws IOException
|
|
|
|
|
* if unable to copy resource file
|
|
|
|
|
*/
|
|
|
|
|
public void copyResource(String resourcePath, String outputPath) throws IOException
|
|
|
|
|
{
|
|
|
|
|
File srcFile = MavenTestingUtils.getTestResourceFile(resourcePath);
|
|
|
|
|
File destFile = new File(jettyHomeDir,OS.separators(outputPath));
|
|
|
|
|
FS.ensureDirExists(destFile.getParentFile());
|
|
|
|
|
IO.copyFile(srcFile,destFile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Copy an arbitrary file from <code>target/test-libs/${libFilename}</code> to the testing directory.
|
|
|
|
|
*
|
|
|
|
|
* @param libFilename
|
|
|
|
|
* the <code>target/test-libs/${libFilename}</code> to copy
|
|
|
|
|
* @param outputPath
|
|
|
|
|
* the destination testing directory relative output path for the lib. (will result in a file with the outputPath name being created)
|
|
|
|
|
* @throws IOException
|
|
|
|
|
* if unable to copy lib
|
|
|
|
|
*/
|
|
|
|
|
public void copyLib(String libFilename, String outputPath) throws IOException
|
|
|
|
|
{
|
|
|
|
|
File srcLib = MavenTestingUtils.getTargetFile("test-libs/" + libFilename);
|
|
|
|
|
File destLib = new File(jettyHomeDir,OS.separators(outputPath));
|
|
|
|
|
FS.ensureDirExists(destLib.getParentFile());
|
|
|
|
|
IO.copyFile(srcLib,destLib);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Copy the <code>${project.basedir}/src/main/config/</code> tree into the testing directory.
|
|
|
|
|
*
|
|
|
|
|
* @throws IOException
|
|
|
|
|
* if unable to copy the directory tree
|
|
|
|
|
*/
|
|
|
|
|
public void copyProjectMainConfig() throws IOException
|
|
|
|
|
{
|
|
|
|
|
File srcDir = MavenTestingUtils.getProjectDir("src/main/config");
|
|
|
|
|
IO.copyDir(srcDir,jettyHomeDir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Create a <code>${jetty.home}/lib/self/${jarFilename}</code> jar file from the content in the <code>${project.basedir}/target/classes/</code> directory.
|
|
|
|
|
*
|
|
|
|
|
* @throws IOException
|
|
|
|
|
* if unable to copy the directory tree
|
|
|
|
|
*/
|
|
|
|
|
public void createProjectLib(String jarFilename) throws IOException
|
|
|
|
|
{
|
|
|
|
|
File srcDir = MavenTestingUtils.getTargetFile("classes");
|
|
|
|
|
File libSelfDir = new File(jettyHomeDir,OS.separators("lib/self"));
|
|
|
|
|
FS.ensureDirExists(libSelfDir);
|
|
|
|
|
File jarFile = new File(libSelfDir,jarFilename);
|
|
|
|
|
JAR.create(srcDir,jarFile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Unpack an arbitrary config from <code>target/test-configs/${configFilename}</code> to the testing directory.
|
|
|
|
|
*
|
|
|
|
|
* @param configFilename
|
|
|
|
|
* the <code>target/test-configs/${configFilename}</code> to copy
|
|
|
|
|
* @throws IOException
|
|
|
|
|
* if unable to unpack config file
|
|
|
|
|
*/
|
|
|
|
|
public void unpackConfig(String configFilename) throws IOException
|
|
|
|
|
{
|
|
|
|
|
File srcConfig = MavenTestingUtils.getTargetFile("test-configs/" + configFilename);
|
|
|
|
|
JAR.unpack(srcConfig,jettyHomeDir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Delete a File or Directory found in the ${jetty.home} directory.
|
|
|
|
|
*
|
|
|
|
|
* @param path
|
|
|
|
|
* the path to delete. (can be a file or directory)
|
|
|
|
|
*/
|
|
|
|
|
public void delete(String path)
|
|
|
|
|
{
|
|
|
|
|
File jettyPath = new File(jettyHomeDir,OS.separators(path));
|
|
|
|
|
FS.delete(jettyPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the baseUri being used for this Jetty Process Instance.
|
|
|
|
|
*
|
|
|
|
|
* @return the base URI for this Jetty Process Instance.
|
|
|
|
|
*/
|
|
|
|
|
public URI getBaseUri()
|
|
|
|
|
{
|
|
|
|
|
return this.baseUri;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the JMX URL being used for this Jetty Process Instance.
|
|
|
|
|
*
|
|
|
|
|
* @return the JMX URL for this Jetty Process Instance.
|
|
|
|
|
*/
|
|
|
|
|
public String getJmxUrl()
|
|
|
|
|
{
|
|
|
|
|
return this.jmxUrl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Take the directory contents from ${project.basedir}/src/test/resources/${testConfigName}/ and copy it over whatever happens to be at ${jetty.home}
|
|
|
|
|
*
|
|
|
|
|
* @param testConfigName
|
|
|
|
|
* the src/test/resources/ directory name to use as the source diretory for the configuration we are interested in.
|
|
|
|
|
* @throws IOException
|
|
|
|
|
* if unable to copy directory.
|
|
|
|
|
*/
|
|
|
|
|
public void overlayConfig(String testConfigName) throws IOException
|
|
|
|
|
{
|
|
|
|
|
File srcDir = MavenTestingUtils.getTestResourceDir(testConfigName);
|
|
|
|
|
IO.copyDir(srcDir,jettyHomeDir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Start the jetty server
|
|
|
|
|
*
|
|
|
|
|
* @throws IOException
|
|
|
|
|
* if unable to start the server.
|
|
|
|
|
*/
|
|
|
|
|
public void start() throws IOException
|
|
|
|
|
{
|
|
|
|
|
List<String> commands = new ArrayList<String>();
|
|
|
|
|
commands.add(getJavaBin());
|
|
|
|
|
|
|
|
|
|
commands.add("-Djetty.home=" + jettyHomeDir.getAbsolutePath());
|
|
|
|
|
|
|
|
|
|
// Do a dry run first to get the exact command line for Jetty process
|
|
|
|
|
commands.add("-jar");
|
|
|
|
|
commands.add("start.jar");
|
|
|
|
|
commands.add("jetty.port=0");
|
|
|
|
|
if (_debug)
|
|
|
|
|
{
|
|
|
|
|
commands.add("-D.DEBUG=true");
|
|
|
|
|
}
|
|
|
|
|
commands.add("--dry-run");
|
|
|
|
|
|
|
|
|
|
ProcessBuilder pbCmd = new ProcessBuilder(commands);
|
|
|
|
|
pbCmd.directory(jettyHomeDir);
|
|
|
|
|
|
|
|
|
|
String cmdLine = null;
|
|
|
|
|
Process pidCmd = pbCmd.start();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
cmdLine = readOutputLine(pidCmd);
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
pidCmd.destroy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cmdLine == null || !cmdLine.contains("XmlConfiguration"))
|
|
|
|
|
{
|
|
|
|
|
Assert.fail("Unable to get Jetty command line");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Need to breakdown commandline into parts, as spaces in command line will cause failures.
|
|
|
|
|
List<String> execCommands = splitAndUnescapeCommandLine(cmdLine);
|
|
|
|
|
|
|
|
|
|
System.out.printf("Executing: %s%n",cmdLine);
|
|
|
|
|
System.out.printf("Working Dir: %s%n",jettyHomeDir.getAbsolutePath());
|
|
|
|
|
|
|
|
|
|
pbCmd = new ProcessBuilder(execCommands);
|
|
|
|
|
pid = pbCmd.start();
|
|
|
|
|
|
|
|
|
|
ConsoleParser parser = new ConsoleParser();
|
|
|
|
|
List<String[]> jmxList = parser.newPattern("JMX Remote URL: (.*)",0);
|
|
|
|
|
List<String[]> connList = parser.newPattern("Started [A-Za-z]*Connector@([0-9]*\\.[0-9]*\\.[0-9]*\\.[0-9]*):([0-9]*)",1);
|
|
|
|
|
// DISABLED: This is what exists in Jetty 9+
|
|
|
|
|
// List<String[]> connList = parser.newPattern("Started [A-Za-z]*Connector@.*[\\({]([0-9]*\\.[0-9]*\\.[0-9]*\\.[0-9]*):([0-9]*)[\\)}].*",1);
|
|
|
|
|
|
|
|
|
|
startPump("STDOUT",parser,this.pid.getInputStream());
|
|
|
|
|
startPump("STDERR",parser,this.pid.getErrorStream());
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
parser.waitForDone(this.startTime,this.timeUnit);
|
|
|
|
|
|
|
|
|
|
if (!jmxList.isEmpty())
|
|
|
|
|
{
|
|
|
|
|
this.jmxUrl = jmxList.get(0)[0];
|
|
|
|
|
System.out.printf("## Found JMX connector at %s%n",this.jmxUrl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!connList.isEmpty())
|
|
|
|
|
{
|
|
|
|
|
String[] params = connList.get(0);
|
|
|
|
|
if (params.length == 2)
|
|
|
|
|
{
|
|
|
|
|
this.baseUri = URI.create("http://localhost:" + params[1] + "/");
|
|
|
|
|
}
|
|
|
|
|
System.out.printf("## Found Jetty connector at host: %s port: %s%n",(Object[])params);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
catch (InterruptedException e)
|
|
|
|
|
{
|
|
|
|
|
pid.destroy();
|
|
|
|
|
Assert.fail("Unable to get required information within time limit");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static List<String> splitAndUnescapeCommandLine(CharSequence rawCmdLine)
|
|
|
|
|
{
|
|
|
|
|
List<String> cmds = new ArrayList<String>();
|
|
|
|
|
|
|
|
|
|
int len = rawCmdLine.length();
|
|
|
|
|
StringBuilder arg = new StringBuilder();
|
|
|
|
|
boolean escaped = false;
|
|
|
|
|
boolean inQuote = false;
|
|
|
|
|
char c;
|
|
|
|
|
for (int i = 0; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
c = rawCmdLine.charAt(i);
|
|
|
|
|
if (escaped)
|
|
|
|
|
{
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case 'r':
|
|
|
|
|
arg.append('\r');
|
|
|
|
|
break;
|
|
|
|
|
case 'f':
|
|
|
|
|
arg.append('\f');
|
|
|
|
|
break;
|
|
|
|
|
case 't':
|
|
|
|
|
arg.append('\t');
|
|
|
|
|
break;
|
|
|
|
|
case 'n':
|
|
|
|
|
arg.append('\n');
|
|
|
|
|
break;
|
|
|
|
|
case 'b':
|
|
|
|
|
arg.append('\b');
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
arg.append(c);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
escaped = false;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (c == '\\')
|
|
|
|
|
{
|
|
|
|
|
escaped = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if ((c == ' ') && (!inQuote))
|
|
|
|
|
{
|
|
|
|
|
// the delim!
|
|
|
|
|
cmds.add(String.valueOf(arg.toString()));
|
|
|
|
|
arg.setLength(0);
|
|
|
|
|
}
|
|
|
|
|
else if (c == '"')
|
|
|
|
|
{
|
|
|
|
|
inQuote = !inQuote;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
arg.append(c);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
cmds.add(String.valueOf(arg.toString()));
|
|
|
|
|
|
|
|
|
|
return cmds;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String readOutputLine(Process pidCmd) throws IOException
|
|
|
|
|
{
|
|
|
|
|
InputStream in = null;
|
|
|
|
|
InputStreamReader reader = null;
|
|
|
|
|
BufferedReader buf = null;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
in = pidCmd.getInputStream();
|
|
|
|
|
reader = new InputStreamReader(in);
|
|
|
|
|
buf = new BufferedReader(reader);
|
|
|
|
|
return buf.readLine();
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
IO.close(buf);
|
|
|
|
|
IO.close(reader);
|
|
|
|
|
IO.close(in);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static class ConsoleParser
|
|
|
|
|
{
|
|
|
|
|
private List<ConsolePattern> patterns = new ArrayList<ConsolePattern>();
|
|
|
|
|
private CountDownLatch latch;
|
|
|
|
|
private int count;
|
|
|
|
|
|
|
|
|
|
public List<String[]> newPattern(String exp, int cnt)
|
|
|
|
|
{
|
|
|
|
|
ConsolePattern pat = new ConsolePattern(exp,cnt);
|
|
|
|
|
patterns.add(pat);
|
|
|
|
|
count += cnt;
|
|
|
|
|
|
|
|
|
|
return pat.getMatches();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void parse(String line)
|
|
|
|
|
{
|
|
|
|
|
for (ConsolePattern pat : patterns)
|
|
|
|
|
{
|
|
|
|
|
Matcher mat = pat.getMatcher(line);
|
|
|
|
|
if (mat.find())
|
|
|
|
|
{
|
|
|
|
|
int num = 0, count = mat.groupCount();
|
|
|
|
|
String[] match = new String[count];
|
|
|
|
|
while (num++ < count)
|
|
|
|
|
{
|
|
|
|
|
match[num - 1] = mat.group(num);
|
|
|
|
|
}
|
|
|
|
|
pat.getMatches().add(match);
|
|
|
|
|
|
|
|
|
|
if (pat.getCount() > 0)
|
|
|
|
|
{
|
|
|
|
|
getLatch().countDown();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void waitForDone(long timeout, TimeUnit unit) throws InterruptedException
|
|
|
|
|
{
|
|
|
|
|
getLatch().await(timeout,unit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private CountDownLatch getLatch()
|
|
|
|
|
{
|
|
|
|
|
synchronized (this)
|
|
|
|
|
{
|
|
|
|
|
if (latch == null)
|
|
|
|
|
{
|
|
|
|
|
latch = new CountDownLatch(count);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return latch;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static class ConsolePattern
|
|
|
|
|
{
|
|
|
|
|
private Pattern pattern;
|
|
|
|
|
private List<String[]> matches;
|
|
|
|
|
private int count;
|
|
|
|
|
|
|
|
|
|
ConsolePattern(String exp, int cnt)
|
|
|
|
|
{
|
|
|
|
|
pattern = Pattern.compile(exp);
|
|
|
|
|
matches = new ArrayList<String[]>();
|
|
|
|
|
count = cnt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Matcher getMatcher(String line)
|
|
|
|
|
{
|
|
|
|
|
return pattern.matcher(line);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<String[]> getMatches()
|
|
|
|
|
{
|
|
|
|
|
return matches;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int getCount()
|
|
|
|
|
{
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void startPump(String mode, ConsoleParser parser, InputStream inputStream)
|
|
|
|
|
{
|
|
|
|
|
ConsoleStreamer pump = new ConsoleStreamer(mode,inputStream);
|
|
|
|
|
pump.setParser(parser);
|
|
|
|
|
Thread thread = new Thread(pump,"ConsoleStreamer/" + mode);
|
|
|
|
|
thread.start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* enable debug on the jetty process
|
|
|
|
|
*
|
|
|
|
|
* @param debug
|
|
|
|
|
*/
|
|
|
|
|
public void setDebug(boolean debug)
|
|
|
|
|
{
|
|
|
|
|
_debug = debug;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String getJavaBin()
|
|
|
|
|
{
|
|
|
|
|
String javaexes[] = new String[]
|
|
|
|
|
{ "java", "java.exe" };
|
|
|
|
|
|
|
|
|
|
File javaHomeDir = new File(System.getProperty("java.home"));
|
|
|
|
|
for (String javaexe : javaexes)
|
|
|
|
|
{
|
|
|
|
|
File javabin = new File(javaHomeDir,OS.separators("bin/" + javaexe));
|
|
|
|
|
if (javabin.exists() && javabin.isFile())
|
|
|
|
|
{
|
|
|
|
|
return javabin.getAbsolutePath();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Assert.fail("Unable to find java bin");
|
|
|
|
|
return "java";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Stop the jetty server
|
|
|
|
|
*/
|
|
|
|
|
public void stop()
|
|
|
|
|
{
|
|
|
|
|
System.out.println("Stopping JettyDistro ...");
|
|
|
|
|
if (pid != null)
|
|
|
|
|
{
|
|
|
|
|
// TODO: maybe issue a STOP instead?
|
|
|
|
|
pid.destroy();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Simple streamer for the console output from a Process
|
|
|
|
|
*/
|
|
|
|
|
private static class ConsoleStreamer implements Runnable
|
|
|
|
|
{
|
|
|
|
|
private String mode;
|
|
|
|
|
private BufferedReader reader;
|
|
|
|
|
private ConsoleParser parser;
|
|
|
|
|
|
|
|
|
|
public ConsoleStreamer(String mode, InputStream is)
|
|
|
|
|
{
|
|
|
|
|
this.mode = mode;
|
|
|
|
|
this.reader = new BufferedReader(new InputStreamReader(is));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setParser(ConsoleParser connector)
|
|
|
|
|
{
|
|
|
|
|
this.parser = connector;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void run()
|
|
|
|
|
{
|
|
|
|
|
String line;
|
|
|
|
|
// System.out.printf("ConsoleStreamer/%s initiated%n",mode);
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
while ((line = reader.readLine()) != (null))
|
|
|
|
|
{
|
|
|
|
|
if (parser != null)
|
|
|
|
|
{
|
|
|
|
|
parser.parse(line);
|
|
|
|
|
}
|
|
|
|
|
System.out.println("[" + mode + "] " + line);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (IOException ignore)
|
|
|
|
|
{
|
|
|
|
|
/* ignore */
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
IO.close(reader);
|
|
|
|
|
}
|
|
|
|
|
// System.out.printf("ConsoleStreamer/%s finished%n",mode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setStartTime(long startTime, TimeUnit timeUnit)
|
|
|
|
|
{
|
|
|
|
|
this.startTime = startTime;
|
|
|
|
|
this.timeUnit = timeUnit;
|
|
|
|
|
}
|
|
|
|
|
}
|