Skip to content

Commit

Permalink
Fixed SurefireSensor
Browse files Browse the repository at this point in the history
  • Loading branch information
Gilles Grousset committed Jan 6, 2015
1 parent 9404b1d commit f991a62
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 51 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@

<maven.test.redirectTestOutputToFile>true</maven.test.redirectTestOutputToFile>

<sonar.version>4.3.2</sonar.version>
<sonar.version>4.3</sonar.version>
<sslr.version>1.20</sslr.version>

<!-- Configuration for sonar-packaging-maven-plugin -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@

import com.google.common.collect.ImmutableList;

import org.sonar.plugins.objectivec.tests.SurefireSensor;
import org.sonar.plugins.objectivec.violations.OCLintProfile;
import org.sonar.plugins.objectivec.violations.OCLintProfileImporter;
import org.sonar.plugins.objectivec.violations.OCLintRuleRepository;
import org.sonar.plugins.objectivec.violations.OCLintSensor;
import org.sonar.plugins.surefire.SurefireSensor;

@Properties({
@Property(key = CoberturaSensor.REPORT_PATTERN_KEY, defaultValue = CoberturaSensor.DEFAULT_REPORT_PATTERN, name = "Path to unit test coverage report(s)", description = "Relative to projects' root. Ant patterns are accepted", global = false, project = true),
Expand Down
156 changes: 156 additions & 0 deletions src/main/java/org/sonar/plugins/objectivec/tests/SurefireParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* Sonar Objective-C Plugin
* Copyright (C) 2012 OCTO Technology
* [email protected]
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
*/

package org.sonar.plugins.objectivec.tests;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.Metric;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Resource;
import org.sonar.api.utils.ParsingUtils;
import org.sonar.api.utils.StaxParser;
import org.sonar.api.utils.XmlParserException;
import org.sonar.plugins.surefire.TestCaseDetails;
import org.sonar.plugins.surefire.TestSuiteParser;
import org.sonar.plugins.surefire.TestSuiteReport;

import javax.xml.transform.TransformerException;
import java.io.File;
import java.io.FilenameFilter;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
* Created by gillesgrousset on 06/01/15.
*/
public class SurefireParser {

public void collect(Project project, SensorContext context, File reportsDir) {
File[] xmlFiles = getReports(reportsDir);

if (xmlFiles.length == 0) {
insertZeroWhenNoReports(project, context);
} else {
parseFiles(context, xmlFiles);
}
}

private File[] getReports(File dir) {
if (dir == null || !dir.isDirectory() || !dir.exists()) {
return new File[0];
}

File[] list = dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith("TEST") && name.endsWith(".xml");
}
});

return dir.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.startsWith("TEST") && name.endsWith(".xml");
}
});
}

private void insertZeroWhenNoReports(Project pom, SensorContext context) {
if ( !StringUtils.equalsIgnoreCase("pom", pom.getPackaging())) {
context.saveMeasure(CoreMetrics.TESTS, 0.0);
}
}

private void parseFiles(SensorContext context, File[] reports) {
Set<TestSuiteReport> analyzedReports = new HashSet<TestSuiteReport>();
try {
for (File report : reports) {
TestSuiteParser parserHandler = new TestSuiteParser();
StaxParser parser = new StaxParser(parserHandler, false);
parser.parse(report);

for (TestSuiteReport fileReport : parserHandler.getParsedReports()) {
if ( !fileReport.isValid() || analyzedReports.contains(fileReport)) {
continue;
}
if (fileReport.getTests() > 0) {
double testsCount = fileReport.getTests() - fileReport.getSkipped();
saveClassMeasure(context, fileReport, CoreMetrics.SKIPPED_TESTS, fileReport.getSkipped());
saveClassMeasure(context, fileReport, CoreMetrics.TESTS, testsCount);
saveClassMeasure(context, fileReport, CoreMetrics.TEST_ERRORS, fileReport.getErrors());
saveClassMeasure(context, fileReport, CoreMetrics.TEST_FAILURES, fileReport.getFailures());
saveClassMeasure(context, fileReport, CoreMetrics.TEST_EXECUTION_TIME, fileReport.getTimeMS());
double passedTests = testsCount - fileReport.getErrors() - fileReport.getFailures();
if (testsCount > 0) {
double percentage = passedTests * 100d / testsCount;
saveClassMeasure(context, fileReport, CoreMetrics.TEST_SUCCESS_DENSITY, ParsingUtils.scaleValue(percentage));
}
saveTestsDetails(context, fileReport);
analyzedReports.add(fileReport);
}
}
}

} catch (Exception e) {
throw new XmlParserException("Can not parse surefire reports", e);
}
}

