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.server.computation.issue;
22 import java.util.Collections;
23 import java.util.List;
24 import org.junit.Before;
25 import org.junit.Rule;
26 import org.junit.Test;
27 import org.junit.rules.TemporaryFolder;
28 import org.mockito.ArgumentCaptor;
29 import org.sonar.api.issue.Issue;
30 import org.sonar.api.rule.RuleKey;
31 import org.sonar.api.rule.Severity;
32 import org.sonar.api.utils.System2;
33 import org.sonar.core.issue.DefaultIssue;
34 import org.sonar.core.issue.tracking.Tracker;
35 import org.sonar.db.DbTester;
36 import org.sonar.db.component.ComponentDto;
37 import org.sonar.db.component.ComponentTesting;
38 import org.sonar.db.issue.IssueDto;
39 import org.sonar.db.rule.RuleDto;
40 import org.sonar.db.rule.RuleTesting;
41 import org.sonar.scanner.protocol.Constants;
42 import org.sonar.scanner.protocol.output.ScannerReport;
43 import org.sonar.server.computation.batch.BatchReportReaderRule;
44 import org.sonar.server.computation.batch.TreeRootHolderRule;
45 import org.sonar.server.computation.component.Component;
46 import org.sonar.server.computation.component.TypeAwareVisitor;
47 import org.sonar.server.computation.issue.commonrule.CommonRuleEngineImpl;
48 import org.sonar.server.computation.qualityprofile.ActiveRulesHolderRule;
49 import org.sonar.server.computation.source.SourceLinesRepositoryRule;
50 import org.sonar.server.issue.IssueTesting;
52 import static com.google.common.collect.Lists.newArrayList;
53 import static com.google.common.collect.Sets.newHashSet;
54 import static java.util.Arrays.asList;
55 import static org.assertj.core.api.Assertions.assertThat;
56 import static org.mockito.Matchers.eq;
57 import static org.mockito.Mockito.mock;
58 import static org.mockito.Mockito.verify;
59 import static org.sonar.server.computation.component.ReportComponent.builder;
61 public class IntegrateIssuesVisitorTest {
63 static final String FILE_UUID = "FILE_UUID";
64 static final String FILE_KEY = "FILE_KEY";
65 static final int FILE_REF = 2;
66 static final Component FILE = builder(Component.Type.FILE, FILE_REF)
71 static final String PROJECT_KEY = "PROJECT_KEY";
72 static final String PROJECT_UUID = "PROJECT_UUID";
73 static final int PROJECT_REF = 1;
74 static final Component PROJECT = builder(Component.Type.PROJECT, PROJECT_REF)
76 .setUuid(PROJECT_UUID)
81 public TemporaryFolder temp = new TemporaryFolder();
84 public DbTester dbTester = DbTester.create(System2.INSTANCE);
87 public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
90 public BatchReportReaderRule reportReader = new BatchReportReaderRule();
93 public ActiveRulesHolderRule activeRulesHolderRule = new ActiveRulesHolderRule();
96 public RuleRepositoryRule ruleRepositoryRule = new RuleRepositoryRule();
99 public ComponentIssuesRepositoryRule componentIssuesRepository = new ComponentIssuesRepositoryRule(treeRootHolder);
102 public SourceLinesRepositoryRule fileSourceRepository = new SourceLinesRepositoryRule();
104 ArgumentCaptor<DefaultIssue> defaultIssueCaptor = ArgumentCaptor.forClass(DefaultIssue.class);
106 BaseIssuesLoader baseIssuesLoader = new BaseIssuesLoader(treeRootHolder, dbTester.getDbClient(), ruleRepositoryRule, activeRulesHolderRule);
107 TrackerExecution tracker = new TrackerExecution(new TrackerBaseInputFactory(baseIssuesLoader, dbTester.getDbClient()), new TrackerRawInputFactory(treeRootHolder, reportReader,
108 fileSourceRepository, new CommonRuleEngineImpl()), new Tracker<DefaultIssue, DefaultIssue>());
109 IssueCache issueCache;
111 IssueLifecycle issueLifecycle = mock(IssueLifecycle.class);
112 IssueVisitor issueVisitor = mock(IssueVisitor.class);
113 IssueVisitors issueVisitors = new IssueVisitors(new IssueVisitor[]{issueVisitor});
114 ComponentsWithUnprocessedIssues componentsWithUnprocessedIssues = new ComponentsWithUnprocessedIssues();
116 TypeAwareVisitor underTest;
119 public void setUp() throws Exception {
120 treeRootHolder.setRoot(PROJECT);
121 issueCache = new IssueCache(temp.newFile(), System2.INSTANCE);
122 underTest = new IntegrateIssuesVisitor(tracker, issueCache, issueLifecycle, issueVisitors, componentsWithUnprocessedIssues, componentIssuesRepository);
126 public void process_new_issue() throws Exception {
127 componentsWithUnprocessedIssues.setUuids(Collections.<String>emptySet());
129 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
130 .setMsg("the message")
131 .setRuleRepository("xoo")
133 .setSeverity(Constants.Severity.BLOCKER)
135 reportReader.putIssues(FILE_REF, asList(reportIssue));
136 fileSourceRepository.addLine(FILE_REF, "line1");
138 underTest.visitAny(FILE);
140 verify(issueLifecycle).initNewOpenIssue(defaultIssueCaptor.capture());
141 assertThat(defaultIssueCaptor.getValue().ruleKey().rule()).isEqualTo("S001");
143 verify(issueLifecycle).doAutomaticTransition(defaultIssueCaptor.capture());
144 assertThat(defaultIssueCaptor.getValue().ruleKey().rule()).isEqualTo("S001");
146 assertThat(newArrayList(issueCache.traverse())).hasSize(1);
147 assertThat(componentsWithUnprocessedIssues.getUuids()).isEmpty();
151 public void process_existing_issue() throws Exception {
152 componentsWithUnprocessedIssues.setUuids(newHashSet(FILE_UUID));
154 RuleKey ruleKey = RuleTesting.XOO_X1;
155 // Issue from db has severity major
156 addBaseIssue(ruleKey);
158 // Issue from report has severity blocker
159 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
160 .setMsg("the message")
161 .setRuleRepository(ruleKey.repository())
162 .setRuleKey(ruleKey.rule())
163 .setSeverity(Constants.Severity.BLOCKER)
165 reportReader.putIssues(FILE_REF, asList(reportIssue));
166 fileSourceRepository.addLine(FILE_REF, "line1");
168 underTest.visitAny(FILE);
170 ArgumentCaptor<DefaultIssue> rawIssueCaptor = ArgumentCaptor.forClass(DefaultIssue.class);
171 ArgumentCaptor<DefaultIssue> baseIssueCaptor = ArgumentCaptor.forClass(DefaultIssue.class);
172 verify(issueLifecycle).mergeExistingOpenIssue(rawIssueCaptor.capture(), baseIssueCaptor.capture());
173 assertThat(rawIssueCaptor.getValue().severity()).isEqualTo(Severity.BLOCKER);
174 assertThat(baseIssueCaptor.getValue().severity()).isEqualTo(Severity.MAJOR);
176 verify(issueLifecycle).doAutomaticTransition(defaultIssueCaptor.capture());
177 assertThat(defaultIssueCaptor.getValue().ruleKey()).isEqualTo(ruleKey);
178 List<DefaultIssue> issues = newArrayList(issueCache.traverse());
179 assertThat(issues).hasSize(1);
180 assertThat(issues.get(0).severity()).isEqualTo(Severity.BLOCKER);
182 assertThat(componentsWithUnprocessedIssues.getUuids()).isEmpty();
186 public void process_manual_issue() throws Exception {
187 componentsWithUnprocessedIssues.setUuids(newHashSet(FILE_UUID));
189 RuleKey ruleKey = RuleKey.of(RuleKey.MANUAL_REPOSITORY_KEY, "architecture");
190 addBaseIssue(ruleKey);
192 underTest.visitAny(FILE);
194 verify(issueLifecycle).moveOpenManualIssue(defaultIssueCaptor.capture(), eq((Integer) null));
195 assertThat(defaultIssueCaptor.getValue().ruleKey()).isEqualTo(ruleKey);
197 verify(issueLifecycle).doAutomaticTransition(defaultIssueCaptor.capture());
198 assertThat(defaultIssueCaptor.getValue().ruleKey()).isEqualTo(ruleKey);
199 List<DefaultIssue> issues = newArrayList(issueCache.traverse());
200 assertThat(issues).hasSize(1);
202 assertThat(componentsWithUnprocessedIssues.getUuids()).isEmpty();
206 public void execute_issue_visitors() throws Exception {
207 componentsWithUnprocessedIssues.setUuids(Collections.<String>emptySet());
208 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
209 .setMsg("the message")
210 .setRuleRepository("xoo")
212 .setSeverity(Constants.Severity.BLOCKER)
214 reportReader.putIssues(FILE_REF, asList(reportIssue));
215 fileSourceRepository.addLine(FILE_REF, "line1");
217 underTest.visitAny(FILE);
219 verify(issueVisitor).beforeComponent(FILE);
220 verify(issueVisitor).afterComponent(FILE);
221 verify(issueVisitor).onIssue(eq(FILE), defaultIssueCaptor.capture());
222 assertThat(defaultIssueCaptor.getValue().ruleKey().rule()).isEqualTo("S001");
226 public void close_unmatched_base_issue() throws Exception {
227 componentsWithUnprocessedIssues.setUuids(newHashSet(FILE_UUID));
228 RuleKey ruleKey = RuleTesting.XOO_X1;
229 addBaseIssue(ruleKey);
231 // No issue in the report
233 underTest.visitAny(FILE);
235 verify(issueLifecycle).doAutomaticTransition(defaultIssueCaptor.capture());
236 assertThat(defaultIssueCaptor.getValue().isBeingClosed()).isTrue();
237 List<DefaultIssue> issues = newArrayList(issueCache.traverse());
238 assertThat(issues).hasSize(1);
240 assertThat(componentsWithUnprocessedIssues.getUuids()).isEmpty();
244 public void feed_component_issues_repo() throws Exception {
245 componentsWithUnprocessedIssues.setUuids(Collections.<String>emptySet());
247 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
248 .setMsg("the message")
249 .setRuleRepository("xoo")
251 .setSeverity(Constants.Severity.BLOCKER)
253 reportReader.putIssues(FILE_REF, asList(reportIssue));
254 fileSourceRepository.addLine(FILE_REF, "line1");
256 underTest.visitAny(FILE);
258 assertThat(componentIssuesRepository.getIssues(FILE_REF)).hasSize(1);
262 public void empty_component_issues_repo_when_no_issue() throws Exception {
263 componentsWithUnprocessedIssues.setUuids(Collections.<String>emptySet());
265 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
266 .setMsg("the message")
267 .setRuleRepository("xoo")
269 .setSeverity(Constants.Severity.BLOCKER)
271 reportReader.putIssues(FILE_REF, asList(reportIssue));
272 fileSourceRepository.addLine(FILE_REF, "line1");
274 underTest.visitAny(FILE);
275 assertThat(componentIssuesRepository.getIssues(FILE_REF)).hasSize(1);
277 underTest.visitAny(PROJECT);
278 assertThat(componentIssuesRepository.getIssues(PROJECT)).isEmpty();
281 private void addBaseIssue(RuleKey ruleKey) {
282 ComponentDto project = ComponentTesting.newProjectDto(PROJECT_UUID).setKey(PROJECT_KEY);
283 ComponentDto file = ComponentTesting.newFileDto(project, FILE_UUID).setKey(FILE_KEY);
284 dbTester.getDbClient().componentDao().insert(dbTester.getSession(), project, file);
286 RuleDto ruleDto = RuleTesting.newDto(ruleKey);
287 dbTester.getDbClient().ruleDao().insert(dbTester.getSession(), ruleDto);
288 ruleRepositoryRule.add(ruleKey);
290 IssueDto issue = IssueTesting.newDto(ruleDto, file, project)
292 .setStatus(Issue.STATUS_OPEN)
293 .setSeverity(Severity.MAJOR);
294 dbTester.getDbClient().issueDao().insert(dbTester.getSession(), issue);
295 dbTester.getSession().commit();