3 * Copyright (C) 2009-2023 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.ce.task.projectanalysis.issue;
22 import com.google.common.collect.Iterators;
23 import com.tngtech.java.junit.dataprovider.DataProvider;
24 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
25 import com.tngtech.java.junit.dataprovider.UseDataProvider;
26 import java.util.Collection;
27 import java.util.Collections;
29 import java.util.Optional;
30 import java.util.function.Consumer;
31 import org.jetbrains.annotations.NotNull;
32 import org.jetbrains.annotations.Nullable;
33 import org.junit.Before;
34 import org.junit.Rule;
35 import org.junit.Test;
36 import org.junit.runner.RunWith;
37 import org.sonar.api.issue.impact.SoftwareQuality;
38 import org.sonar.api.rule.RuleKey;
39 import org.sonar.api.rule.Severity;
40 import org.sonar.api.rules.RuleType;
41 import org.sonar.api.utils.Duration;
42 import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
43 import org.sonar.ce.task.projectanalysis.component.Component;
44 import org.sonar.ce.task.projectanalysis.component.ReportComponent;
45 import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
46 import org.sonar.ce.task.projectanalysis.issue.filter.IssueFilter;
47 import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
48 import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolderRule;
49 import org.sonar.ce.task.projectanalysis.source.SourceLinesHashRepository;
50 import org.sonar.core.issue.DefaultIssue;
51 import org.sonar.core.issue.tracking.Input;
52 import org.sonar.db.protobuf.DbIssues;
53 import org.sonar.scanner.protocol.Constants;
54 import org.sonar.scanner.protocol.output.ScannerReport;
55 import org.sonar.scanner.protocol.output.ScannerReport.FlowType;
56 import org.sonar.scanner.protocol.output.ScannerReport.IssueType;
57 import org.sonar.server.rule.CommonRuleKeys;
59 import static java.util.Arrays.asList;
60 import static java.util.Collections.emptyMap;
61 import static java.util.Collections.singletonList;
62 import static org.assertj.core.api.Assertions.assertThat;
63 import static org.mockito.ArgumentMatchers.any;
64 import static org.mockito.ArgumentMatchers.eq;
65 import static org.mockito.Mockito.mock;
66 import static org.mockito.Mockito.when;
67 import static org.sonar.api.issue.Issue.STATUS_OPEN;
68 import static org.sonar.api.issue.Issue.STATUS_TO_REVIEW;
69 import static org.sonar.scanner.protocol.output.ScannerReport.MessageFormattingType.CODE;
71 @RunWith(DataProviderRunner.class)
72 public class TrackerRawInputFactoryTest {
74 private static final String FILE_UUID = "fake_uuid";
75 private static final String ANOTHER_FILE_UUID = "another_fake_uuid";
76 private static final String EXAMPLE_LINE_OF_CODE_FORMAT = "int example = line + of + code + %d; ";
78 private static final int FILE_REF = 2;
79 private static final int NOT_IN_REPORT_FILE_REF = 3;
80 private static final int ANOTHER_FILE_REF = 4;
81 private static final String TEST_CONTEXT_KEY = "test_context_key";
84 public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot(PROJECT);
86 public BatchReportReaderRule reportReader = new BatchReportReaderRule();
88 public ActiveRulesHolderRule activeRulesHolder = new ActiveRulesHolderRule();
90 public RuleRepositoryRule ruleRepository = new RuleRepositoryRule();
92 private static final ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, FILE_REF).setUuid(FILE_UUID).build();
93 private static final ReportComponent ANOTHER_FILE = ReportComponent.builder(Component.Type.FILE, ANOTHER_FILE_REF).setUuid(ANOTHER_FILE_UUID).build();
94 private static final ReportComponent PROJECT = ReportComponent.builder(Component.Type.PROJECT, 1).addChildren(FILE, ANOTHER_FILE).build();
96 private final SourceLinesHashRepository sourceLinesHash = mock(SourceLinesHashRepository.class);
97 private final IssueFilter issueFilter = mock(IssueFilter.class);
98 private final TrackerRawInputFactory underTest = new TrackerRawInputFactory(treeRootHolder, reportReader, sourceLinesHash,
99 issueFilter, ruleRepository, activeRulesHolder);
102 public void before() {
103 when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
104 when(issueFilter.accept(any(), eq(FILE))).thenReturn(true);
108 public void load_source_hash_sequences() {
109 Input<DefaultIssue> input = underTest.create(FILE);
111 assertThat(input.getLineHashSequence()).isNotNull();
112 assertThat(input.getLineHashSequence().getHashForLine(1)).isEqualTo("line");
113 assertThat(input.getLineHashSequence().getHashForLine(2)).isEmpty();
114 assertThat(input.getLineHashSequence().getHashForLine(3)).isEmpty();
116 assertThat(input.getBlockHashSequence()).isNotNull();
120 public void load_source_hash_sequences_only_on_files() {
121 Input<DefaultIssue> input = underTest.create(PROJECT);
123 assertThat(input.getLineHashSequence()).isNotNull();
124 assertThat(input.getBlockHashSequence()).isNotNull();
128 public void load_issues_from_report() {
129 RuleKey ruleKey = RuleKey.of("java", "S001");
130 markRuleAsActive(ruleKey);
131 registerRule(ruleKey, "name", r -> r.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW));
132 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
133 .setTextRange(newTextRange(2))
134 .setMsg("the message")
135 .addMsgFormatting(ScannerReport.MessageFormatting.newBuilder().setStart(0).setEnd(3).setType(CODE).build())
136 .addOverridenImpacts(ScannerReport.Impact.newBuilder()
137 .setSoftwareQuality(SoftwareQuality.MAINTAINABILITY.name())
138 .setSeverity(org.sonar.api.issue.impact.Severity.HIGH.name())
140 .setRuleRepository(ruleKey.repository())
141 .setRuleKey(ruleKey.rule())
142 .setSeverity(Constants.Severity.BLOCKER)
144 .setQuickFixAvailable(true)
146 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
147 Input<DefaultIssue> input = underTest.create(FILE);
149 Collection<DefaultIssue> issues = input.getIssues();
150 assertThat(issues).hasSize(1);
151 DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
153 // fields set by analysis report
154 assertThat(issue.ruleKey()).isEqualTo(ruleKey);
155 assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
156 assertThat(issue.line()).isEqualTo(2);
157 assertThat(issue.gap()).isEqualTo(3.14);
158 assertThat(issue.message()).isEqualTo("the message");
159 assertThat(issue.isQuickFixAvailable()).isTrue();
161 // Check message formatting
162 DbIssues.MessageFormattings messageFormattings = Iterators.getOnlyElement(issues.iterator()).getMessageFormattings();
163 assertThat(messageFormattings.getMessageFormattingCount()).isEqualTo(1);
164 assertThat(messageFormattings.getMessageFormatting(0).getStart()).isZero();
165 assertThat(messageFormattings.getMessageFormatting(0).getEnd()).isEqualTo(3);
166 assertThat(messageFormattings.getMessageFormatting(0).getType()).isEqualTo(DbIssues.MessageFormattingType.CODE);
168 // fields set by compute engine
169 assertThat(issue.checksum()).isEqualTo(input.getLineHashSequence().getHashForLine(2));
170 assertThat(issue.tags()).isEmpty();
171 assertInitializedIssue(issue);
172 assertThat(issue.effort()).isNull();
173 assertThat(issue.getRuleDescriptionContextKey()).isEmpty();
174 assertThat(issue.impacts()).containsExactlyEntriesOf(Map.of(SoftwareQuality.MAINTAINABILITY, org.sonar.api.issue.impact.Severity.HIGH));
178 public void load_issues_from_report_with_locations() {
179 RuleKey ruleKey = RuleKey.of("java", "S001");
180 markRuleAsActive(ruleKey);
182 ScannerReport.MessageFormatting messageFormatting = ScannerReport.MessageFormatting.newBuilder().setStart(0).setEnd(4).setType(CODE).build();
183 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
184 .setMsg("the message")
185 .setRuleRepository(ruleKey.repository())
186 .setRuleKey(ruleKey.rule())
187 .addFlow(ScannerReport.Flow.newBuilder()
188 .setType(FlowType.DATA)
189 .setDescription("flow1")
190 .addLocation(ScannerReport.IssueLocation.newBuilder().setMsg("loc1").addMsgFormatting(messageFormatting).setComponentRef(1).build())
191 .addLocation(ScannerReport.IssueLocation.newBuilder().setMsg("loc2").setComponentRef(1).build()))
192 .addFlow(ScannerReport.Flow.newBuilder()
193 .setType(FlowType.EXECUTION)
194 .addLocation(ScannerReport.IssueLocation.newBuilder().setTextRange(newTextRange(2)).setComponentRef(1).build()))
195 .addFlow(ScannerReport.Flow.newBuilder()
196 .addLocation(ScannerReport.IssueLocation.newBuilder().setTextRange(newTextRange(2)).setComponentRef(1).build()))
198 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
199 Input<DefaultIssue> input = underTest.create(FILE);
201 Collection<DefaultIssue> issues = input.getIssues();
202 DbIssues.Locations locations = Iterators.getOnlyElement(issues.iterator()).getLocations();
203 assertThat(locations.getFlowCount()).isEqualTo(3);
204 assertThat(locations.getFlow(0).getDescription()).isEqualTo("flow1");
205 assertThat(locations.getFlow(0).getType()).isEqualTo(DbIssues.FlowType.DATA);
206 assertThat(locations.getFlow(0).getLocationList()).hasSize(2);
208 assertThat(locations.getFlow(0).getLocation(0).getMsg()).isEqualTo("loc1");
209 assertThat(locations.getFlow(0).getLocation(0).getMsgFormattingCount()).isEqualTo(1);
210 assertThat(locations.getFlow(0).getLocation(0).getMsgFormatting(0)).extracting(m -> m.getStart(), m -> m.getEnd(), m -> m.getType())
211 .containsExactly(0, 4, DbIssues.MessageFormattingType.CODE);
213 assertThat(locations.getFlow(1).hasDescription()).isFalse();
214 assertThat(locations.getFlow(1).getType()).isEqualTo(DbIssues.FlowType.EXECUTION);
215 assertThat(locations.getFlow(1).getLocationList()).hasSize(1);
217 assertThat(locations.getFlow(2).hasDescription()).isFalse();
218 assertThat(locations.getFlow(2).hasType()).isFalse();
219 assertThat(locations.getFlow(2).getLocationList()).hasSize(1);
223 public void load_issues_from_report_with_rule_description_context_key() {
224 RuleKey ruleKey = RuleKey.of("java", "S001");
225 markRuleAsActive(ruleKey);
227 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
228 .setTextRange(newTextRange(2))
229 .setMsg("the message")
230 .setRuleRepository(ruleKey.repository())
231 .setRuleKey(ruleKey.rule())
232 .setRuleDescriptionContextKey(TEST_CONTEXT_KEY)
234 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
235 Input<DefaultIssue> input = underTest.create(FILE);
237 Collection<DefaultIssue> issues = input.getIssues();
240 .extracting(DefaultIssue::getRuleDescriptionContextKey)
241 .containsOnly(Optional.of(TEST_CONTEXT_KEY));
245 public void create_whenImpactIsNotDefinedAtRuleLevel_shouldDiscardImpacts() {
246 RuleKey ruleKey = RuleKey.of("java", "S001");
247 markRuleAsActive(ruleKey);
248 registerRule(ruleKey, "name", r -> r.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW));
249 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
250 .setTextRange(newTextRange(2))
251 .setMsg("the message")
252 .setRuleRepository(ruleKey.repository())
253 .setRuleKey(ruleKey.rule())
254 .addOverridenImpacts(ScannerReport.Impact.newBuilder()
255 .setSoftwareQuality(SoftwareQuality.SECURITY.name())
256 .setSeverity(org.sonar.api.issue.impact.Severity.LOW.name()).build())
258 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
259 Input<DefaultIssue> input = underTest.create(FILE);
261 Collection<DefaultIssue> issues = input.getIssues();
264 assertThat(issues.iterator().next().impacts()).isEmpty();
268 public void set_rule_name_as_message_when_issue_message_from_report_is_empty() {
269 RuleKey ruleKey = RuleKey.of("java", "S001");
270 markRuleAsActive(ruleKey);
271 registerRule(ruleKey, "Rule 1", r -> {
273 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
274 .setRuleRepository(ruleKey.repository())
275 .setRuleKey(ruleKey.rule())
278 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
279 Input<DefaultIssue> input = underTest.create(FILE);
281 Collection<DefaultIssue> issues = input.getIssues();
282 assertThat(issues).hasSize(1);
283 DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
285 // fields set by analysis report
286 assertThat(issue.ruleKey()).isEqualTo(ruleKey);
288 // fields set by compute engine
289 assertInitializedIssue(issue);
290 assertThat(issue.message()).isEqualTo("Rule 1");
295 public void load_issues_from_report_missing_secondary_location_component() {
296 RuleKey ruleKey = RuleKey.of("java", "S001");
297 markRuleAsActive(ruleKey);
299 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
300 .setTextRange(newTextRange(2))
301 .setMsg("the message")
302 .setRuleRepository(ruleKey.repository())
303 .setRuleKey(ruleKey.rule())
304 .setSeverity(Constants.Severity.BLOCKER)
306 .addFlow(ScannerReport.Flow.newBuilder()
307 .addLocation(ScannerReport.IssueLocation.newBuilder()
308 .setComponentRef(FILE_REF)
309 .setMsg("Secondary location in same file")
310 .setTextRange(newTextRange(2)))
311 .addLocation(ScannerReport.IssueLocation.newBuilder()
312 .setComponentRef(NOT_IN_REPORT_FILE_REF)
313 .setMsg("Secondary location in a missing file")
314 .setTextRange(newTextRange(3)))
315 .addLocation(ScannerReport.IssueLocation.newBuilder()
316 .setComponentRef(ANOTHER_FILE_REF)
317 .setMsg("Secondary location in another file")
318 .setTextRange(newTextRange(3)))
321 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
322 Input<DefaultIssue> input = underTest.create(FILE);
324 Collection<DefaultIssue> issues = input.getIssues();
325 assertThat(issues).hasSize(1);
326 DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
328 DbIssues.Locations locations = issue.getLocations();
329 // fields set by analysis report
330 assertThat(locations.getFlowList()).hasSize(1);
331 assertThat(locations.getFlow(0).getLocationList()).hasSize(2);
332 // Not component id if location is in the same file
333 assertThat(locations.getFlow(0).getLocation(0).getComponentId()).isEmpty();
334 assertThat(locations.getFlow(0).getLocation(1).getComponentId()).isEqualTo(ANOTHER_FILE_UUID);
338 @UseDataProvider("ruleTypeAndStatusByIssueType")
339 public void load_external_issues_from_report(IssueType issueType, RuleType expectedRuleType, String expectedStatus) {
340 registerRule(RuleKey.of("external_eslint", "S001"), "rule", r -> {
341 r.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, org.sonar.api.issue.impact.Severity.LOW);
343 ScannerReport.ExternalIssue reportIssue = ScannerReport.ExternalIssue.newBuilder()
344 .setTextRange(newTextRange(2))
345 .setMsg("the message")
346 .addMsgFormatting(ScannerReport.MessageFormatting.newBuilder().setStart(0).setEnd(3).build())
347 .setEngineId("eslint")
349 .setSeverity(Constants.Severity.BLOCKER)
352 .addFlow(ScannerReport.Flow.newBuilder().setType(FlowType.DATA).addLocation(ScannerReport.IssueLocation.newBuilder().build()).build())
353 .addImpacts(ScannerReport.Impact.newBuilder().setSoftwareQuality(SoftwareQuality.MAINTAINABILITY.name())
354 .setSeverity(org.sonar.api.issue.impact.Severity.MEDIUM.name()).build())
356 reportReader.putExternalIssues(FILE.getReportAttributes().getRef(), asList(reportIssue));
357 Input<DefaultIssue> input = underTest.create(FILE);
359 Collection<DefaultIssue> issues = input.getIssues();
360 assertThat(issues).hasSize(1);
361 DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
363 // fields set by analysis report
364 assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("external_eslint", "S001"));
365 assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
366 assertThat(issue.line()).isEqualTo(2);
367 assertThat(issue.effort()).isEqualTo(Duration.create(20L));
368 assertThat(issue.message()).isEqualTo("the message");
370 // Check message formatting
371 DbIssues.MessageFormattings messageFormattings = Iterators.getOnlyElement(issues.iterator()).getMessageFormattings();
372 assertThat(messageFormattings.getMessageFormattingCount()).isEqualTo(1);
373 assertThat(messageFormattings.getMessageFormatting(0).getStart()).isZero();
374 assertThat(messageFormattings.getMessageFormatting(0).getEnd()).isEqualTo(3);
375 assertThat(messageFormattings.getMessageFormatting(0).getType()).isEqualTo(DbIssues.MessageFormattingType.CODE);
377 assertThat(issue.type()).isEqualTo(expectedRuleType);
379 DbIssues.Locations locations = Iterators.getOnlyElement(issues.iterator()).getLocations();
380 assertThat(locations.getFlowCount()).isEqualTo(1);
381 assertThat(locations.getFlow(0).getType()).isEqualTo(DbIssues.FlowType.DATA);
382 assertThat(locations.getFlow(0).getLocationList()).hasSize(1);
384 // fields set by compute engine
385 assertThat(issue.checksum()).isEqualTo(input.getLineHashSequence().getHashForLine(2));
386 assertThat(issue.tags()).isEmpty();
387 assertInitializedExternalIssue(issue, expectedStatus);
389 assertThat(issue.impacts()).containsExactlyEntriesOf(Map.of(SoftwareQuality.MAINTAINABILITY, org.sonar.api.issue.impact.Severity.MEDIUM));
393 public static Object[][] ruleTypeAndStatusByIssueType() {
394 return new Object[][]{
395 {IssueType.CODE_SMELL, RuleType.CODE_SMELL, STATUS_OPEN},
396 {IssueType.BUG, RuleType.BUG, STATUS_OPEN},
397 {IssueType.VULNERABILITY, RuleType.VULNERABILITY, STATUS_OPEN},
398 {IssueType.SECURITY_HOTSPOT, RuleType.SECURITY_HOTSPOT, STATUS_TO_REVIEW}
403 @UseDataProvider("ruleTypeAndStatusByIssueType")
404 public void load_external_issues_from_report_with_default_effort(IssueType issueType, RuleType expectedRuleType, String expectedStatus) {
405 registerRule(RuleKey.of("external_eslint", "S001"), "rule", r -> {
407 ScannerReport.ExternalIssue reportIssue = ScannerReport.ExternalIssue.newBuilder()
408 .setTextRange(newTextRange(2))
409 .setMsg("the message")
410 .setEngineId("eslint")
412 .setSeverity(Constants.Severity.BLOCKER)
415 reportReader.putExternalIssues(FILE.getReportAttributes().getRef(), asList(reportIssue));
416 Input<DefaultIssue> input = underTest.create(FILE);
418 Collection<DefaultIssue> issues = input.getIssues();
419 assertThat(issues).hasSize(1);
420 DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
422 // fields set by analysis report
423 assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("external_eslint", "S001"));
424 assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
425 assertThat(issue.line()).isEqualTo(2);
426 assertThat(issue.effort()).isEqualTo(Duration.create(0L));
427 assertThat(issue.message()).isEqualTo("the message");
428 assertThat(issue.type()).isEqualTo(expectedRuleType);
430 // fields set by compute engine
431 assertThat(issue.checksum()).isEqualTo(input.getLineHashSequence().getHashForLine(2));
432 assertThat(issue.tags()).isEmpty();
433 assertInitializedExternalIssue(issue, expectedStatus);
437 public void create_whenSeverityAndTypeNotProvided_shouldTakeFromTheRule() {
438 registerRule(RuleKey.of("external_eslint", "S001"), "rule", r -> {
439 r.setType(RuleType.BUG);
440 r.setSeverity(Severity.MAJOR);
442 ScannerReport.ExternalIssue reportIssue = createIssue(null, null);
443 reportReader.putExternalIssues(FILE.getReportAttributes().getRef(), asList(reportIssue));
444 Input<DefaultIssue> input = underTest.create(FILE);
446 Collection<DefaultIssue> issues = input.getIssues();
447 assertThat(issues).hasSize(1);
448 DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
450 assertThat(issue.type()).isEqualTo(RuleType.BUG);
451 assertThat(issue.severity()).isEqualTo(Severity.MAJOR);
455 public void create_whenSeverityAndTypeNotProvidedByIssueAndRule_shouldTakeFromTheRuleImpact() {
456 registerRule(RuleKey.of("external_eslint", "S001"), "rule", r -> {
457 r.addDefaultImpact(SoftwareQuality.MAINTAINABILITY, org.sonar.api.issue.impact.Severity.MEDIUM);
459 ScannerReport.ExternalIssue reportIssue = createIssue(null, null);
460 reportReader.putExternalIssues(FILE.getReportAttributes().getRef(), asList(reportIssue));
461 Input<DefaultIssue> input = underTest.create(FILE);
463 Collection<DefaultIssue> issues = input.getIssues();
464 assertThat(issues).hasSize(1);
465 DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
467 assertThat(issue.type()).isEqualTo(RuleType.CODE_SMELL);
468 assertThat(issue.severity()).isEqualTo(Severity.MAJOR);
472 private ScannerReport.ExternalIssue createIssue(@Nullable RuleType ruleType, @Nullable String severity) {
473 ScannerReport.ExternalIssue.Builder builder = ScannerReport.ExternalIssue.newBuilder()
474 .setTextRange(newTextRange(2))
475 .setMsg("the message")
476 .setEngineId("eslint")
478 if (ruleType != null) {
479 builder.setType(IssueType.valueOf(ruleType.name()));
482 if (severity != null) {
483 builder.setSeverity(Constants.Severity.valueOf(severity));
486 return builder.build();
490 public void excludes_issues_on_inactive_rules() {
491 RuleKey ruleKey = RuleKey.of("java", "S001");
492 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
493 .setTextRange(newTextRange(2))
494 .setMsg("the message")
495 .setRuleRepository(ruleKey.repository())
496 .setRuleKey(ruleKey.rule())
497 .setSeverity(Constants.Severity.BLOCKER)
500 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
501 Input<DefaultIssue> input = underTest.create(FILE);
503 Collection<DefaultIssue> issues = input.getIssues();
504 assertThat(issues).isEmpty();
508 public void filter_excludes_issues_from_report() {
509 RuleKey ruleKey = RuleKey.of("java", "S001");
510 markRuleAsActive(ruleKey);
511 when(issueFilter.accept(any(), eq(FILE))).thenReturn(false);
512 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
513 .setTextRange(newTextRange(2))
514 .setMsg("the message")
515 .setRuleRepository(ruleKey.repository())
516 .setRuleKey(ruleKey.rule())
517 .setSeverity(Constants.Severity.BLOCKER)
520 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
521 Input<DefaultIssue> input = underTest.create(FILE);
523 Collection<DefaultIssue> issues = input.getIssues();
524 assertThat(issues).isEmpty();
528 public void exclude_issues_on_common_rules() {
529 RuleKey ruleKey = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), "S001");
530 markRuleAsActive(ruleKey);
531 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
532 .setMsg("the message")
533 .setRuleRepository(ruleKey.repository())
534 .setRuleKey(ruleKey.rule())
535 .setSeverity(Constants.Severity.BLOCKER)
537 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
539 Input<DefaultIssue> input = underTest.create(FILE);
541 assertThat(input.getIssues()).isEmpty();
544 private ScannerReport.TextRange newTextRange(int issueOnLine) {
545 return ScannerReport.TextRange.newBuilder()
546 .setStartLine(issueOnLine)
547 .setEndLine(issueOnLine)
549 .setEndOffset(EXAMPLE_LINE_OF_CODE_FORMAT.length() - 1)
553 private void assertInitializedIssue(DefaultIssue issue) {
554 assertInitializedExternalIssue(issue, STATUS_OPEN);
555 assertThat(issue.effort()).isNull();
556 assertThat(issue.effortInMinutes()).isNull();
559 private void assertInitializedExternalIssue(DefaultIssue issue, String expectedStatus) {
560 assertThat(issue.projectKey()).isEqualTo(PROJECT.getKey());
561 assertThat(issue.componentKey()).isEqualTo(FILE.getKey());
562 assertThat(issue.componentUuid()).isEqualTo(FILE.getUuid());
563 assertThat(issue.resolution()).isNull();
564 assertThat(issue.status()).isEqualTo(expectedStatus);
565 assertThat(issue.key()).isNull();
566 assertThat(issue.authorLogin()).isNull();
569 private void markRuleAsActive(RuleKey ruleKey) {
570 activeRulesHolder.put(new ActiveRule(ruleKey, Severity.CRITICAL, emptyMap(), 1_000L, null, "qp1"));
573 private void registerRule(RuleKey ruleKey, String name, Consumer<DumbRule> dumbRulePopulator) {
574 DumbRule dumbRule = new DumbRule(ruleKey);
575 dumbRule.setName(name);
576 dumbRulePopulator.accept(dumbRule);
577 ruleRepository.add(dumbRule);