blob: 14cad800616de73af56d9b5c1a3896180164e2a3 [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.felix.ipojo.junit4osgi.plugin;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import junit.framework.Test;
import junit.framework.TestResult;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.codehaus.plexus.util.xml.Xpp3DomWriter;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
/**
* This class generates test result as XML files compatible with Surefire.
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class XMLReport extends Report {
/**
* List of results.
*/
private List m_results = new ArrayList();
/**
* A test ends successfully.
* @param test the test executed successfully.
*/
public void testSucceeded(Test test) {
super.testSucceeded();
long runTime = this.m_endTime - this.m_startTime;
Xpp3Dom testCase = createTestElement(test, runTime);
m_results.add(testCase);
}
/**
* A test throws an unexpected errors.
* @param test the test in error
* @param e the thrown exception
* @param out the output messages printed during the test execution
* @param err the error messages printed during the test execution
* @param log the messages logged during the test execution
*/
public void testError(Test test, Throwable e, String out, String err, String log) {
super.testError(test);
writeTestProblems(test, e, "error", out, err, log);
}
/**
* A test fails.
* @param test the failing test
* @param e the thrown failure
* @param out the output messages printed during the test execution
* @param err the error messages printed during the test execution
* @param log the messages logged during the test execution
*/
public void testFailed(Test test, Throwable e, String out, String err, String log) {
super.testFailed(test);
writeTestProblems(test, e, "failure", out, err, log);
}
/**
* Utility method writing failed and in error test result in the report.
* @param test the test
* @param e the thrown error
* @param name type of failure ("error" or "failure")
* @param out the output messages printed during the test execution
* @param err the error messages printed during the test execution
* @param log the messages logged during the test execution
*/
private void writeTestProblems(Test test, Throwable e, String name, String out, String err, String log) {
long runTime = m_endTime - m_startTime;
Xpp3Dom testCase = createTestElement(test, runTime);
Xpp3Dom element = createElement(testCase, name);
String stackTrace = getStackTrace(test, e);
Throwable t = e;
if (t != null) {
String message = t.getMessage();
if (message != null) {
element.setAttribute("message", message);
element.setAttribute("type",
stackTrace.indexOf(":") > -1 ? stackTrace.substring(0,
stackTrace.indexOf(":")) : stackTrace);
} else {
element.setAttribute("type", new StringTokenizer(stackTrace)
.nextToken());
}
}
if (stackTrace != null) {
element.setValue(stackTrace);
}
addOutputStreamElement(out, "system-out", testCase);
addOutputStreamElement(err, "system-err", testCase);
if (log != null) {
addOutputStreamElement(log, "log-service", testCase);
}
m_results.add(testCase);
}
/**
* Generates the XML reports.
* @param test the test
* @param tr the test result
* @param reportsDirectory the directory in which reports are created.
* @param bc the bundle context (to get installed bundles)
* @param configuration the Felix configuration
* @throws Exception when the XML report cannot be generated correctly
*/
public void generateReport(Test test, TestResult tr, File reportsDirectory,
BundleContext bc, Map configuration) throws Exception {
long runTime = this.m_endTime - this.m_startTime;
Xpp3Dom testSuite = createTestSuiteElement(test, runTime);
showProperties(testSuite, bc, configuration);
testSuite.setAttribute("tests", String.valueOf(tr.runCount()));
testSuite.setAttribute("errors", String.valueOf(tr.errorCount()));
testSuite.setAttribute("failures", String.valueOf(tr.failureCount()));
for (Iterator i = m_results.iterator(); i.hasNext();) {
Xpp3Dom testcase = (Xpp3Dom) i.next();
testSuite.addChild(testcase);
}
File reportFile = new File(reportsDirectory, "TEST-"
+ getReportName(test).replace(' ', '_') + ".xml");
File reportDir = reportFile.getParentFile();
reportDir.mkdirs();
PrintWriter writer = null;
try {
writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(reportFile), "UTF-8")));
writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>" + NL);
Xpp3DomWriter.write(new PrettyPrintXMLWriter(writer), testSuite);
} catch (UnsupportedEncodingException e) {
throw new Exception("Unable to use UTF-8 encoding", e);
} catch (FileNotFoundException e) {
throw new Exception("Unable to create file: " + e.getMessage(), e);
} finally {
IOUtil.close(writer);
}
}
/**
* Creates a XML test case element.
* @param test the test
* @param runTime the elapsed time to execute the test.
* @return the XML element describing the given test.
*/
private Xpp3Dom createTestElement(Test test, long runTime) {
Xpp3Dom testCase = new Xpp3Dom("testcase");
testCase.setAttribute("name", getReportName(test));
testCase.setAttribute("time", Long.toString(runTime) + " sec");
return testCase;
}
/**
* Creates a XML test suite element.
* @param test the test
* @param runTime the elapsed time to execute the test suite.
* @return the XML element describing the given test suite.
*/
private Xpp3Dom createTestSuiteElement(Test test, long runTime) {
Xpp3Dom testCase = new Xpp3Dom("testsuite");
testCase.setAttribute("name", getReportName(test));
testCase.setAttribute("time", Long.toString(runTime) + " sec");
return testCase;
}
/**
* Computes report name.
* @param test the test
* @return the report name
*/
private static String getReportName(Test test) {
String report = test.toString();
if (report.indexOf("(") > 0) {
report = report.substring(0, report.indexOf("("));
}
return report;
}
/**
* Creates an XML element.
* @param element the parent element
* @param name the name of the element to create
* @return the resulting XML tree.
*/
private Xpp3Dom createElement(Xpp3Dom element, String name) {
Xpp3Dom component = new Xpp3Dom(name);
element.addChild(component);
return component;
}
/**
* Adds system properties to the XML report.
* This method also adds installed bundles.
* @param testSuite the XML element.
* @param bc the bundle context
* @param configuration the configuration of the underlying OSGi platform
*/
private void showProperties(Xpp3Dom testSuite, BundleContext bc, Map configuration) {
Xpp3Dom properties = createElement(testSuite, "properties");
Properties systemProperties = System.getProperties();
if (systemProperties != null) {
Enumeration propertyKeys = systemProperties.propertyNames();
while (propertyKeys.hasMoreElements()) {
String key = (String) propertyKeys.nextElement();
String value = systemProperties.getProperty(key);
if (value == null) {
value = "null";
}
Xpp3Dom property = createElement(properties, "property");
property.setAttribute("name", key);
property.setAttribute("value", value);
}
}
if (configuration != null) {
Iterator it = configuration.keySet().iterator();
while (it.hasNext()) {
String key = (String) it.next();
Object obj = (Object) configuration.get(key);
String value = null;
if (obj == null) {
value = "null";
} else if (obj instanceof String) {
value = (String) obj;
} else {
value = obj.toString();
}
Xpp3Dom property = createElement(properties, "property");
property.setAttribute("name", key);
property.setAttribute("value", value);
}
}
Xpp3Dom buns = createElement(properties, "bundles");
Bundle[] bundles = bc.getBundles();
for (int i = 0; i < bundles.length; i++) {
String sn = bundles[i].getSymbolicName();
String state = "UNKNOWN";
switch (bundles[i].getState()) {
case Bundle.ACTIVE:
state = "ACTIVE";
break;
case Bundle.INSTALLED:
state = "INSTALLED";
break;
case Bundle.RESOLVED:
state = "RESOLVED";
break;
case Bundle.UNINSTALLED:
state = "UNINSTALLED";
break;
default:
break;
}
Xpp3Dom bundle = createElement(buns, "bundle");
bundle.setAttribute("symbolic-name", sn);
bundle.setAttribute("state", state);
}
}
/**
* Adds messages written during the test execution in the
* XML tree.
* @param stdOut the messages
* @param name the name of the stream (out, error, log)
* @param testCase the XML tree
*/
private void addOutputStreamElement(String stdOut, String name,
Xpp3Dom testCase) {
if (stdOut != null && stdOut.trim().length() > 0) {
createElement(testCase, name).setValue(stdOut);
}
}
}