package hudson.plugins.performance.parsers; import hudson.Extension; import hudson.plugins.performance.data.HttpSample; import hudson.plugins.performance.descriptors.PerformanceReportParserDescriptor; import hudson.plugins.performance.reports.PerformanceReport; import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.DataBoundConstructor; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.io.File; import java.util.Date; /** * Parser for JUnit. * * @author Manuel Carrasco */ public class JUnitParser extends AbstractParser { @Extension public static class DescriptorImpl extends PerformanceReportParserDescriptor { @Override public String getDisplayName() { return "JUnit"; } } @DataBoundConstructor public JUnitParser(String glob) { super(glob); } @Override public String getDefaultGlobPattern() { return "**/TEST-*.xml"; } @Override PerformanceReport parse(File reportFile) throws Exception { final SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setValidating(false); factory.setNamespaceAware(false); final SAXParser parser = factory.newSAXParser(); final PerformanceReport report = new PerformanceReport(); report.setReportFileName(reportFile.getName()); parser.parse(reportFile, new DefaultHandler() { private HttpSample currentSample; private int status; @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (("testsuite".equalsIgnoreCase(qName) || "testcase".equalsIgnoreCase(qName)) && status != 0) { report.addSample(currentSample); status = 0; } } /** * JUnit XML format is: tag "testcase" with attributes: "name" and * "time". If there is one error, there is an other tag, "failure" * inside testcase tag. SOAPUI uses JUnit format */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if ("testcase".equalsIgnoreCase(qName)) { if (status != 0) { report.addSample(currentSample); } status = 1; currentSample = new HttpSample(); currentSample.setDate(new Date(0)); String time = attributes.getValue("time"); currentSample.setDuration(parseDuration(time)); currentSample.setSuccessful(true); currentSample.setUri(attributes.getValue("classname") + "." + attributes.getValue("name")); currentSample.setErrorObtained(false); } else if ("failure".equalsIgnoreCase(qName) && status != 0) { currentSample.setErrorObtained(false); currentSample.setSuccessful(false); report.addSample(currentSample); status = 0; } else if ("error".equalsIgnoreCase(qName) && status != 0) { currentSample.setErrorObtained(true); currentSample.setSuccessful(false); report.addSample(currentSample); status = 0; } } }); return report; } /** * Strips any commas from <code>time</code>, then parses it into a long. */ static long parseDuration(final String time) { if (StringUtils.isEmpty(time)) { return 0; } else { // don't want commas or else will break on parse. final double duration = Double.parseDouble(time.replaceAll(",", "")); return (long) (duration * 1000); } } }