blob: 6f9b7ce9df6a9f01593440b34468ca93a73937e6 [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2017 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.deploy.test;
import static org.hamcrest.Matchers.is;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.PathAssert;
import org.eclipse.jetty.toolchain.test.TestingDir;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.junit.Assert;
/**
* Allows for setting up a Jetty server for testing based on XML configuration files.
*/
public class XmlConfiguredJetty
{
private List<URL> _xmlConfigurations;
private Map<String,String> _properties = new HashMap<>();
private Server _server;
private int _serverPort;
private String _scheme = HttpScheme.HTTP.asString();
private File _jettyHome;
public XmlConfiguredJetty(TestingDir testdir) throws IOException
{
_xmlConfigurations = new ArrayList<>();
Properties properties = new Properties();
String jettyHomeBase = testdir.getPath().toString();
// Ensure we have a new (pristene) directory to work with.
int idx = 0;
_jettyHome = new File(jettyHomeBase + "#" + idx);
while (_jettyHome.exists())
{
idx++;
_jettyHome = new File(jettyHomeBase + "#" + idx);
}
deleteContents(_jettyHome);
// Prepare Jetty.Home (Test) dir
_jettyHome.mkdirs();
File logsDir = new File(_jettyHome,"logs");
logsDir.mkdirs();
File etcDir = new File(_jettyHome,"etc");
etcDir.mkdirs();
IO.copyFile(MavenTestingUtils.getTestResourceFile("etc/realm.properties"),new File(etcDir,"realm.properties"));
IO.copyFile(MavenTestingUtils.getTestResourceFile("etc/webdefault.xml"),new File(etcDir,"webdefault.xml"));
File webappsDir = new File(_jettyHome,"webapps");
if (webappsDir.exists())
{
deleteContents(webappsDir);
}
webappsDir.mkdirs();
File tmpDir = new File(_jettyHome,"tmp");
if (tmpDir.exists())
{
deleteContents(tmpDir);
}
tmpDir.mkdirs();
File workishDir = new File(_jettyHome,"workish");
if (workishDir.exists())
{
deleteContents(workishDir);
}
workishDir.mkdirs();
// Setup properties
System.setProperty("java.io.tmpdir",tmpDir.getAbsolutePath());
properties.setProperty("jetty.home",_jettyHome.getAbsolutePath());
System.setProperty("jetty.home",_jettyHome.getAbsolutePath());
properties.setProperty("test.basedir",MavenTestingUtils.getBaseDir().getAbsolutePath());
properties.setProperty("test.resourcesdir",MavenTestingUtils.getTestResourcesDir().getAbsolutePath());
properties.setProperty("test.webapps",webappsDir.getAbsolutePath());
properties.setProperty("test.targetdir",MavenTestingUtils.getTargetDir().getAbsolutePath());
properties.setProperty("test.workdir",workishDir.getAbsolutePath());
// Write out configuration for use by ConfigurationManager.
File testConfig = new File(_jettyHome, "xml-configured-jetty.properties");
try (OutputStream out = new FileOutputStream(testConfig))
{
properties.store(out,"Generated by " + XmlConfiguredJetty.class.getName());
}
for (Object key:properties.keySet())
setProperty(String.valueOf(key),String.valueOf(properties.get(key)));
}
public void addConfiguration(File xmlConfigFile) throws MalformedURLException
{
addConfiguration(Resource.toURL(xmlConfigFile));
}
public void addConfiguration(String testConfigName) throws MalformedURLException
{
addConfiguration(MavenTestingUtils.getTestResourceFile(testConfigName));
}
public void addConfiguration(URL xmlConfig)
{
_xmlConfigurations.add(xmlConfig);
}
public void assertNoWebAppContexts()
{
List<WebAppContext> contexts = getWebAppContexts();
if (contexts.size() > 0)
{
for (WebAppContext context : contexts)
{
System.err.println("WebAppContext should not exist:\n" + context);
}
Assert.assertEquals("Contexts.size",0,contexts.size());
}
}
public String getResponse(String path) throws IOException
{
URI destUri = getServerURI().resolve(path);
URL url = destUri.toURL();
URLConnection conn = url.openConnection();
InputStream in = null;
try
{
in = conn.getInputStream();
return IO.toString(in);
}
finally
{
IO.close(in);
}
}
public void assertResponseContains(String path, String needle) throws IOException
{
// System.err.println("Issuing request to " + path);
String content = getResponse(path);
Assert.assertTrue("Content should contain <" + needle + ">, instead got <" + content + ">",content.contains(needle));
}
public void assertWebAppContextsExists(String... expectedContextPaths)
{
List<WebAppContext> contexts = getWebAppContexts();
if (expectedContextPaths.length != contexts.size())
{
System.err.println("## Expected Contexts");
for (String expected : expectedContextPaths)
{
System.err.println(expected);
}
System.err.println("## Actual Contexts");
for (WebAppContext context : contexts)
{
System.err.printf("%s ## %s%n",context.getContextPath(),context);
}
Assert.assertEquals("Contexts.size",expectedContextPaths.length,contexts.size());
}
for (String expectedPath : expectedContextPaths)
{
boolean found = false;
for (WebAppContext context : contexts)
{
if (context.getContextPath().equals(expectedPath))
{
found = true;
Assert.assertThat("Context[" + context.getContextPath() + "].state", context.getState(), is("STARTED"));
break;
}
}
Assert.assertTrue("Did not find Expected Context Path " + expectedPath,found);
}
}
private void copyFile(String type, File srcFile, File destFile) throws IOException
{
PathAssert.assertFileExists(type + " File",srcFile);
IO.copyFile(srcFile,destFile);
PathAssert.assertFileExists(type + " File",destFile);
System.err.printf("Copy %s: %s%n To %s: %s%n",type,srcFile,type,destFile);
System.err.printf("Destination Exists: %s - %s%n",destFile.exists(),destFile);
}
public void copyWebapp(String srcName, String destName) throws IOException
{
System.err.printf("Copying Webapp: %s -> %s%n",srcName,destName);
File srcDir = MavenTestingUtils.getTestResourceDir("webapps");
File destDir = new File(_jettyHome,"webapps");
File srcFile = new File(srcDir,srcName);
File destFile = new File(destDir,destName);
copyFile("Webapp",srcFile,destFile);
}
private void deleteContents(File dir)
{
// System.err.printf("Delete (dir) %s/%n",dir);
if (!dir.exists())
{
return;
}
File[] files = dir.listFiles();
if (files != null)
{
for (File file : files)
{
// Safety measure. only recursively delete within target directory.
if (file.isDirectory() && file.getAbsolutePath().contains("target" + File.separator))
{
deleteContents(file);
Assert.assertTrue("Delete failed: " + file.getAbsolutePath(),file.delete());
}
else
{
System.err.printf("Delete (file) %s%n",file);
Assert.assertTrue("Delete failed: " + file.getAbsolutePath(),file.delete());
}
}
}
}
public File getJettyDir(String name)
{
return new File(_jettyHome,name);
}
public File getJettyHome()
{
return _jettyHome;
}
public String getScheme()
{
return _scheme;
}
public Server getServer()
{
return _server;
}
public int getServerPort()
{
return _serverPort;
}
public URI getServerURI() throws UnknownHostException
{
StringBuilder uri = new StringBuilder();
URIUtil.appendSchemeHostPort(uri, getScheme(), InetAddress.getLocalHost().getHostAddress(), getServerPort());
return URI.create(uri.toString());
}
public List<WebAppContext> getWebAppContexts()
{
List<WebAppContext> contexts = new ArrayList<>();
HandlerCollection handlers = (HandlerCollection)_server.getHandler();
Handler children[] = handlers.getChildHandlers();
for (Handler handler : children)
{
if (handler instanceof WebAppContext)
{
WebAppContext context = (WebAppContext)handler;
contexts.add(context);
}
}
return contexts;
}
public void load() throws Exception
{
XmlConfiguration last = null;
Object[] obj = new Object[this._xmlConfigurations.size()];
// Configure everything
for (int i = 0; i < this._xmlConfigurations.size(); i++)
{
URL configURL = this._xmlConfigurations.get(i);
XmlConfiguration configuration = new XmlConfiguration(configURL);
if (last != null)
configuration.getIdMap().putAll(last.getIdMap());
configuration.getProperties().putAll(_properties);
obj[i] = configuration.configure();
last = configuration;
}
// Test for Server Instance.
Server foundServer = null;
int serverCount = 0;
for (int i = 0; i < this._xmlConfigurations.size(); i++)
{
if (obj[i] instanceof Server)
{
if (obj[i].equals(foundServer))
{
// Identical server instance found
break;
}
foundServer = (Server)obj[i];
serverCount++;
}
}
if (serverCount <= 0)
{
throw new Exception("Load failed to configure a " + Server.class.getName());
}
Assert.assertEquals("Server load count",1,serverCount);
this._server = foundServer;
this._server.setStopTimeout(10);
}
public void removeWebapp(String name)
{
File destDir = new File(_jettyHome,"webapps");
File contextFile = new File(destDir,name);
if (contextFile.exists())
{
Assert.assertTrue("Delete of Webapp file: " + contextFile.getAbsolutePath(),contextFile.delete());
}
}
public void setProperty(String key, String value)
{
_properties.put(key,value);
}
public void setScheme(String scheme)
{
this._scheme = scheme;
}
public void start() throws Exception
{
Assert.assertNotNull("Server should not be null (failed load?)",_server);
_server.start();
// Find the active server port.
_serverPort = -1;
Connector connectors[] = _server.getConnectors();
for (int i = 0; _serverPort<0 && i < connectors.length; i++)
{
if (connectors[i] instanceof NetworkConnector)
{
int port = ((NetworkConnector)connectors[i]).getLocalPort();
if (port>0)
_serverPort=port;
}
}
Assert.assertTrue("Server Port is between 1 and 65535. Actually <" + _serverPort + ">",(1 <= this._serverPort) && (this._serverPort <= 65535));
// Uncomment to have server start and continue to run (without exiting)
// System.err.printf("Listening to port %d%n",this.serverPort);
// server.join();
}
public void stop() throws Exception
{
_server.stop();
}
}