]> source.dussan.org Git - sonarqube.git/blob
85e7a2682f841fbbd35cb1d304737dcb8bef48e9
[sonarqube.git] /
1 /*
2  * Sonar, open source software quality management tool.
3  * Copyright (C) 2008-2011 SonarSource
4  * mailto:contact AT sonarsource DOT com
5  *
6  * Sonar is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * Sonar is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with Sonar; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
19  */
20 package org.sonar.plugins.surefire.api;
21
22 import org.apache.commons.lang.StringUtils;
23 import org.sonar.api.batch.SensorContext;
24 import org.sonar.api.measures.CoreMetrics;
25 import org.sonar.api.measures.Measure;
26 import org.sonar.api.measures.Metric;
27 import org.sonar.api.resources.Project;
28 import org.sonar.api.resources.Resource;
29 import org.sonar.api.utils.ParsingUtils;
30 import org.sonar.api.utils.SonarException;
31 import org.sonar.api.utils.StaxParser;
32 import org.sonar.plugins.surefire.data.SurefireStaxHandler;
33 import org.sonar.plugins.surefire.data.UnitTestClassReport;
34 import org.sonar.plugins.surefire.data.UnitTestIndex;
35
36 import java.io.File;
37 import java.io.FilenameFilter;
38 import java.util.Map;
39
40 import javax.xml.stream.XMLStreamException;
41
42 /**
43  * @since 2.4
44  */
45 public abstract class AbstractSurefireParser {
46
47   public void collect(Project project, SensorContext context, File reportsDir) {
48     File[] xmlFiles = getReports(reportsDir);
49
50     if (xmlFiles.length == 0) {
51       // See http://jira.codehaus.org/browse/SONAR-2371
52       if (project.getModules().isEmpty()) {
53         context.saveMeasure(CoreMetrics.TESTS, 0.0);
54       }
55     } else {
56       parseFiles(context, xmlFiles);
57     }
58   }
59
60   private File[] getReports(File dir) {
61     if (dir == null || !dir.isDirectory() || !dir.exists()) {
62       return new File[0];
63     }
64     return dir.listFiles(new FilenameFilter() {
65       public boolean accept(File dir, String name) {
66         return name.startsWith("TEST") && name.endsWith(".xml");
67       }
68     });
69   }
70
71   private void parseFiles(SensorContext context, File[] reports) {
72     UnitTestIndex index = new UnitTestIndex();
73     parseFiles(reports, index);
74     sanitize(index);
75     save(index, context);
76   }
77
78   private void parseFiles(File[] reports, UnitTestIndex index) {
79     SurefireStaxHandler staxParser = new SurefireStaxHandler(index);
80     StaxParser parser = new StaxParser(staxParser, false);
81     for (File report : reports) {
82       try {
83         parser.parse(report);
84       } catch (XMLStreamException e) {
85         throw new SonarException("Fail to parse the Surefire report: " + report, e);
86       }
87     }
88   }
89
90   private void sanitize(UnitTestIndex index) {
91     for (String classname : index.getClassnames()) {
92       if (StringUtils.contains(classname, "$")) {
93         // Surefire reports classes whereas sonar supports files
94         String parentClassName = StringUtils.substringBeforeLast(classname, "$");
95         index.merge(classname, parentClassName);
96       }
97     }
98   }
99
100   private void save(UnitTestIndex index, SensorContext context) {
101     for (Map.Entry<String, UnitTestClassReport> entry : index.getIndexByClassname().entrySet()) {
102       UnitTestClassReport report = entry.getValue();
103       if (report.getTests() > 0) {
104         Resource resource = getUnitTestResource(entry.getKey());
105         double testsCount = report.getTests() - report.getSkipped();
106         saveMeasure(context, resource, CoreMetrics.SKIPPED_TESTS, report.getSkipped());
107         saveMeasure(context, resource, CoreMetrics.TESTS, testsCount);
108         saveMeasure(context, resource, CoreMetrics.TEST_ERRORS, report.getErrors());
109         saveMeasure(context, resource, CoreMetrics.TEST_FAILURES, report.getFailures());
110         saveMeasure(context, resource, CoreMetrics.TEST_EXECUTION_TIME, report.getDurationMilliseconds());
111         double passedTests = testsCount - report.getErrors() - report.getFailures();
112         if (testsCount > 0) {
113           double percentage = passedTests * 100d / testsCount;
114           saveMeasure(context, resource, CoreMetrics.TEST_SUCCESS_DENSITY, ParsingUtils.scaleValue(percentage));
115         }
116         saveResults(context, resource, report);
117       }
118     }
119   }
120
121   private void saveMeasure(SensorContext context, Resource resource, Metric metric, double value) {
122     if (!Double.isNaN(value)) {
123       context.saveMeasure(resource, metric, value);
124     }
125   }
126
127   private void saveResults(SensorContext context, Resource resource, UnitTestClassReport report) {
128     context.saveMeasure(resource, new Measure(CoreMetrics.TEST_DATA, report.toXml()));
129   }
130
131   protected abstract Resource<?> getUnitTestResource(String classKey);
132
133 }