Package com.canoo.webtest.reporting

Source Code of com.canoo.webtest.reporting.XmlResultConverter

// Copyright � 2002-2007 Canoo Engineering AG, Switzerland.
package com.canoo.webtest.reporting;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.lang.StringUtils;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Location;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.canoo.webtest.boundary.PackageBoundary;
import com.canoo.webtest.engine.NameValuePair;
import com.canoo.webtest.engine.WebTestException;
import com.canoo.webtest.steps.HtmlParserMessage;

/**
* The class converts a given {@link com.canoo.webtest.reporting.StepResult} into its XML representation.
* It is used to decouple report file handling ({@link XmlReporter}) and report content generation (this class).
*
* @author Marc Guillemot
*/
public class XmlResultConverter {

    // Constants for all used XML elements
    public static final String ROOT_ELEMENT = "summary";
    public static final String TESTRESULT_ELEMENT = "testresult";
    public static final String RESULTS_ELEMENT = "results";
    public static final String CONFIG_ELEMENT = "config";
    public static final String PARAMETER_ELEMENT = "parameter";
    public static final String STEP_ELEMENT = "step";
    public static final String FAILURE_ELEMENT = "failure";
    public static final String ERROR_ELEMENT = "error";
    public static final String STEP_RESULT_ATTRIBUTE = "result";
    public static final String STEP_COMPLETED_ELEMENT = "completed";
    public static final String STEP_FAILED_ELEMENT = "failed";
    public static final String STEP_NOTEXECUTED_ELEMENT = "notexecuted";

    private RootStepResult fResult;

    public XmlResultConverter(final RootStepResult result) {
        fResult = result;
    }

    /**
     * This method actually adds the XML representation of the test result
     * to the provided XML document. If the document is new (empty), it
     * creates the required root element. Then it appends a new
     * child to the root containing this result representation.
     *
     * @param doc An XML document into which the report for the current
     *            test result shall be added
     * @throws ReportCreationException Signals an inconsistency in the
     *                                 XML document
     */
    public void addToDocument(final Document doc) throws ReportCreationException {
        final NodeList nodeList = doc.getElementsByTagName(ROOT_ELEMENT);
        final Element rootElement;
        if (nodeList.getLength() == 0) {
            if (doc.getChildNodes().getLength() > 0) {
                throw new ReportCreationException("Another root already exists!");
            }
            rootElement = doc.createElement(ROOT_ELEMENT);
            doc.appendChild(rootElement);
            addSummaryAttribute(rootElement);
        } else {
            rootElement = (Element) nodeList.item(0);
        }
        final Element testResult = addNewElement(rootElement, TESTRESULT_ELEMENT);
        addResultAttributes(testResult);
        final String description = fResult.getWebtestDescription();
        if (!StringUtils.isEmpty(description)) {
            final Element descriptionElt = addNewElement(testResult, "description");
            addText(descriptionElt, description); // as node with text because extensions will come
        }
        addConfig(testResult);
        addResults(testResult);
    }

    private void addSummaryAttribute(final Element rootElement) {
        addNewAttribute(rootElement, "Implementation-Title",
            PackageBoundary.getImplementationTitle());
        addNewAttribute(rootElement, "Implementation-Version",
            PackageBoundary.getImplementationVersion());
    }

    private void addResults(final Element parent) {
        final Element resultsElement = addNewElement(parent, RESULTS_ELEMENT);

        addSteps(resultsElement, fResult.getChildren());
        addFailureIfNeeded(resultsElement);
        addErrorIfNeeded(resultsElement);
    }

    private void addErrorIfNeeded(final Element parent) {
        if (fResult.isError()) {
            final Element errorElement = addNewElement(parent, ERROR_ELEMENT);
            final Throwable error = fResult.getException();
            addNewAttribute(errorElement, "exception", error.getClass().getName());
            addFailureDetails(errorElement);
           
            // stacktrace
            final Element stackTrace = addNewElement(errorElement, "stacktrace");
            final StringWriter s = new StringWriter();
            error.printStackTrace(new PrintWriter(s));
            addText(stackTrace, s.toString());
        }
    }

    private void addFailureIfNeeded(final Element parent) {
        if (fResult.isFailure()) {
            final Element failureElement = addNewElement(parent, FAILURE_ELEMENT);
            addFailureDetails(failureElement);
        }
    }
   
    private void addFailureDetails(final Element failure)
    {
        final Throwable throwable = fResult.getException();

        final List locations = new ArrayList();
        Throwable rootCause = throwable;
        Throwable ex = throwable;
        while (ex != null)
        {
          rootCause = ex;
          if (rootCause instanceof BuildException)
            locations.add(((BuildException) rootCause).getLocation());
          ex = ex.getCause();
        }

        if (!locations.isEmpty())
        {
          // call stack of ant calls (if any)
        final Element antCallStack = addNewElement(failure, "antStack");
        for (int i=locations.size()-1; i>=0; --i)
        {
          final Location loc = (Location) locations.get(i);
          final Element antCall = addNewElement(antCallStack, "call");
          antCall.setAttribute("filename", loc.getFileName());
          antCall.setAttribute("line", String.valueOf(loc.getLineNumber()));
        }
        }
        if (rootCause instanceof WebTestException)
        {
          final WebTestException e = (WebTestException) rootCause;

          addNewAttribute(failure, "message", e.getShortMessage());

            for (final Iterator iter = e.getDetails().iterator(); iter.hasNext();) {
        final NameValuePair detail = (NameValuePair) iter.next();
              final Element detailElt = addNewElement(failure, "detail");
              addNewAttribute(detailElt, "name", detail.getName());
              addText(detailElt, detail.getValue());
      }
        }
        else
        {
            addNewAttribute(failure, "message", throwable.getMessage());
        }
    }

