package jp.vmi.junit.result;
import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jp.vmi.selenium.selenese.utils.CommandLineUtils;
import static jp.vmi.junit.result.ObjectFactory.*;
/**
* Record and output test-suite & test-case results.
* <p>
* It expected that this is parsed by Jenkins.
* </p>
* @see <a href="https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/hudson/tasks/junit/SuiteResult.java">Jenkins SuiteResult class.</a>
* @see <a href="https://github.com/jenkinsci/jenkins/blob/master/core/src/main/java/hudson/tasks/junit/CaseResult.java">Jenkins CaseResult class.</a>
*/
public final class JUnitResult {
private static final Logger log = LoggerFactory.getLogger(JUnitResult.class);
/** filename of failsafe-summary. */
public static final String FAILSAFE_SUMMARY_FILENAME = "failsafe-summary.xml";
private static final String[] PROP_NAMES = {
"java.vm.name",
"java.version",
"os.name",
"os.version",
"os.arch",
"user.language",
"user.country",
"user.timezone",
};
private String[] commandLineArgs = null;
private String xmlResultDir = null;
private final JAXBContext context = initContext();
private final Map<Object, TestResult<?>> map = new ConcurrentHashMap<>();
private final FailsafeSummary failsafeSummary = factory.createFailsafeSummary();
private JAXBContext initContext() {
try {
return JAXBContext.newInstance(ObjectFactory.class);
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
/**
* Set command line arguments.
*
* @param args command line arguments.
*/
public void setCommandLineArgs(String[] args) {
commandLineArgs = args;
}
/**
* Set XML result directory.
*
* @param dir XML result directory.
*/
public void setDir(String dir) {
this.xmlResultDir = dir;
}
protected void mkdirs() {
File dir = new File(xmlResultDir);
if (!dir.exists()) {
dir.mkdirs();
log.info("Make the directory for XML result: {}", dir);
}
}
/**
* Start test-suite.
*
* @param testSuite test-suite instance.
*/
public void startTestSuite(ITestSuite testSuite) {
TestSuiteResult suiteResult = factory.createTestSuiteResult(testSuite);
for (String propName : PROP_NAMES)
suiteResult.addProperty(propName, System.getProperty(propName, "<UNKNOWN>"));
if (commandLineArgs != null)
suiteResult.addProperty("seleneseRunner.args", CommandLineUtils.espaceCommandLineArgs(commandLineArgs));
map.put(testSuite, suiteResult);
}
/**
* End test-suite.
*
* @param testSuite test-suite instatnce.
*/
public void endTestSuite(ITestSuite testSuite) {
TestSuiteResult suiteResult = (TestSuiteResult) map.remove(testSuite);
if (xmlResultDir == null || suiteResult.getTests() == 0)
return;
try {
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
//marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
mkdirs();
File file = new File(xmlResultDir, "TEST-" + suiteResult.getBaseName() + ".xml");
marshaller.marshal(suiteResult, file);
log.info("Generated JUnit result: {}", file);
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
/**
* Add property in test-suite.
*
* @param testSuite test-suite instatnce.
* @param name property name.
* @param value property value.
*/
public void addProperty(ITestSuite testSuite, String name, String value) {
TestSuiteResult suiteResult = (TestSuiteResult) map.get(testSuite);
suiteResult.addProperty(name, value);
}
/**
* Start test-case.
* @param testTarget test-suite or test-case instance.
* @param testCase test-case instance.
*/
public void startTestCase(ITestTarget testTarget, ITestCase testCase) {
TestCaseResult caseResult = factory.createTestCaseResult(testCase);
map.put(testCase, caseResult);
if (testTarget != null && testTarget instanceof ITestSuite) {
TestSuiteResult suiteResult = (TestSuiteResult) map.get(testTarget);
suiteResult.addTestCaseResult(caseResult);
}
}
/**
* End test-case.
*
* @param testCase test-case instance.
*/
public void endTestCase(ITestCase testCase) {
TestCaseResult caseResult = (TestCaseResult) map.remove(testCase);
failsafeSummary.skipped += caseResult.getSkipped();
}
/**
* Set success.
*
* @param testCase test-case instance.
*/
public void setSuccess(ITestCase testCase) {
TestCaseResult caseResult = (TestCaseResult) map.get(testCase);
caseResult.setSuccess();
failsafeSummary.completed++;
}
/**
* Set error in test-case.
*
* @param testCase test-case instance.
* @param message error message.
* @param trace error trace.
*/
public void setError(ITestCase testCase, String message, String trace) {
TestCaseResult caseResult = (TestCaseResult) map.get(testCase);
caseResult.setError(message, trace);
failsafeSummary.completed++;
failsafeSummary.errors++;
}
/**
* Set failure in test-case.
*
* @param testCase test-case instance.
* @param message error message.
* @param trace error trace.
*/
public void setFailure(ITestCase testCase, String message, String trace) {
TestCaseResult caseResult = (TestCaseResult) map.get(testCase);
caseResult.setFailure(message, trace);
failsafeSummary.completed++;
failsafeSummary.failures++;
}
/**
* Generate "failsafe-summary.xml" into XML result directory.
*/
public void generateFailsafeSummary() {
if (xmlResultDir == null)
return;
try {
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
mkdirs();
File file = new File(xmlResultDir, FAILSAFE_SUMMARY_FILENAME);
marshaller.marshal(failsafeSummary, file);
log.info("Generated failsafe summary: {}", file);
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
}