3 * Copyright (C) 2009-2024 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.rule.RuleKey;
38 import org.sonar.api.rule.Severity;
39 import org.sonar.api.rules.RuleType;
40 import org.sonar.api.utils.Duration;
41 import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
42 import org.sonar.ce.task.projectanalysis.component.Component;
43 import org.sonar.ce.task.projectanalysis.component.ReportComponent;
44 import org.sonar.ce.task.projectanalysis.component.TreeRootHolderRule;
45 import org.sonar.ce.task.projectanalysis.issue.filter.IssueFilter;
46 import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRule;
47 import org.sonar.ce.task.projectanalysis.qualityprofile.ActiveRulesHolderRule;
48 import org.sonar.ce.task.projectanalysis.source.SourceLinesHashRepository;
49 import org.sonar.core.issue.DefaultIssue;
50 import org.sonar.core.issue.tracking.Input;
51 import org.sonar.db.protobuf.DbIssues;
52 import org.sonar.scanner.protocol.Constants;
53 import org.sonar.scanner.protocol.output.ScannerReport;
54 import org.sonar.scanner.protocol.output.ScannerReport.FlowType;
55 import org.sonar.scanner.protocol.output.ScannerReport.IssueType;
56 import org.sonar.server.rule.CommonRuleKeys;
58 import static java.util.Arrays.asList;
59 import static java.util.Collections.emptyMap;
60 import static java.util.Collections.singletonList;
61 import static org.assertj.core.api.Assertions.assertThat;
62 import static org.mockito.ArgumentMatchers.any;
63 import static org.mockito.ArgumentMatchers.eq;
64 import static org.mockito.Mockito.mock;
65 import static org.mockito.Mockito.when;
66 import static org.sonar.api.issue.Issue.STATUS_OPEN;
67 import static org.sonar.api.issue.Issue.STATUS_TO_REVIEW;
68 import static org.sonar.api.issue.impact.Severity.LOW;
69 import static org.sonar.api.issue.impact.SoftwareQuality.MAINTAINABILITY;
70 import static org.sonar.api.issue.impact.SoftwareQuality.SECURITY;
71 import static org.sonar.scanner.protocol.output.ScannerReport.MessageFormattingType.CODE;
73 @RunWith(DataProviderRunner.class)
74 public class TrackerRawInputFactoryTest {
76 private static final String FILE_UUID = "fake_uuid";
77 private static final String ANOTHER_FILE_UUID = "another_fake_uuid";
78 private static final String EXAMPLE_LINE_OF_CODE_FORMAT = "int example = line + of + code + %d; ";
80 private static final int FILE_REF = 2;
81 private static final int NOT_IN_REPORT_FILE_REF = 3;
82 private static final int ANOTHER_FILE_REF = 4;
83 private static final String TEST_CONTEXT_KEY = "test_context_key";
86 public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule().setRoot(PROJECT);
88 public BatchReportReaderRule reportReader = new BatchReportReaderRule();
90 public ActiveRulesHolderRule activeRulesHolder = new ActiveRulesHolderRule();
92 public RuleRepositoryRule ruleRepository = new RuleRepositoryRule();
94 private static final ReportComponent FILE = ReportComponent.builder(Component.Type.FILE, FILE_REF).setUuid(FILE_UUID).build();
95 private static final ReportComponent ANOTHER_FILE = ReportComponent.builder(Component.Type.FILE, ANOTHER_FILE_REF).setUuid(ANOTHER_FILE_UUID).build();
96 private static final ReportComponent PROJECT = ReportComponent.builder(Component.Type.PROJECT, 1).addChildren(FILE, ANOTHER_FILE).build();
98 private final SourceLinesHashRepository sourceLinesHash = mock(SourceLinesHashRepository.class);
99 private final IssueFilter issueFilter = mock(IssueFilter.class);
100 private final TrackerRawInputFactory underTest = new TrackerRawInputFactory(treeRootHolder, reportReader, sourceLinesHash,
101 issueFilter, ruleRepository, activeRulesHolder);
104 public void before() {
105 when(sourceLinesHash.getLineHashesMatchingDBVersion(FILE)).thenReturn(Collections.singletonList("line"));
106 when(issueFilter.accept(any(), eq(FILE))).thenReturn(true);
110 public void load_source_hash_sequences() {
111 Input<DefaultIssue> input = underTest.create(FILE);
113 assertThat(input.getLineHashSequence()).isNotNull();
114 assertThat(input.getLineHashSequence().getHashForLine(1)).isEqualTo("line");
115 assertThat(input.getLineHashSequence().getHashForLine(2)).isEmpty();
116 assertThat(input.getLineHashSequence().getHashForLine(3)).isEmpty();
118 assertThat(input.getBlockHashSequence()).isNotNull();
122 public void load_source_hash_sequences_only_on_files() {
123 Input<DefaultIssue> input = underTest.create(PROJECT);
125 assertThat(input.getLineHashSequence()).isNotNull();
126 assertThat(input.getBlockHashSequence()).isNotNull();
130 public void load_issues_from_report() {
131 RuleKey ruleKey = RuleKey.of("java", "S001");
132 markRuleAsActive(ruleKey);
133 registerRule(ruleKey, "name", r -> r.addDefaultImpact(MAINTAINABILITY, LOW));
134 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
135 .setTextRange(newTextRange(2))
136 .setMsg("the message")
137 .addMsgFormatting(ScannerReport.MessageFormatting.newBuilder().setStart(0).setEnd(3).setType(CODE).build())
138 .addOverridenImpacts(ScannerReport.Impact.newBuilder()
139 .setSoftwareQuality(MAINTAINABILITY.name())
140 .setSeverity(org.sonar.api.issue.impact.Severity.HIGH.name())
142 .setRuleRepository(ruleKey.repository())
143 .setRuleKey(ruleKey.rule())
144 .setSeverity(Constants.Severity.BLOCKER)
146 .setQuickFixAvailable(true)
148 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
149 Input<DefaultIssue> input = underTest.create(FILE);
151 Collection<DefaultIssue> issues = input.getIssues();
152 assertThat(issues).hasSize(1);
153 DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
155 // fields set by analysis report
156 assertThat(issue.ruleKey()).isEqualTo(ruleKey);
157 assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
158 assertThat(issue.line()).isEqualTo(2);
159 assertThat(issue.gap()).isEqualTo(3.14);
160 assertThat(issue.message()).isEqualTo("the message");
161 assertThat(issue.isQuickFixAvailable()).isTrue();
163 // Check message formatting
164 DbIssues.MessageFormattings messageFormattings = Iterators.getOnlyElement(issues.iterator()).getMessageFormattings();
165 assertThat(messageFormattings.getMessageFormattingCount()).isEqualTo(1);
166 assertThat(messageFormattings.getMessageFormatting(0).getStart()).isZero();
167 assertThat(messageFormattings.getMessageFormatting(0).getEnd()).isEqualTo(3);
168 assertThat(messageFormattings.getMessageFormatting(0).getType()).isEqualTo(DbIssues.MessageFormattingType.CODE);
170 // fields set by compute engine
171 assertThat(issue.checksum()).isEqualTo(input.getLineHashSequence().getHashForLine(2));
172 assertThat(issue.tags()).isEmpty();
173 assertInitializedIssue(issue);
174 assertThat(issue.effort()).isNull();
175 assertThat(issue.getRuleDescriptionContextKey()).isEmpty();
176 assertThat(issue.impacts()).containsExactlyEntriesOf(Map.of(MAINTAINABILITY, org.sonar.api.issue.impact.Severity.HIGH));
180 public void load_issues_from_report_with_locations() {
181 RuleKey ruleKey = RuleKey.of("java", "S001");
182 markRuleAsActive(ruleKey);
183 registerRule(ruleKey, "name");
185 ScannerReport.MessageFormatting messageFormatting = ScannerReport.MessageFormatting.newBuilder().setStart(0).setEnd(4).setType(CODE).build();
186 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
187 .setMsg("the message")
188 .setRuleRepository(ruleKey.repository())
189 .setRuleKey(ruleKey.rule())
190 .addFlow(ScannerReport.Flow.newBuilder()
191 .setType(FlowType.DATA)
192 .setDescription("flow1")
193 .addLocation(ScannerReport.IssueLocation.newBuilder().setMsg("loc1").addMsgFormatting(messageFormatting).setComponentRef(1).build())
194 .addLocation(ScannerReport.IssueLocation.newBuilder().setMsg("loc2").setComponentRef(1).build()))
195 .addFlow(ScannerReport.Flow.newBuilder()
196 .setType(FlowType.EXECUTION)
197 .addLocation(ScannerReport.IssueLocation.newBuilder().setTextRange(newTextRange(2)).setComponentRef(1).build()))
198 .addFlow(ScannerReport.Flow.newBuilder()
199 .addLocation(ScannerReport.IssueLocation.newBuilder().setTextRange(newTextRange(2)).setComponentRef(1).build()))
201 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
202 Input<DefaultIssue> input = underTest.create(FILE);
204 Collection<DefaultIssue> issues = input.getIssues();
205 DbIssues.Locations locations = Iterators.getOnlyElement(issues.iterator()).getLocations();
206 assertThat(locations.getFlowCount()).isEqualTo(3);
207 assertThat(locations.getFlow(0).getDescription()).isEqualTo("flow1");
208 assertThat(locations.getFlow(0).getType()).isEqualTo(DbIssues.FlowType.DATA);
209 assertThat(locations.getFlow(0).getLocationList()).hasSize(2);
211 assertThat(locations.getFlow(0).getLocation(0).getMsg()).isEqualTo("loc1");
212 assertThat(locations.getFlow(0).getLocation(0).getMsgFormattingCount()).isEqualTo(1);
213 assertThat(locations.getFlow(0).getLocation(0).getMsgFormatting(0)).extracting(m -> m.getStart(), m -> m.getEnd(), m -> m.getType())
214 .containsExactly(0, 4, DbIssues.MessageFormattingType.CODE);
216 assertThat(locations.getFlow(1).hasDescription()).isFalse();
217 assertThat(locations.getFlow(1).getType()).isEqualTo(DbIssues.FlowType.EXECUTION);
218 assertThat(locations.getFlow(1).getLocationList()).hasSize(1);
220 assertThat(locations.getFlow(2).hasDescription()).isFalse();
221 assertThat(locations.getFlow(2).hasType()).isFalse();
222 assertThat(locations.getFlow(2).getLocationList()).hasSize(1);
226 public void load_issues_from_report_with_rule_description_context_key() {
227 RuleKey ruleKey = RuleKey.of("java", "S001");
228 markRuleAsActive(ruleKey);
229 registerRule(ruleKey, "name");
231 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
232 .setTextRange(newTextRange(2))
233 .setMsg("the message")
234 .setRuleRepository(ruleKey.repository())
235 .setRuleKey(ruleKey.rule())
236 .setRuleDescriptionContextKey(TEST_CONTEXT_KEY)
238 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
239 Input<DefaultIssue> input = underTest.create(FILE);
241 Collection<DefaultIssue> issues = input.getIssues();
244 .extracting(DefaultIssue::getRuleDescriptionContextKey)
245 .containsOnly(Optional.of(TEST_CONTEXT_KEY));
249 public void create_whenImpactIsNotDefinedAtRuleLevel_shouldDiscardImpacts() {
250 RuleKey ruleKey = RuleKey.of("java", "S001");
251 markRuleAsActive(ruleKey);
252 registerRule(ruleKey, "name", r -> r.addDefaultImpact(MAINTAINABILITY, LOW));
253 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
254 .setTextRange(newTextRange(2))
255 .setMsg("the message")
256 .setRuleRepository(ruleKey.repository())
257 .setRuleKey(ruleKey.rule())
258 .addOverridenImpacts(ScannerReport.Impact.newBuilder()
259 .setSoftwareQuality(SECURITY.name())
260 .setSeverity(LOW.name()).build())
262 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
264 Input<DefaultIssue> input = underTest.create(FILE);
266 Collection<DefaultIssue> issues = input.getIssues();
267 assertThat(issues).hasSize(1);
268 assertThat(issues.iterator().next().impacts()).hasSize(1).containsEntry(MAINTAINABILITY, LOW);
272 public void set_rule_name_as_message_when_issue_message_from_report_is_empty() {
273 RuleKey ruleKey = RuleKey.of("java", "S001");
274 markRuleAsActive(ruleKey);
275 registerRule(ruleKey, "Rule 1");
276 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
277 .setRuleRepository(ruleKey.repository())
278 .setRuleKey(ruleKey.rule())
281 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
282 Input<DefaultIssue> input = underTest.create(FILE);
284 Collection<DefaultIssue> issues = input.getIssues();
285 assertThat(issues).hasSize(1);
286 DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
288 // fields set by analysis report
289 assertThat(issue.ruleKey()).isEqualTo(ruleKey);
291 // fields set by compute engine
292 assertInitializedIssue(issue);
293 assertThat(issue.message()).isEqualTo("Rule 1");
298 public void load_issues_from_report_missing_secondary_location_component() {
299 RuleKey ruleKey = RuleKey.of("java", "S001");
300 markRuleAsActive(ruleKey);
301 registerRule(ruleKey, "name");
303 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
304 .setTextRange(newTextRange(2))
305 .setMsg("the message")
306 .setRuleRepository(ruleKey.repository())
307 .setRuleKey(ruleKey.rule())
308 .setSeverity(Constants.Severity.BLOCKER)
310 .addFlow(ScannerReport.Flow.newBuilder()
311 .addLocation(ScannerReport.IssueLocation.newBuilder()
312 .setComponentRef(FILE_REF)
313 .setMsg("Secondary location in same file")
314 .setTextRange(newTextRange(2)))
315 .addLocation(ScannerReport.IssueLocation.newBuilder()
316 .setComponentRef(NOT_IN_REPORT_FILE_REF)
317 .setMsg("Secondary location in a missing file")
318 .setTextRange(newTextRange(3)))
319 .addLocation(ScannerReport.IssueLocation.newBuilder()
320 .setComponentRef(ANOTHER_FILE_REF)
321 .setMsg("Secondary location in another file")
322 .setTextRange(newTextRange(3)))
325 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
326 Input<DefaultIssue> input = underTest.create(FILE);
328 Collection<DefaultIssue> issues = input.getIssues();
329 assertThat(issues).hasSize(1);
330 DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
332 DbIssues.Locations locations = issue.getLocations();
333 // fields set by analysis report
334 assertThat(locations.getFlowList()).hasSize(1);
335 assertThat(locations.getFlow(0).getLocationList()).hasSize(2);
336 // Not component id if location is in the same file
337 assertThat(locations.getFlow(0).getLocation(0).getComponentId()).isEmpty();
338 assertThat(locations.getFlow(0).getLocation(1).getComponentId()).isEqualTo(ANOTHER_FILE_UUID);
342 @UseDataProvider("ruleTypeAndStatusByIssueType")
343 public void load_external_issues_from_report(IssueType issueType, RuleType expectedRuleType, String expectedStatus) {
344 registerRule(RuleKey.of("external_eslint", "S001"), "rule", r -> r.addDefaultImpact(MAINTAINABILITY, LOW));
345 ScannerReport.ExternalIssue reportIssue = ScannerReport.ExternalIssue.newBuilder()
346 .setTextRange(newTextRange(2))
347 .setMsg("the message")
348 .addMsgFormatting(ScannerReport.MessageFormatting.newBuilder().setStart(0).setEnd(3).build())
349 .setEngineId("eslint")
351 .setSeverity(Constants.Severity.BLOCKER)
354 .addFlow(ScannerReport.Flow.newBuilder().setType(FlowType.DATA).addLocation(ScannerReport.IssueLocation.newBuilder().build()).build())
355 .addImpacts(ScannerReport.Impact.newBuilder().setSoftwareQuality(MAINTAINABILITY.name())
356 .setSeverity(org.sonar.api.issue.impact.Severity.MEDIUM.name()).build())
358 reportReader.putExternalIssues(FILE.getReportAttributes().getRef(), asList(reportIssue));
359 Input<DefaultIssue> input = underTest.create(FILE);
361 Collection<DefaultIssue> issues = input.getIssues();
362 assertThat(issues).hasSize(1);
363 DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
365 // fields set by analysis report
366 assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("external_eslint", "S001"));
367 assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
368 assertThat(issue.line()).isEqualTo(2);
369 assertThat(issue.effort()).isEqualTo(Duration.create(20L));
370 assertThat(issue.message()).isEqualTo("the message");
372 // Check message formatting
373 DbIssues.MessageFormattings messageFormattings = Iterators.getOnlyElement(issues.iterator()).getMessageFormattings();
374 assertThat(messageFormattings.getMessageFormattingCount()).isEqualTo(1);
375 assertThat(messageFormattings.getMessageFormatting(0).getStart()).isZero();
376 assertThat(messageFormattings.getMessageFormatting(0).getEnd()).isEqualTo(3);
377 assertThat(messageFormattings.getMessageFormatting(0).getType()).isEqualTo(DbIssues.MessageFormattingType.CODE);
379 assertThat(issue.type()).isEqualTo(expectedRuleType);
381 DbIssues.Locations locations = Iterators.getOnlyElement(issues.iterator()).getLocations();
382 assertThat(locations.getFlowCount()).isEqualTo(1);
383 assertThat(locations.getFlow(0).getType()).isEqualTo(DbIssues.FlowType.DATA);
384 assertThat(locations.getFlow(0).getLocationList()).hasSize(1);
386 // fields set by compute engine
387 assertThat(issue.checksum()).isEqualTo(input.getLineHashSequence().getHashForLine(2));
388 assertThat(issue.tags()).isEmpty();
389 assertInitializedExternalIssue(issue, expectedStatus);
391 assertThat(issue.impacts()).containsExactlyEntriesOf(Map.of(MAINTAINABILITY, org.sonar.api.issue.impact.Severity.MEDIUM));
395 public static Object[][] ruleTypeAndStatusByIssueType() {
396 return new Object[][]{
397 {IssueType.CODE_SMELL, RuleType.CODE_SMELL, STATUS_OPEN},
398 {IssueType.BUG, RuleType.BUG, STATUS_OPEN},
399 {IssueType.VULNERABILITY, RuleType.VULNERABILITY, STATUS_OPEN},
400 {IssueType.SECURITY_HOTSPOT, RuleType.SECURITY_HOTSPOT, STATUS_TO_REVIEW}
405 @UseDataProvider("ruleTypeAndStatusByIssueType")
406 public void load_external_issues_from_report_with_default_effort(IssueType issueType, RuleType expectedRuleType, String expectedStatus) {
407 registerRule(RuleKey.of("external_eslint", "S001"), "rule");
408 ScannerReport.ExternalIssue reportIssue = ScannerReport.ExternalIssue.newBuilder()
409 .setTextRange(newTextRange(2))
410 .setMsg("the message")
411 .setEngineId("eslint")
413 .setSeverity(Constants.Severity.BLOCKER)
416 reportReader.putExternalIssues(FILE.getReportAttributes().getRef(), asList(reportIssue));
417 Input<DefaultIssue> input = underTest.create(FILE);
419 Collection<DefaultIssue> issues = input.getIssues();
420 assertThat(issues).hasSize(1);
421 DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
423 // fields set by analysis report
424 assertThat(issue.ruleKey()).isEqualTo(RuleKey.of("external_eslint", "S001"));
425 assertThat(issue.severity()).isEqualTo(Severity.BLOCKER);
426 assertThat(issue.line()).isEqualTo(2);
427 assertThat(issue.effort()).isEqualTo(Duration.create(0L));
428 assertThat(issue.message()).isEqualTo("the message");
429 assertThat(issue.type()).isEqualTo(expectedRuleType);
431 // fields set by compute engine
432 assertThat(issue.checksum()).isEqualTo(input.getLineHashSequence().getHashForLine(2));
433 assertThat(issue.tags()).isEmpty();
434 assertInitializedExternalIssue(issue, expectedStatus);
438 public void create_whenSeverityAndTypeNotProvided_shouldTakeFromTheRule() {
439 registerRule(RuleKey.of("external_eslint", "S001"), "rule", r -> {
440 r.setType(RuleType.BUG);
441 r.setSeverity(Severity.MAJOR);
443 ScannerReport.ExternalIssue reportIssue = createIssue(null, null);
444 reportReader.putExternalIssues(FILE.getReportAttributes().getRef(), asList(reportIssue));
445 Input<DefaultIssue> input = underTest.create(FILE);
447 Collection<DefaultIssue> issues = input.getIssues();
448 assertThat(issues).hasSize(1);
449 DefaultIssue issue = Iterators.getOnlyElement(issues.iterator());
451 assertThat(issue.type()).isEqualTo(RuleType.BUG);
452 assertThat(issue.severity()).isEqualTo(Severity.MAJOR);
456 public void create_whenSeverityAndTypeNotProvidedByIssueAndRule_shouldTakeFromTheRuleImpact() {
457 registerRule(RuleKey.of("external_eslint", "S001"), "rule",
458 r -> r.addDefaultImpact(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 registerRule(ruleKey, "name");
512 when(issueFilter.accept(any(), eq(FILE))).thenReturn(false);
513 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
514 .setTextRange(newTextRange(2))
515 .setMsg("the message")
516 .setRuleRepository(ruleKey.repository())
517 .setRuleKey(ruleKey.rule())
518 .setSeverity(Constants.Severity.BLOCKER)
521 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
522 Input<DefaultIssue> input = underTest.create(FILE);
524 Collection<DefaultIssue> issues = input.getIssues();
525 assertThat(issues).isEmpty();
529 public void exclude_issues_on_common_rules() {
530 RuleKey ruleKey = RuleKey.of(CommonRuleKeys.commonRepositoryForLang("java"), "S001");
531 markRuleAsActive(ruleKey);
532 ScannerReport.Issue reportIssue = ScannerReport.Issue.newBuilder()
533 .setMsg("the message")
534 .setRuleRepository(ruleKey.repository())
535 .setRuleKey(ruleKey.rule())
536 .setSeverity(Constants.Severity.BLOCKER)
538 reportReader.putIssues(FILE.getReportAttributes().getRef(), singletonList(reportIssue));
540 Input<DefaultIssue> input = underTest.create(FILE);
542 assertThat(input.getIssues()).isEmpty();
545 private ScannerReport.TextRange newTextRange(int issueOnLine) {
546 return ScannerReport.TextRange.newBuilder()
547 .setStartLine(issueOnLine)
548 .setEndLine(issueOnLine)
550 .setEndOffset(EXAMPLE_LINE_OF_CODE_FORMAT.length() - 1)
554 private void assertInitializedIssue(DefaultIssue issue) {
555 assertInitializedExternalIssue(issue, STATUS_OPEN);
556 assertThat(issue.effort()).isNull();
557 assertThat(issue.effortInMinutes()).isNull();
560 private void assertInitializedExternalIssue(DefaultIssue issue, String expectedStatus) {
561 assertThat(issue.projectKey()).isEqualTo(PROJECT.getKey());
562 assertThat(issue.componentKey()).isEqualTo(FILE.getKey());
563 assertThat(issue.componentUuid()).isEqualTo(FILE.getUuid());
564 assertThat(issue.resolution()).isNull();
565 assertThat(issue.status()).isEqualTo(expectedStatus);
566 assertThat(issue.key()).isNull();
567 assertThat(issue.authorLogin()).isNull();
570 private void markRuleAsActive(RuleKey ruleKey) {
571 activeRulesHolder.put(new ActiveRule(ruleKey, Severity.CRITICAL, emptyMap(), 1_000L, null, "qp1"));
574 private void registerRule(RuleKey ruleKey, String name) {
575 registerRule(ruleKey, name, r -> {});
578 private void registerRule(RuleKey ruleKey, String name, Consumer<DumbRule> dumbRulePopulator) {
579 DumbRule dumbRule = new DumbRule(ruleKey);
580 dumbRule.setName(name);
581 dumbRulePopulator.accept(dumbRule);
582 ruleRepository.add(dumbRule);