private void saveTestsDetails(SensorContext context, TestSuiteReport fileReport) throws TransformerException {
StringBuilder testCaseDetails = new StringBuilder(256);
testCaseDetails.append("<tests-details>");
List<TestCaseDetails> details = fileReport.getDetails();
for (TestCaseDetails detail : details) {
testCaseDetails.append("<testcase status=\"").append(detail.getStatus())
.append("\" time=\"").append(detail.getTimeMS())
.append("\" name=\"").append(detail.getName()).append("\"");
boolean isError = detail.getStatus().equals(TestCaseDetails.STATUS_ERROR);
if (isError || detail.getStatus().equals(TestCaseDetails.STATUS_FAILURE)) {
testCaseDetails.append(">")
.append(isError ? "<error message=\"" : "<failure message=\"")
.append(StringEscapeUtils.escapeXml(detail.getErrorMessage())).append("\">")
.append("<![CDATA[").append(StringEscapeUtils.escapeXml(detail.getStackTrace())).append("]]>")
.append(isError ? "</error>" : "</failure>").append("</testcase>");
} else {
testCaseDetails.append("/>");
}
}
testCaseDetails.append("</tests-details>");
context.saveMeasure(getUnitTestResource(fileReport.getClassKey()), new Measure(CoreMetrics.TEST_DATA, testCaseDetails.toString()));
}

private void saveClassMeasure(SensorContext context, TestSuiteReport fileReport, Metric metric, double value) {
if ( !Double.isNaN(value)) {
context.saveMeasure(getUnitTestResource(fileReport.getClassKey()), metric, value);
}
}

public Resource getUnitTestResource(String classKey) {

String filename = classKey.replace('.', '/') + ".m";
org.sonar.api.resources.File sonarFile = new org.sonar.api.resources.File(filename);
sonarFile.setQualifier(Qualifiers.UNIT_TEST_FILE);
return sonarFile;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,38 +28,35 @@
import org.sonar.api.batch.SensorContext;
import org.sonar.api.config.Settings;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Qualifiers;
import org.sonar.api.resources.Resource;
import org.sonar.plugins.objectivec.core.ObjectiveC;
import org.sonar.plugins.surefire.api.AbstractSurefireParser;

import java.io.File;

public class SurefireSensor implements Sensor {

private static final Logger LOG = LoggerFactory.getLogger(SurefireSensor.class);
public static final String REPORT_PATH_KEY = "sonar.junit.reportsPath";
public static final String DEFAULT_REPORT_PATH = "sonar-reports/";
private final Settings conf;
private static final Logger LOG = LoggerFactory.getLogger(SurefireSensor.class);
public static final String REPORT_PATH_KEY = "sonar.junit.reportsPath";
public static final String DEFAULT_REPORT_PATH = "sonar-reports/";
private final Settings conf;

public SurefireSensor() {
this(null);
}
public SurefireSensor() {
this(null);
}

public SurefireSensor(final Settings config) {
conf = config;
}
public SurefireSensor(final Settings config) {
conf = config;
}

@DependsUpon
public Class<?> dependsUponCoverageSensors() {
return CoverageExtension.class;
}
@DependsUpon
public Class<?> dependsUponCoverageSensors() {
return CoverageExtension.class;
}

public boolean shouldExecuteOnProject(Project project) {
return ObjectiveC.KEY.equals(ObjectiveC.KEY);
}
public boolean shouldExecuteOnProject(Project project) {
return ObjectiveC.KEY.equals(project.getLanguageKey());
}

public void analyse(Project project, SensorContext context) {
public void analyse(Project project, SensorContext context) {

/*
GitHub Issue #50
Expand All @@ -77,37 +74,27 @@ that is very different (and does not contain a matching method).
So the implementation here reaches into the project properties and pulls the path out by itself.
*/

collect(project, context, new File(reportPath()));
}
collect(project, context, new File(reportPath()));
}

protected void collect(Project project, SensorContext context, File reportsDir) {
LOG.info("parsing {}", reportsDir);
SUREFIRE_PARSER.collect(project, context, reportsDir);
}
protected void collect(Project project, SensorContext context, File reportsDir) {
LOG.info("parsing {}", reportsDir);
SUREFIRE_PARSER.collect(project, context, reportsDir);
}

private static final SurefireParser SUREFIRE_PARSER = new SurefireParser();

private static final AbstractSurefireParser SUREFIRE_PARSER = null;

/*new AbstractSurefireParser() {
@Override
protected Resource<?> getUnitTestResource(String classKey) {
String filename = classKey.replace('.', '/') + ".m";
org.sonar.api.resources.File sonarFile = new org.sonar.api.resources.File(filename);
sonarFile.setQualifier(Qualifiers.UNIT_TEST_FILE);
return sonarFile;
public String toString() {
return "Objective-C SurefireSensor";
}

private String reportPath() {
String reportPath = conf.getString(REPORT_PATH_KEY);
if (reportPath == null) {
reportPath = DEFAULT_REPORT_PATH;
}
return reportPath;
}
};*/

@Override
public String toString() {
return "Objective-C SurefireSensor";
}

private String reportPath() {
String reportPath = conf.getString(REPORT_PATH_KEY);
if (reportPath == null) {
reportPath = DEFAULT_REPORT_PATH;
}
return reportPath;
}

}

0 comments on commit f991a62

Please sign in to comment.