]> source.dussan.org Git - sonarqube.git/blob
a144431af8cbe7c4e44a0b07a14232e822e77604
[sonarqube.git] /
1 package org.sonar.plugins.surefire.api;
2
3 import org.apache.commons.lang.StringEscapeUtils;
4 import org.apache.commons.lang.StringUtils;
5 import org.sonar.api.batch.SensorContext;
6 import org.sonar.api.measures.CoreMetrics;
7 import org.sonar.api.measures.Measure;
8 import org.sonar.api.measures.Metric;
9 import org.sonar.api.resources.Project;
10 import org.sonar.api.resources.Resource;
11 import org.sonar.api.utils.ParsingUtils;
12 import org.sonar.api.utils.StaxParser;
13 import org.sonar.api.utils.XmlParserException;
14 import org.sonar.plugins.surefire.TestCaseDetails;
15 import org.sonar.plugins.surefire.TestSuiteParser;
16 import org.sonar.plugins.surefire.TestSuiteReport;
17
18 import java.io.File;
19 import java.io.FilenameFilter;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Set;
23
24 import javax.xml.transform.TransformerException;
25
26 /**
27  * @since 2.4
28  */
29 public abstract class AbstractSurefireParser {
30
31   public void collect(Project project, SensorContext context, File reportsDir) {
32     File[] xmlFiles = getReports(reportsDir);
33
34     if (xmlFiles.length == 0) {
35       insertZeroWhenNoReports(project, context);
36     } else {
37       parseFiles(context, xmlFiles);
38     }
39   }
40
41   private File[] getReports(File dir) {
42     if (dir == null || !dir.isDirectory() || !dir.exists()) {
43       return new File[0];
44     }
45     return dir.listFiles(new FilenameFilter() {
46       public boolean accept(File dir, String name) {
47         return name.startsWith("TEST") && name.endsWith(".xml");
48       }
49     });
50   }
51
52   private void insertZeroWhenNoReports(Project pom, SensorContext context) {
53     if ( !StringUtils.equalsIgnoreCase("pom", pom.getPackaging())) {
54       context.saveMeasure(CoreMetrics.TESTS, 0.0);
55     }
56   }
57
58   private void parseFiles(SensorContext context, File[] reports) {
59     Set<TestSuiteReport> analyzedReports = new HashSet<TestSuiteReport>();
60     try {
61       for (File report : reports) {
62         TestSuiteParser parserHandler = new TestSuiteParser();
63         StaxParser parser = new StaxParser(parserHandler, false);
64         parser.parse(report);
65
66         for (TestSuiteReport fileReport : parserHandler.getParsedReports()) {
67           if ( !fileReport.isValid() || analyzedReports.contains(fileReport)) {
68             continue;
69           }
70           if (fileReport.getTests() > 0) {
71             double testsCount = fileReport.getTests() - fileReport.getSkipped();
72             saveClassMeasure(context, fileReport, CoreMetrics.SKIPPED_TESTS, fileReport.getSkipped());
73             saveClassMeasure(context, fileReport, CoreMetrics.TESTS, testsCount);
74             saveClassMeasure(context, fileReport, CoreMetrics.TEST_ERRORS, fileReport.getErrors());
75             saveClassMeasure(context, fileReport, CoreMetrics.TEST_FAILURES, fileReport.getFailures());
76             saveClassMeasure(context, fileReport, CoreMetrics.TEST_EXECUTION_TIME, fileReport.getTimeMS());
77             double passedTests = testsCount - fileReport.getErrors() - fileReport.getFailures();
78             if (testsCount > 0) {
79               double percentage = passedTests * 100d / testsCount;
80               saveClassMeasure(context, fileReport, CoreMetrics.TEST_SUCCESS_DENSITY, ParsingUtils.scaleValue(percentage));
81             }
82             saveTestsDetails(context, fileReport);
83             analyzedReports.add(fileReport);
84           }
85         }
86       }
87
88     } catch (Exception e) {
89       throw new XmlParserException("Can not parse surefire reports", e);
90     }
91   }
92
93   private void saveTestsDetails(SensorContext context, TestSuiteReport fileReport) throws TransformerException {
94     StringBuilder testCaseDetails = new StringBuilder(256);
95     testCaseDetails.append("<tests-details>");
96     List<TestCaseDetails> details = fileReport.getDetails();
97     for (TestCaseDetails detail : details) {
98       testCaseDetails.append("<testcase status=\"").append(detail.getStatus())
99           .append("\" time=\"").append(detail.getTimeMS())
100           .append("\" name=\"").append(detail.getName()).append("\"");
101       boolean isError = detail.getStatus().equals(TestCaseDetails.STATUS_ERROR);
102       if (isError || detail.getStatus().equals(TestCaseDetails.STATUS_FAILURE)) {
103         testCaseDetails.append(">")
104             .append(isError ? "<error message=\"" : "<failure message=\"")
105             .append(StringEscapeUtils.escapeXml(detail.getErrorMessage())).append("\">")
106             .append("<![CDATA[").append(StringEscapeUtils.escapeXml(detail.getStackTrace())).append("]]>")
107             .append(isError ? "</error>" : "</failure>").append("</testcase>");
108       } else {
109         testCaseDetails.append("/>");
110       }
111     }
112     testCaseDetails.append("</tests-details>");
113     context.saveMeasure(getUnitTestResource(fileReport.getClassKey()), new Measure(CoreMetrics.TEST_DATA, testCaseDetails.toString()));
114   }
115
116   private void saveClassMeasure(SensorContext context, TestSuiteReport fileReport, Metric metric, double value) {
117     if ( !Double.isNaN(value)) {
118       context.saveMeasure(getUnitTestResource(fileReport.getClassKey()), metric, value);
119     }
120   }
121
122   protected abstract Resource<?> getUnitTestResource(String classKey);
123
124 }