Merge branch 'jetty-7' into jetty-8

This commit is contained in:
Joakim Erdfelt 2013-08-02 15:11:05 -07:00
commit 01786aa0c2
7 changed files with 914 additions and 41 deletions

View File

@ -6,9 +6,9 @@
<version>8.1.13-SNAPSHOT</version> <version>8.1.13-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>spdy-core</artifactId> <artifactId>spdy-core</artifactId>
<name>Jetty :: SPDY :: Core</name> <name>Jetty :: SPDY :: Core</name>
<url>http://www.eclipse.org/jetty</url> <url>http://www.eclipse.org/jetty</url>
<dependencies> <dependencies>
<dependency> <dependency>
@ -16,21 +16,21 @@
<artifactId>jetty-util</artifactId> <artifactId>jetty-util</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.hamcrest</groupId> <groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId> <artifactId>hamcrest-library</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId> <artifactId>mockito-core</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId> <artifactId>slf4j-log4j12</artifactId>

View File

@ -64,13 +64,13 @@
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.hamcrest</groupId> <groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId> <artifactId>hamcrest-library</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId> <artifactId>slf4j-log4j12</artifactId>

17
pom.xml
View File

@ -510,7 +510,7 @@
<dependency> <dependency>
<groupId>org.eclipse.jetty.toolchain</groupId> <groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId> <artifactId>jetty-test-helper</artifactId>
<version>2.0</version> <version>2.5</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
@ -530,17 +530,22 @@
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.8.1</version> <version>4.11</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.hamcrest</groupId> <groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId> <artifactId>hamcrest-core</artifactId>
<version>1.1</version> <version>1.3</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId> <artifactId>mockito-core</artifactId>
<version>1.8.5</version> <version>1.9.5</version>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>

View File

@ -18,21 +18,18 @@
package org.eclipse.jetty.test.monitor; package org.eclipse.jetty.test.monitor;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.*;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import javax.management.MBeanServerConnection;
import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.monitor.JMXMonitor; import org.eclipse.jetty.monitor.JMXMonitor;
import org.eclipse.jetty.toolchain.jmx.JmxServiceConnection; import org.eclipse.jetty.test.support.JettyDistro;
import org.eclipse.jetty.toolchain.test.JettyDistro;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;

View File

@ -18,15 +18,13 @@
package org.eclipse.jetty.test.monitor; package org.eclipse.jetty.test.monitor;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.*;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import javax.management.MBeanServerConnection;
import org.eclipse.jetty.client.ContentExchange; import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.http.HttpMethods;
@ -40,8 +38,7 @@ import org.eclipse.jetty.monitor.jmx.MonitorAction;
import org.eclipse.jetty.monitor.triggers.GreaterThanAttrEventTrigger; import org.eclipse.jetty.monitor.triggers.GreaterThanAttrEventTrigger;
import org.eclipse.jetty.monitor.triggers.LessThanOrEqualToAttrEventTrigger; import org.eclipse.jetty.monitor.triggers.LessThanOrEqualToAttrEventTrigger;
import org.eclipse.jetty.monitor.triggers.OrEventTrigger; import org.eclipse.jetty.monitor.triggers.OrEventTrigger;
import org.eclipse.jetty.toolchain.jmx.JmxServiceConnection; import org.eclipse.jetty.test.support.JettyDistro;
import org.eclipse.jetty.toolchain.test.JettyDistro;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.ExecutorThreadPool; import org.eclipse.jetty.util.thread.ExecutorThreadPool;

View File

@ -18,7 +18,7 @@
package org.eclipse.jetty.test.monitor; package org.eclipse.jetty.test.monitor;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.*;
import java.io.IOException; import java.io.IOException;
import java.util.Random; import java.util.Random;
@ -30,7 +30,7 @@ import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.http.HttpMethods; import org.eclipse.jetty.http.HttpMethods;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.monitor.JMXMonitor; import org.eclipse.jetty.monitor.JMXMonitor;
import org.eclipse.jetty.toolchain.test.JettyDistro; import org.eclipse.jetty.test.support.JettyDistro;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;

View File