    private void addSteps(final Element parent, final List steps) {
        for (final Iterator iter = steps.iterator(); iter.hasNext();) {
            addSingleTask(parent, (StepResult) iter.next());
        }
    }


    private void addSingleTask(final Element parent, final StepResult stepResult)
    {
        final Element stepElement = addNewElement(parent, STEP_ELEMENT);
        stepElement.setAttribute("taskName", stepResult.getTaskName());
        if (stepResult.getTaskDescription() != null) {
          stepElement.setAttribute("description", stepResult.getTaskDescription());
        }

        addStepResult(stepElement, stepResult);

        final Map attributes = new TreeMap(stepResult.getAttributes());

        attributes.remove("description");
        final String resultFile = (String) attributes.remove("resultFilename");
        addParameters(stepElement, attributes); // add attributes bevor resultFile
        if (resultFile != null)
        {
            final Element resultFileElement = addNewElement(stepElement, "resultFile");
            resultFileElement.setAttribute("name", resultFile);
        }

        // html errors and warnings
        if (!stepResult.getHtmlParserMessages().isEmpty()) {
            final Element htmlParser = addNewElement(stepElement, "htmlparser");
            addParserMessages(htmlParser, stepResult.getHtmlParserMessages());
        }
        addSteps(stepElement, stepResult.getChildren());
    }

    /**
     * creates the subnodes for the parser messages
     *
     * @param htmlParser the parent node
     * @param messages   the list of {@link HtmlParserMessage}
     */
    private static void addParserMessages(final Element htmlParser, final List messages) {
        for (Iterator iter = messages.iterator(); iter.hasNext();) {
            final HtmlParserMessage msg = (HtmlParserMessage) iter.next();
            final Element elt = addNewElement(htmlParser,
                msg.getType().toString());
            elt.setAttribute("url", msg.getURL().toString());
            elt.setAttribute("line", String.valueOf(msg.getLine()));
            elt.setAttribute("col", String.valueOf(msg.getColumn()));
            elt.appendChild(htmlParser.getOwnerDocument().createTextNode(msg.getMessage()));
        }
    }

    private static void addStepResult(final Element parent, final StepResult step) {
        final long duration;
        final String result;
        if (step.isCompleted()) {
          result = step.isSuccessful() ? STEP_COMPLETED_ELEMENT : STEP_FAILED_ELEMENT;
            duration = step.getDuration();
        }
        else {
          result = STEP_NOTEXECUTED_ELEMENT;
            duration = 0;
        }
        parent.setAttribute(STEP_RESULT_ATTRIBUTE, result);
        parent.setAttribute("duration", Long.toString(duration));
    }

    private void addConfig(final Element resultElement) {
        final Element configElement = addNewElement(resultElement, CONFIG_ELEMENT);
        addParameters(configElement,
            fResult.getConfig().getParameterDictionary());
    }

    private void addParameters(final Element parent, final Map parameterDictionary)
    {
        for (final Iterator iter = parameterDictionary.entrySet().iterator(); iter.hasNext();)
        {
            final Map.Entry parameter = (Map.Entry) iter.next();
            final Element parameterElement = addNewElement(parent, PARAMETER_ELEMENT);
            addNewAttribute(parameterElement, "name", parameter.getKey().toString());
            final String value = String.valueOf(parameter.getValue());
            addNewAttribute(parameterElement, "value", value);
        }
    }

    /**
     * PRE: there must be at least one user test step.
     * This is asserted in {@link com.canoo.webtest.ant.TestStepSequence#doExecute()}.
     */
    private void addResultAttributes(final Element resultElement) {
        addNewAttribute(resultElement, "testspecname",
            fResult.getWebtestName());
        addNewAttribute(resultElement, "location", fResult.getWebtestLocation().toString());
       
        addNewAttribute(resultElement, "starttime", fResult.getStartDate().toString());
        if (fResult.isCompleted()) {
            addNewAttribute(resultElement, "endtime", fResult.getEndDate().toString());
        }
        addNewAttribute(resultElement, "successful", fResult.isSuccessful() ? "yes" : "no");
    }

    private static void addNewAttribute(final Element parent, final String name, final String value) {
        parent.setAttribute(name, value);
    }

    /**
     * Creates an element with the given name and adds it to the parent
     * @param parent the parent node
     * @param name the name of the element to create
     * @return the newly created element
     */
    private static Element addNewElement(final Node parent, final String name) {
        final Element e = parent.getOwnerDocument().createElement(name);
        parent.appendChild(e);
        return e;
    }

    /**
     * Creates a CDATA section with the provided text and adds it to the parent node
     * @param parent the parent node
     * @param text the text to add
     */
    private static void addText(final Node parent, final String text) {
        parent.appendChild(parent.getOwnerDocument().createCDATASection(text));
    }
}
TOP

Related Classes of com.canoo.webtest.reporting.XmlResultConverter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.