package com.canoo.webtest.extension;
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
import org.w3c.dom.Attr;
import com.canoo.webtest.engine.Context;
import com.canoo.webtest.engine.StepFailedException;
import com.canoo.webtest.steps.Step;
import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
/**
* Selects attributes with an xpath and downloads them.
*
* @author Denis N. Antonioli
* @webtest.step
* category="Extension"
* name="verifyLinkedContent"
* description="Verify all selected links on a page for existence and, optionally, mime-type."
*/
public class VerifyLinkedContent extends Step {
private static final Logger LOG = Logger.getLogger(VerifyLinkedContent.class);
private String fXpath;
private String fAccept;
private MimeType fMimeTypes;
public static final String LINE_SEPARATOR;
static {
LINE_SEPARATOR = System.getProperty("line.separator");
}
{
fMimeTypes = MimeType.ALL_MEDIA;
}
protected void verifyParameters() {
nullResponseCheck();
nullParamCheck(getXpath(), "xpath");
if (getAccept() != null) {
fMimeTypes = new MimeType(getAccept());
}
}
/**
* Selects the resources to check.
* @param xpath The links to check.
* @webtest.parameter
* required="yes"
* description="The links to checks"
*/
public void setXpath(final String xpath) {
fXpath = xpath;
}
public String getXpath() {
return fXpath;
}
/**
* See description of the Accept header in RFC 2616.
*
* @param accept The accepted mimetype(s).
* @webtest.parameter
* required="no"
* default="Accepts anything."
* description="Type and subtype that the answer must have, in the classical mime-type notation."
*/
public void setAccept(final String accept) {
fAccept = accept;
}
public String getAccept() {
return fAccept;
}
public void doExecute() throws Exception {
final Context context = getContext();
final HtmlPage currentResponse;
try {
currentResponse = (HtmlPage) context.getCurrentResponse();
} catch (ClassCastException cce) {
throw new StepFailedException("Current response is not an html page but " + context.getCurrentResponse().getClass(), this);
}
final StringBuffer sb = verifyLinksOnPage(currentResponse);
if (sb.length() > 0) {
sb.insert(0, currentResponse.getUrl().toExternalForm() + ":" + LINE_SEPARATOR);
throw new StepFailedException(sb.toString(), this);
}
}
WebClient setupWebClient() {
final WebClient webClient = getContext().getConfig().createWebClient();
webClient.setThrowExceptionOnFailingStatusCode(true);
webClient.setWebConnection(getContext().getWebClient().getWebConnection());
return webClient;
}
StringBuffer verifyLinksOnPage(final HtmlPage htmlPage) throws Exception {
final WebClient webClient = setupWebClient();
final StringBuffer sb = new StringBuffer();
for (final Iterator it = iterateAllMatchingElements(htmlPage).iterator(); it.hasNext();) {
sb.append(verifyOneLink(webClient, htmlPage, (Attr) it.next()));
}
return sb;
}
String verifyOneLink(final WebClient webClient, final HtmlPage htmlPage, final Attr linkAttribute) throws IOException {
final String key = (String) linkAttribute.getLocalName();
final String src = (String) linkAttribute.getValue();
final URL url = htmlPage.getFullyQualifiedUrl(src);
LOG.debug(src + " -> " + url.toExternalForm());
try {
final Page resp = webClient.getPage(url);
final String contentType = resp.getWebResponse().getContentType();
if (!fMimeTypes.match(contentType)) {
final StringBuffer sb = new StringBuffer();
sb.append(src).append(" <").append(url.toExternalForm()).append("> ");
sb.append(contentType).append(" is not expected").append(LINE_SEPARATOR);
LOG.info("Failed link with " + key + "=\"" + src + "\", mime-type is " + contentType);
return sb.toString();
}
}
catch (final FailingHttpStatusCodeException fhsce) {
StringBuffer sb = new StringBuffer();
sb.append(src).append(" <").append(url.toExternalForm()).append("> ");
sb.append(fhsce.getStatusCode()).append(" ").append(fhsce.getMessage()).append(LINE_SEPARATOR);
LOG.info("Failed link with " + key + "=\"" + src + "\", code is " + fhsce.getStatusCode());
return sb.toString();
}
LOG.debug("Link with " + key + "=\"" + src + "\" is ok");
return "";
}
List iterateAllMatchingElements(final HtmlPage htmlPage) throws Exception {
try {
return getContext().getXPathHelper().selectNodes(htmlPage, getXpath());
} catch (final Exception e) {
LOG.error(e.getMessage(), e);
throw e;
}
}
public boolean isPerformingAction() {
return false;
}
}