blob: 62a925dc01fb6740952fb0b7a5d15c5a12a519f7 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.SubmitMethod;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.WebRequestSettings;
import com.gargoylesoftware.htmlunit.WebResponse;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.xpath.HtmlUnitXPath;
import com.gargoylesoftware.htmlunit.xml.XmlPage;
import junit.framework.TestCase;
import org.apache.avalon.framework.logger.ConsoleLogger;
import org.apache.avalon.framework.logger.Logger;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.io.FileUtils;
import org.jaxen.SimpleNamespaceContext;
import org.jaxen.XPath;
import org.jaxen.dom.DOMXPath;
import org.w3c.dom.Document;
import java.io.File;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
* Base class to run test cases on Cocoon samples.
* <p>
* This class extends the JUnit TestCase class to setup an environment which
* makes it possible to easily test Cocoon pages.
* First call one of the load methods and then assert on the response object,
* XML document (@see loadXmlPage), or HTML document (@see loadHtmlPage).
* </p>
* <p>
* Examples:
* </p>
* <pre>
* public void testStatus() {
* loadResponse("/samples/test/status");
* assertEquals("Status code", 200, response.getStatusCode());
* }
*
* public void testTitle() {
* loadHtmlPage("/samples/test/title");
* assertXPath("html/head/title"", "The Title");
* }
* </pre>
*
* <p>
* For loading XML and HTML documents currently on GET requests with
* optional querystring are supported. Please add POST requests and
* request parameters when you need them.
* </p>
* @version $Id: $
*/
public abstract class HtmlUnitTestCase
extends TestCase
{
/**
* Logger for informative output by test cases.
* The default log level is WARN but may be changed by setting the
* property junit.test.loglevel to a different numeric value.
*/
protected Logger logger;
/**
* Base URL of the running Cocoon server which is to be tested.
* Set by property htmlunit.test.baseurl usually as http://localhost:8888/.
*/
protected URL baseURL;
/**
* Low-level access to WebClient object.
*/
protected WebClient webClient;
/**
* Low-level access to WebResponse object.
*/
protected WebResponse response;
/**
* Low-level access to XML document (org.w3c.dom.Document) or HTML document
* (com.gargoylesoftware.htmlunit.html.HtmlPage).
*/
protected Object document;
/**
* Low-level access to namespace mappings for XPath expressions.
*/
protected Map namespaces = new HashMap();
/* (non-Javadoc)
* @see junit.framework.TestCase#setUp()
*/
protected void setUp()
throws Exception
{
super.setUp();
String level = System.getProperty("junit.test.loglevel", "" + ConsoleLogger.LEVEL_WARN);
this.logger = new ConsoleLogger(Integer.parseInt(level));
String baseurl = System.getProperty("htmlunit.test.baseurl");
this.baseURL = new URL(baseurl);
this.webClient = new WebClient();
this.webClient.setRedirectEnabled(false);
this.namespaces.clear();
}
/* (non-Javadoc)
* @see junit.framework.TestCase#tearDown()
*/
protected void tearDown()
throws Exception
{
this.response = null;
this.document = null;
super.tearDown();
}
/**
* Sends HTTP GET request and loads response object.
*/
protected void loadResponse(String pageURL)
throws Exception
{
WebRequestSettings webRequestSettings = new WebRequestSettings(new URL(baseURL, pageURL), SubmitMethod.GET);
this.response = webClient.loadWebResponse(webRequestSettings);
}
/**
* Sends HTTP DELETE request and loads response object.
*/
protected void loadDeleteResponse(String pageURL)
throws Exception
{
URL url = new URL(baseURL, pageURL);
DeleteMethod method = new DeleteMethod(url.toExternalForm());
this.response = new HttpClientResponse(url, method);
}
/**
* Sends HTTP PUT request and loads response object.
*/
protected void loadPutResponse(String pageURL, String content)
throws Exception
{
URL url = new URL(baseURL, pageURL);
PutMethod method = new PutMethod(url.toExternalForm());
method.setRequestEntity(new StringRequestEntity(content));
this.response = new HttpClientResponse(url, method);
}
/**
* Sends HTTP request and parses response as HTML document.
*/
protected void loadHtmlPage(String pageURL)
throws Exception
{
URL url = new URL(baseURL, pageURL);
Page page = webClient.getPage(url);
this.response = page.getWebResponse();
assertTrue("Response should be an HTML page", page instanceof HtmlPage);
this.document = page;
assertNotNull("Response contains invalid HTML", this.document);
}
/**
* Sends HTTP request and parses response as XML document.
*/
protected void loadXmlPage(String pageURL)
throws Exception
{
URL url = new URL(baseURL, pageURL);
Page page = webClient.getPage(url);
this.response = page.getWebResponse();
assertTrue("Response should be an XML page", page instanceof XmlPage);
XmlPage xmlPage = (XmlPage)page;
this.document = xmlPage.getXmlDocument();
assertNotNull("Response contains invalid XML", this.document);
}
/**
* Returns XPath expression as string.
*
* @param xpathExpr XPath expression
*
* @return Value of XPath expression in current document.
* Empty string if XPath not matched.
*/
protected String evalXPath(String xpathExpr)
throws Exception
{
XPath xpath = null;
if( document == null )
return null;
else if( document instanceof HtmlPage )
xpath = new HtmlUnitXPath(xpathExpr);
else if( document instanceof Document )
xpath = new DOMXPath(xpathExpr);
else
fail("Document type "+document.getClass().getName());
xpath.setNamespaceContext(new SimpleNamespaceContext(namespaces));
return xpath.stringValueOf(document);
}
/**
* Add a namespace mapping for XPath expressions.
*/
protected void addNamespace(String prefix, String uri)
throws Exception
{
namespaces.put(prefix, uri);
}
/**
* Assert that XPath expression result matches exactly expected value.
*/
protected void assertXPath(String xpathExpr, String expected)
throws Exception
{
assertEquals(xpathExpr, expected, evalXPath(xpathExpr));
}
/**
* Copy file from webapp source to deployment area filtering content
* to replace parameter by value.
* The source and deployment directories are defined by the properties
* htmlunit.test.source-dir and htmlunit.test.deploy-dir.
*
* This method is most useful for testing the automatic reloading of
* changed files.
*/
protected void copyWebappFile(String filename, String param, String value)
throws Exception
{
String srcdir = System.getProperty("htmlunit.test.source-dir");
String dstdir = System.getProperty("htmlunit.test.deploy-dir");
File srcfile = new File(srcdir+"/"+filename);
File dstfile = new File(dstdir+"/"+filename);
final String encoding = "ISO-8859-1";
StringBuffer content = new StringBuffer(FileUtils.readFileToString(srcfile, encoding));
int index = content.indexOf(param);
while( index != -1 ) {
content.replace(index, index+param.length(), value);
index = content.indexOf(param, index+1);
}
FileUtils.writeStringToFile(dstfile, content.toString(), encoding);
// Leave server some time to realize that file has changed.
Thread.sleep(1000);
}
}