@ -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>
* &lt;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"&gt;
*
* &lt;!-- Common Destination Directories --&gt;
*
* &lt;properties&gt;
* &lt;test-wars-dir&gt;${project.build.directory}/test-wars&lt;/test-wars-dir&gt;
* &lt;test-libs-dir&gt;${project.build.directory}/test-libs&lt;/test-libs-dir&gt;
* &lt;test-distro-dir&gt;${project.build.directory}/test-dist&lt;/test-distro-dir&gt;
* &lt;/properties&gt;
*
* &lt;build&gt;
* &lt;plugins&gt;
* &lt;plugin&gt;
* &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
* &lt;artifactId&gt;maven-dependency-plugin&lt;/artifactId&gt;
* &lt;version&gt;2.1&lt;/version&gt;
* &lt;executions&gt;
*
* &lt;!-- Copy LIB and WAR dependencies into place that JettyDistro can use them --&gt;
*
* &lt;execution&gt;
* &lt;id&gt;test-lib-war-copy&lt;/id&gt;
* &lt;phase&gt;process-test-resources&lt;/phase&gt;
* &lt;goals&gt;
* &lt;goal&gt;copy&lt;/goal&gt;
* &lt;/goals&gt;
* &lt;configuration&gt;
* &lt;artifactItems&gt;
* &lt;artifactItem&gt;
* &lt;groupId&gt;org.mortbay.jetty.testwars&lt;/groupId&gt;
* &lt;artifactId&gt;test-war-java_util_logging&lt;/artifactId&gt;
* &lt;version&gt;7.3.0&lt;/version&gt;
* &lt;type&gt;war&lt;/type&gt;
* &lt;outputDirectory&gt;${test-wars-dir}&lt;/outputDirectory&gt;
* &lt;/artifactItem&gt;
* &lt;artifactItem&gt;
* &lt;groupId&gt;org.mortbay.jetty&lt;/groupId&gt;
* &lt;artifactId&gt;jetty-aspect-servlet-api-2.5&lt;/artifactId&gt;
* &lt;version&gt;7.3.0&lt;/version&gt;
* &lt;type&gt;jar&lt;/type&gt;
* &lt;outputDirectory&gt;${test-libs-dir}&lt;/outputDirectory&gt;
* &lt;/artifactItem&gt;
* &lt;/artifactItems&gt;
* &lt;overWriteIfNewer&gt;true&lt;/overWriteIfNewer&gt;
* &lt;overWrite&gt;true&lt;/overWrite&gt;
* &lt;stripVersion&gt;true&lt;/stripVersion&gt;
* &lt;/configuration&gt;
* &lt;/execution&gt;
*
* &lt;!-- Extract Jetty DISTRIBUTION into place that JettyDistro can use it --&gt;
*
* &lt;execution&gt;
* &lt;id&gt;unpack-test-dist&lt;/id&gt;
* &lt;phase&gt;process-test-resources&lt;/phase&gt;
* &lt;goals&gt;
* &lt;goal&gt;unpack&lt;/goal&gt;
* &lt;/goals&gt;
* &lt;configuration&gt;
* &lt;artifactItems&gt;
* &lt;artifactItem&gt;
* &lt;groupId&gt;org.eclipse.jetty&lt;/groupId&gt;
* &lt;artifactId&gt;jetty-distribution&lt;/artifactId&gt;
* &lt;version&gt;7.3.0&lt;/version&gt;
* &lt;type&gt;zip&lt;/type&gt;
* &lt;overWrite&gt;true&lt;/overWrite&gt;
* &lt;/artifactItem&gt;
* &lt;/artifactItems&gt;
* &lt;outputAbsoluteArtifactFilename&gt;true&lt;/outputAbsoluteArtifactFilename&gt;
* &lt;outputDirectory&gt;${test-distro-dir}&lt;/outputDirectory&gt;
* &lt;overWriteSnapshots&gt;true&lt;/overWriteSnapshots&gt;
* &lt;overWriteIfNewer&gt;true&lt;/overWriteIfNewer&gt;
* &lt;/configuration&gt;
* &lt;/execution&gt;
* &lt;/executions&gt;
* &lt;/plugin&gt;
* &lt;/plugins&gt;
* &lt;/build&gt;
*
* &lt;/project&gt;
* </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>&#064;BeforeClass</code> and <code>&#064;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;
*
* &#064;BeforeClass
* public static void initJetty() throws Exception
* {
* jetty = new JettyDistro(MySampleTest.class);
*
* jetty.copyTestWar(&quot;test-war-java_util_logging.war&quot;);
* jetty.copyTestWar(&quot;test-war-policy.war&quot;);
*
* jetty.delete(&quot;webapps/test.war&quot;);
* jetty.delete(&quot;contexts/test.d&quot;);
* jetty.delete(&quot;contexts/javadoc.xml&quot;);
* jetty.delete(&quot;contexts/test.xml&quot;);
*
* jetty.overlayConfig(&quot;no_security&quot;);
*
* jetty.setDebug(true);
*
* jetty.start();
* }
*
* &#064;AfterClass
* public static void shutdownJetty() throws Exception
* {
* if (jetty != null)
* {
* jetty.stop();
* }
* }
*
* &#064;Test
* public void testRequest() throws Exception
* {
* SimpleRequest request = new SimpleRequest(jetty.getBaseUri());
* String path = &quot;/test-war-policy/security/PRACTICAL/testFilsystem&quot;);
* String response = request.getString(path);
* Assert.assertEquals(&quot;Success&quot;, 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;
}
}