3 * Copyright (C) 2009-2016 SonarSource SA
4 * mailto:contact 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.batch.mediumtest.issuesmode;
22 import org.apache.commons.lang.StringUtils;
24 import org.sonar.api.utils.log.LoggerLevel;
25 import org.assertj.core.api.Condition;
26 import org.sonar.batch.issue.tracking.TrackedIssue;
27 import com.google.common.collect.ImmutableMap;
30 import java.io.IOException;
31 import java.text.ParseException;
32 import java.text.SimpleDateFormat;
33 import java.util.Date;
34 import java.util.LinkedList;
35 import java.util.List;
37 import org.apache.commons.codec.digest.DigestUtils;
38 import org.apache.commons.io.FileUtils;
39 import org.apache.commons.io.filefilter.FileFilterUtils;
40 import org.junit.After;
41 import org.junit.Before;
42 import org.junit.Test;
43 import org.junit.rules.TemporaryFolder;
44 import org.sonar.api.CoreProperties;
45 import org.sonar.api.utils.log.LogTester;
46 import org.sonar.batch.bootstrapper.IssueListener;
47 import org.sonar.batch.mediumtest.BatchMediumTester;
48 import org.sonar.batch.mediumtest.TaskResult;
49 import org.sonar.batch.scan.report.ConsoleReport;
50 import org.sonar.scanner.protocol.Constants.Severity;
51 import org.sonar.scanner.protocol.input.ScannerInput.ServerIssue;
52 import org.sonar.xoo.XooPlugin;
53 import org.sonar.xoo.rule.XooRulesDefinition;
54 import static org.assertj.core.api.Assertions.assertThat;
56 public class IssueModeAndReportsMediumTest {
59 public TemporaryFolder temp = new TemporaryFolder();
62 public LogTester logTester = new LogTester();
64 private static SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
66 private static Long date(String date) {
68 return sdf.parse(date).getTime();
69 } catch (ParseException e) {
70 throw new IllegalStateException(e);
74 public BatchMediumTester tester = BatchMediumTester.builder()
75 .bootstrapProperties(ImmutableMap.of(CoreProperties.ANALYSIS_MODE, CoreProperties.ANALYSIS_MODE_ISSUES))
76 .registerPlugin("xoo", new XooPlugin())
77 .addDefaultQProfile("xoo", "Sonar Way")
78 .addRules(new XooRulesDefinition())
79 .addRule("manual:MyManualIssue", "manual", "MyManualIssue", "My manual issue")
80 .addRule("manual:MyManualIssueDup", "manual", "MyManualIssue", "My manual issue")
81 .addActiveRule("xoo", "OneIssuePerLine", null, "One issue per line", "MAJOR", null, "xoo")
82 .addActiveRule("xoo", "OneIssueOnDirPerFile", null, "OneIssueOnDirPerFile", "MAJOR", null, "xoo")
83 .addActiveRule("xoo", "OneIssuePerModule", null, "OneIssuePerModule", "MAJOR", null, "xoo")
84 .addActiveRule("manual", "MyManualIssue", null, "My manual issue", "MAJOR", null, null)
85 .setPreviousAnalysisDate(new Date())
86 // Existing issue that is still detected
87 .mockServerIssue(ServerIssue.newBuilder().setKey("xyz")
88 .setModuleKey("sample")
89 .setPath("xources/hello/HelloJava.xoo")
90 .setRuleRepository("xoo")
91 .setRuleKey("OneIssuePerLine")
93 .setSeverity(Severity.MAJOR)
94 .setCreationDate(date("14/03/2004"))
95 .setChecksum(DigestUtils.md5Hex("packagehello;"))
98 // Existing issue that is no more detected (will be closed)
99 .mockServerIssue(ServerIssue.newBuilder().setKey("resolved")
100 .setModuleKey("sample")
101 .setPath("xources/hello/HelloJava.xoo")
102 .setRuleRepository("xoo")
103 .setRuleKey("OneIssuePerLine")
105 .setSeverity(Severity.MAJOR)
106 .setCreationDate(date("14/03/2004"))
107 .setChecksum(DigestUtils.md5Hex("dontexist"))
110 // Existing issue on project that is still detected
111 .mockServerIssue(ServerIssue.newBuilder().setKey("resolved-on-project")
112 .setModuleKey("sample")
113 .setRuleRepository("xoo")
114 .setRuleKey("OneIssuePerModule")
115 .setSeverity(Severity.CRITICAL)
116 .setCreationDate(date("14/03/2004"))
120 .mockServerIssue(ServerIssue.newBuilder().setKey("manual")
121 .setModuleKey("sample")
122 .setPath("xources/hello/HelloJava.xoo")
123 .setRuleRepository("manual")
124 .setRuleKey("MyManualIssue")
126 .setSeverity(Severity.MAJOR)
127 .setCreationDate(date("14/03/2004"))
128 .setChecksum(DigestUtils.md5Hex("packagehello;"))
134 public void prepare() {
143 private File copyProject(String path) throws Exception {
144 File projectDir = temp.newFolder();
145 File originalProjectDir = new File(IssueModeAndReportsMediumTest.class.getResource(path).toURI());
146 FileUtils.copyDirectory(originalProjectDir, projectDir, FileFilterUtils.notFileFilter(FileFilterUtils.nameFileFilter(".sonar")));
151 public void testIssueTracking() throws Exception {
152 File projectDir = copyProject("/mediumtest/xoo/sample");
154 TaskResult result = tester
155 .newScanTask(new File(projectDir, "sonar-project.properties"))
160 int resolvedIssue = 0;
161 for (TrackedIssue issue : result.trackedIssues()) {
163 .println(issue.getMessage() + " " + issue.key() + " " + issue.getRuleKey() + " " + issue.isNew() + " " + issue.resolution() + " " + issue.componentKey() + " "
164 + issue.startLine());
167 } else if (issue.resolution() != null) {
173 System.out.println("new: " + newIssues + " open: " + openIssues + " resolved " + resolvedIssue);
174 assertThat(newIssues).isEqualTo(16);
175 assertThat(openIssues).isEqualTo(3);
176 assertThat(resolvedIssue).isEqualTo(1);
179 String logs = StringUtils.join(logTester.logs(LoggerLevel.INFO), "\n");
181 assertThat(logs).contains("Performing issue tracking");
182 assertThat(logs).contains("6/6 components tracked");
184 // assert that original fields of a matched issue are kept
185 assertThat(result.trackedIssues()).haveExactly(1, new Condition<TrackedIssue>() {
187 public boolean matches(TrackedIssue value) {
188 return value.isNew() == false
189 && "resolved-on-project".equals(value.key())
190 && "OPEN".equals(value.status())
191 && new Date(date("14/03/2004")).equals(value.creationDate());
197 public void testConsoleReport() throws Exception {
198 File projectDir = copyProject("/mediumtest/xoo/sample");
201 .newScanTask(new File(projectDir, "sonar-project.properties"))
202 .property("sonar.issuesReport.console.enable", "true")
205 assertThat(getReportLog()).contains("+16 issues", "+16 major");
209 public void testPostJob() throws Exception {
210 File projectDir = copyProject("/mediumtest/xoo/sample");
213 .newScanTask(new File(projectDir, "sonar-project.properties"))
214 .property("sonar.xoo.enablePostJob", "true")
217 assertThat(logTester.logs()).contains("Resolved issues: 1", "Open issues: 19");
220 private String getReportLog() {
221 for (String log : logTester.logs()) {
222 if (log.contains(ConsoleReport.HEADER)) {
226 throw new IllegalStateException("No console report");
230 public void testHtmlReport() throws Exception {
231 File projectDir = copyProject("/mediumtest/xoo/sample");
234 .newScanTask(new File(projectDir, "sonar-project.properties"))
235 .property("sonar.issuesReport.html.enable", "true")
238 assertThat(new File(projectDir, ".sonar/issues-report/issues-report.html")).exists();
239 assertThat(new File(projectDir, ".sonar/issues-report/issues-report-light.html")).exists();
243 public void testHtmlReportNoFile() throws Exception {
244 File baseDir = temp.newFolder();
245 File srcDir = new File(baseDir, "src");
249 .properties(ImmutableMap.<String, String>builder()
250 .put("sonar.task", "scan")
251 .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
252 .put("sonar.projectKey", "sample")
253 .put("sonar.projectName", "Foo Project")
254 .put("sonar.projectVersion", "1.0-SNAPSHOT")
255 .put("sonar.projectDescription", "Description of Foo Project")
256 .put("sonar.sources", "src")
257 .put("sonar.issuesReport.html.enable", "true")
261 assertThat(FileUtils.readFileToString(new File(baseDir, ".sonar/issues-report/issues-report.html"))).contains("No file analyzed");
262 assertThat(FileUtils.readFileToString(new File(baseDir, ".sonar/issues-report/issues-report-light.html"))).contains("No file analyzed");
266 public void testIssueCallback() throws Exception {
267 File projectDir = copyProject("/mediumtest/xoo/sample");
268 IssueRecorder issueListener = new IssueRecorder();
270 TaskResult result = tester
271 .newScanTask(new File(projectDir, "sonar-project.properties"))
272 .setIssueListener(issueListener)
275 assertThat(result.trackedIssues()).hasSize(20);
276 assertThat(issueListener.issueList).hasSize(20);
279 private class IssueRecorder implements IssueListener {
280 List<Issue> issueList = new LinkedList<>();
283 public void handle(Issue issue) {
284 issueList.add(issue);
289 public void noSyntaxHighlightingInIssuesMode() throws IOException {
291 File baseDir = temp.newFolder();
292 File srcDir = new File(baseDir, "src");
295 File xooFile = new File(srcDir, "sample.xoo");
296 File xoohighlightingFile = new File(srcDir, "sample.xoo.highlighting");
297 FileUtils.write(xooFile, "Sample xoo\ncontent plop");
298 FileUtils.write(xoohighlightingFile, "0:10:s\n11:18:k");
300 TaskResult result = tester.newTask()
301 .properties(ImmutableMap.<String, String>builder()
302 .put("sonar.projectBaseDir", baseDir.getAbsolutePath())
303 .put("sonar.projectKey", "com.foo.project")
304 .put("sonar.projectName", "Foo Project")
305 .put("sonar.projectVersion", "1.0-SNAPSHOT")
306 .put("sonar.projectDescription", "Description of Foo Project")
307 .put("sonar.sources", "src")
311 assertThat(result.getReportReader().hasSyntaxHighlighting(1)).isFalse();
312 assertThat(result.getReportReader().hasSyntaxHighlighting(2)).isFalse();
313 assertThat(result.getReportReader().hasSyntaxHighlighting(3)).isFalse();