3 * Copyright (C) 2009-2017 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program 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.
11 * This program 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.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.scanner.mediumtest.issuesmode;
22 import com.google.common.collect.ImmutableMap;
24 import java.io.IOException;
25 import java.text.ParseException;
26 import java.text.SimpleDateFormat;
27 import java.util.Date;
28 import java.util.LinkedList;
29 import java.util.List;
30 import org.apache.commons.codec.digest.DigestUtils;
31 import org.apache.commons.io.FileUtils;
32 import org.apache.commons.io.filefilter.FileFilterUtils;
33 import org.apache.commons.lang.StringUtils;
34 import org.assertj.core.api.Condition;
35 import org.junit.After;
36 import org.junit.Before;
37 import org.junit.Test;
38 import org.junit.rules.TemporaryFolder;
39 import org.sonar.api.CoreProperties;
40 import org.sonar.api.utils.log.LogTester;
41 import org.sonar.api.utils.log.LoggerLevel;
42 import org.sonar.batch.bootstrapper.IssueListener;
43 import org.sonar.scanner.issue.tracking.TrackedIssue;
44 import org.sonar.scanner.mediumtest.ScannerMediumTester;
45 import org.sonar.scanner.mediumtest.TaskResult;
46 import org.sonar.scanner.protocol.Constants.Severity;
47 import org.sonar.scanner.protocol.input.ScannerInput.ServerIssue;
48 import org.sonar.scanner.scan.report.ConsoleReport;
49 import org.sonar.xoo.XooPlugin;
50 import org.sonar.xoo.rule.XooRulesDefinition;
52 import static org.assertj.core.api.Assertions.assertThat;
54 public class IssueModeAndReportsMediumTest {
57 public TemporaryFolder temp = new TemporaryFolder();
60 public LogTester logTester = new LogTester();
62 private static SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
64 private static Long date(String date) {
66 return sdf.parse(date).getTime();
67 } catch (ParseException e) {
68 throw new IllegalStateException(e);
72 public ScannerMediumTester tester = ScannerMediumTester.builder()
73 .bootstrapProperties(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES))
74 .registerPlugin("xoo", new XooPlugin())
75 .addDefaultQProfile("xoo", "Sonar Way")
76 .addRules(new XooRulesDefinition())
77 .addActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", null, "xoo")
78 .addActiveRule("xoo", "OneIssueOnDirPerFile", null, "OneIssueOnDirPerFile", "MAJOR", null, "xoo")
79 .addActiveRule("xoo", "OneIssuePerModule", null, "OneIssuePerModule", "MAJOR", null, "xoo")
80 .setPreviousAnalysisDate(new Date())
81 // Existing issue that is still detected
82 .mockServerIssue(ServerIssue.newBuilder().setKey("xyz")
83 .setModuleKey("sample")
84 .setPath("xources/hello/HelloJava.xoo")
85 .setRuleRepository("xoo")
86 .setRuleKey("OneIssuePerLine")
88 .setSeverity(Severity.MAJOR)
89 .setCreationDate(date("14/03/2004"))
90 .setChecksum(DigestUtils.md5Hex("packagehello;"))
93 // Existing issue that is no more detected (will be closed)
94 .mockServerIssue(ServerIssue.newBuilder().setKey("resolved")
95 .setModuleKey("sample")
96 .setPath("xources/hello/HelloJava.xoo")
97 .setRuleRepository("xoo")
98 .setRuleKey("OneIssuePerLine")
100 .setSeverity(Severity.MAJOR)
101 .setCreationDate(date("14/03/2004"))
102 .setChecksum(DigestUtils.md5Hex("dontexist"))
105 // Existing issue on project that is still detected
106 .mockServerIssue(ServerIssue.newBuilder().setKey("resolved-on-project")
107 .setModuleKey("sample")
108 .setRuleRepository("xoo")
109 .setRuleKey("OneIssuePerModule")
110 .setSeverity(Severity.CRITICAL)
111 .setCreationDate(date("14/03/2004"))
117 public void prepare() {
126 private File copyProject(String path) throws Exception {
127 File projectDir = temp.newFolder();
128 File originalProjectDir = new File(IssueModeAndReportsMediumTest.class.getResource(path).toURI());
129 FileUtils.copyDirectory(originalProjectDir, projectDir, FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter(".sonar")));
134 public void testIssueTracking() throws Exception {
135 File projectDir = copyProject("/mediumtest/xoo/sample");
137 TaskResult result = tester
138 .newScanTask(new File(projectDir, "sonar-project.properties"))
143 int resolvedIssue = 0;
144 for (TrackedIssue issue : result.trackedIssues()) {
146 .println(issue.getMessage() + " " + issue.key() + " " + issue.getRuleKey() + " " + issue.isNew() + " " + issue.resolution() + " " + issue.componentKey() + " "
147 + issue.startLine());
150 } else if (issue.resolution() != null) {
156 System.out.println("new: " + newIssues + " open: " + openIssues + " resolved " + resolvedIssue);
157 assertThat(newIssues).isEqualTo(16);
158 assertThat(openIssues).isEqualTo(2);
159 assertThat(resolvedIssue).isEqualTo(1);
162 String logs = StringUtils.join(logTester.logs(LoggerLevel.INFO), "\n");
164 assertThat(logs).contains("Performing issue tracking");
165 assertThat(logs).contains("6/6 components tracked");
167 // assert that original fields of a matched issue are kept
168 assertThat(result.trackedIssues()).haveExactly(1, new Condition<TrackedIssue>() {
170 public boolean matches(TrackedIssue value) {
171 return value.isNew() == false
172 && "resolved-on-project".equals(value.key())
173 && "OPEN".equals(value.status())
174 && new Date(date("14/03/2004")).equals(value.creationDate());
180 public void testConsoleReport() throws Exception {
181 File projectDir = copyProject("/mediumtest/xoo/sample");
184 .newScanTask(new File(projectDir, "sonar-project.properties"))
185 .property("sonar.issuesReport.console.enable", "true")
188 assertThat(getReportLog()).contains("+16 issues", "+16 major");
192 public void testPostJob() throws Exception {
193 File projectDir = copyProject("/mediumtest/xoo/sample");
196 .newScanTask(new File(projectDir, "sonar-project.properties"))
197 .property("sonar.xoo.enablePostJob", "true")
200 assertThat(logTester.logs()).contains("Resolved issues: 1", "Open issues: 18");
203 private String getReportLog() {
204 for (String log : logTester.logs()) {
205 if (log.contains(ConsoleReport.HEADER)) {
209 throw new IllegalStateException("No console report");
213 public void testHtmlReport() throws Exception {
214 File projectDir = copyProject("/mediumtest/xoo/sample");
217 .newScanTask(new File(projectDir, "sonar-project.properties"))
218 .property("sonar.issuesReport.html.enable", "true")
221 assertThat(new File(projectDir, ".sonar/issues-report/issues-report.html")).exists();
222 assertThat(new File(projectDir, ".sonar/issues-report/issues-report-light.html")).exists();
226 public void testHtmlReportNoFile() throws Exception {
227 File baseDir = temp.newFolder();
228 File srcDir = new File(baseDir, "src");
232 .properties(ImmutableMap.<String, String>builder()
233 .put("sonar.task", "scan")
234 .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
235 .put("sonar.projectKey", "sample")
236 .put("sonar.projectName", "Foo Project")
237 .put("sonar.projectVersion", "1.0-SNAPSHOT")
238 .put("sonar.projectDescription", "Description of Foo Project")
239 .put("sonar.sources", "src")
240 .put("sonar.issuesReport.html.enable", "true")
244 assertThat(FileUtils.readFileToString(new File(baseDir, ".sonar/issues-report/issues-report.html"))).contains("No file analyzed");
245 assertThat(FileUtils.readFileToString(new File(baseDir, ".sonar/issues-report/issues-report-light.html"))).contains("No file analyzed");
249 public void testIssueCallback() throws Exception {
250 File projectDir = copyProject("/mediumtest/xoo/sample");
251 IssueRecorder issueListener = new IssueRecorder();
253 TaskResult result = tester
254 .newScanTask(new File(projectDir, "sonar-project.properties"))
255 .setIssueListener(issueListener)
256 .property("sonar.verbose", "true")
259 assertThat(result.trackedIssues()).hasSize(19);
260 assertThat(issueListener.issueList).hasSize(19);
263 private class IssueRecorder implements IssueListener {
264 List<Issue> issueList = new LinkedList<>();
267 public void handle(Issue issue) {
268 issueList.add(issue);
273 public void noSyntaxHighlightingInIssuesMode() throws IOException {
275 File baseDir = temp.newFolder();
276 File srcDir = new File(baseDir, "src");
279 File xooFile = new File(srcDir, "sample.xoo");
280 File xoohighlightingFile = new File(srcDir, "sample.xoo.highlighting");
281 FileUtils.write(xooFile, "Sample xoo\ncontent plop");
282 FileUtils.write(xoohighlightingFile, "0:10:s\n11:18:k");
284 TaskResult result = tester.newTask()
285 .properties(ImmutableMap.<String, String>builder()
286 .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
287 .put("sonar.projectKey", "com.foo.project")
288 .put("sonar.projectName", "Foo Project")
289 .put("sonar.projectVersion", "1.0-SNAPSHOT")
290 .put("sonar.projectDescription", "Description of Foo Project")
291 .put("sonar.sources", "src")
295 assertThat(result.getReportReader().hasSyntaxHighlighting(1)).isFalse();
296 assertThat(result.getReportReader().hasSyntaxHighlighting(2)).isFalse();
297 assertThat(result.getReportReader().hasSyntaxHighlighting(3)).isFalse();