diff options
author | antoine.vinot <antoine.vinot@sonarsource.com> | 2023-09-27 17:35:05 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2023-10-04 20:03:19 +0000 |
commit | 87082d7efc8662a0ced560ffe9cc5fe464069327 (patch) | |
tree | 31030bfd73e1877c0a96363bcfe294fcca99cca0 /sonar-scanner-engine | |
parent | de7a6f1b14703043705718aa4a74b460cdd817b2 (diff) | |
download | sonarqube-87082d7efc8662a0ced560ffe9cc5fe464069327.tar.gz sonarqube-87082d7efc8662a0ced560ffe9cc5fe464069327.zip |
SONAR-20553 - Support the new taxonomy for SARIF Format
Diffstat (limited to 'sonar-scanner-engine')
11 files changed, 423 insertions, 99 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/BatchComponents.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/BatchComponents.java index 0c564a64310..a8acb3840ef 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/BatchComponents.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/BatchComponents.java @@ -32,6 +32,7 @@ import org.sonar.scanner.externalissue.sarif.DefaultSarif210Importer; import org.sonar.scanner.externalissue.sarif.LocationMapper; import org.sonar.scanner.externalissue.sarif.RegionMapper; import org.sonar.scanner.externalissue.sarif.ResultMapper; +import org.sonar.scanner.externalissue.sarif.RuleMapper; import org.sonar.scanner.externalissue.sarif.RunMapper; import org.sonar.scanner.externalissue.sarif.SarifIssuesImportSensor; import org.sonar.scanner.genericcoverage.GenericCoverageSensor; @@ -70,6 +71,7 @@ public class BatchComponents { components.add(ResultMapper.class); components.add(LocationMapper.class); components.add(RegionMapper.class); + components.add(RuleMapper.class); return components; } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/DefaultSarif210Importer.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/DefaultSarif210Importer.java index 57fcfee61a9..94bb73ebd1f 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/DefaultSarif210Importer.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/DefaultSarif210Importer.java @@ -21,13 +21,14 @@ package org.sonar.scanner.externalissue.sarif; import java.util.List; import java.util.Set; -import javax.annotation.CheckForNull; -import org.sonar.api.batch.sensor.issue.NewExternalIssue; -import org.sonar.api.scanner.ScannerSide; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.sonar.api.batch.sensor.issue.NewExternalIssue; +import org.sonar.api.batch.sensor.rule.NewAdHocRule; +import org.sonar.api.scanner.ScannerSide; import org.sonar.core.sarif.Run; import org.sonar.core.sarif.Sarif210; +import org.sonar.scanner.externalissue.sarif.RunMapper.RunMapperResult; import static java.util.Objects.requireNonNull; @@ -49,13 +50,17 @@ public class DefaultSarif210Importer implements Sarif210Importer { Set<Run> runs = requireNonNull(sarif210.getRuns(), "The runs section of the Sarif report is null"); for (Run run : runs) { - List<NewExternalIssue> newExternalIssues = toNewExternalIssues(run); - if (newExternalIssues == null) { - failedRuns += 1; - } else { + RunMapperResult runMapperResult = tryMapRun(run); + if (runMapperResult.isSuccess()) { + List<NewAdHocRule> newAdHocRules = runMapperResult.getNewAdHocRules(); + newAdHocRules.forEach(NewAdHocRule::save); + + List<NewExternalIssue> newExternalIssues = runMapperResult.getNewExternalIssues(); successFullyImportedRuns += 1; successFullyImportedIssues += newExternalIssues.size(); newExternalIssues.forEach(NewExternalIssue::save); + } else { + failedRuns += 1; } } return SarifImportResults.builder() @@ -65,13 +70,13 @@ public class DefaultSarif210Importer implements Sarif210Importer { .build(); } - @CheckForNull - private List<NewExternalIssue> toNewExternalIssues(Run run) { + private RunMapperResult tryMapRun(Run run) { try { return runMapper.mapRun(run); } catch (Exception exception) { LOG.warn("Failed to import a sarif run, error: {}", exception.getMessage()); - return null; + return new RunMapperResult().success(false); + } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/ResultMapper.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/ResultMapper.java index 7668c477b57..78536c98213 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/ResultMapper.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/ResultMapper.java @@ -28,16 +28,22 @@ import org.sonar.api.batch.rule.Severity; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.issue.NewExternalIssue; import org.sonar.api.batch.sensor.issue.NewIssueLocation; +import org.sonar.api.issue.impact.SoftwareQuality; +import org.sonar.api.rules.CleanCodeAttribute; import org.sonar.api.rules.RuleType; import org.sonar.api.scanner.ScannerSide; import org.sonar.core.sarif.Location; import org.sonar.core.sarif.Result; import static java.util.Objects.requireNonNull; +import static org.sonar.api.issue.impact.Severity.HIGH; +import static org.sonar.api.issue.impact.Severity.LOW; +import static org.sonar.api.issue.impact.Severity.MEDIUM; +import static org.sonar.api.issue.impact.SoftwareQuality.SECURITY; +import static org.sonar.api.rules.CleanCodeAttribute.CONVENTIONAL; @ScannerSide public class ResultMapper { - public static final Severity DEFAULT_SEVERITY = Severity.MAJOR; private static final Map<String, Severity> SEVERITY_MAPPING = ImmutableMap.<String, Severity>builder() .put("error", Severity.CRITICAL) @@ -46,7 +52,18 @@ public class ResultMapper { .put("none", Severity.INFO) .build(); - private static final RuleType DEFAULT_TYPE = RuleType.VULNERABILITY; + private static final Map<String, org.sonar.api.issue.impact.Severity> IMPACT_SEVERITY_MAPPING = ImmutableMap.<String, org.sonar.api.issue.impact.Severity>builder() + .put("error", HIGH) + .put("warning", MEDIUM) + .put("note", LOW) + .put("none", LOW) + .build(); + + public static final Severity DEFAULT_SEVERITY = Severity.MAJOR; + public static final RuleType DEFAULT_TYPE = RuleType.VULNERABILITY; + public static final CleanCodeAttribute DEFAULT_CLEAN_CODE_ATTRIBUTE = CONVENTIONAL; + public static final SoftwareQuality DEFAULT_SOFTWARE_QUALITY = SECURITY; + public static final org.sonar.api.issue.impact.Severity DEFAULT_IMPACT_SEVERITY = MEDIUM; private final SensorContext sensorContext; private final LocationMapper locationMapper; @@ -56,18 +73,24 @@ public class ResultMapper { this.locationMapper = locationMapper; } - NewExternalIssue mapResult(String driverName, @Nullable String ruleSeverity, Result result) { + NewExternalIssue mapResult(String driverName, @Nullable String ruleSeverity, @Nullable String ruleSeverityForNewTaxonomy, Result result) { NewExternalIssue newExternalIssue = sensorContext.newExternalIssue(); newExternalIssue.type(DEFAULT_TYPE); newExternalIssue.engineId(driverName); newExternalIssue.severity(toSonarQubeSeverity(ruleSeverity)); newExternalIssue.ruleId(requireNonNull(result.getRuleId(), "No ruleId found for issue thrown by driver " + driverName)); + newExternalIssue.cleanCodeAttribute(DEFAULT_CLEAN_CODE_ATTRIBUTE); + newExternalIssue.addImpact(DEFAULT_SOFTWARE_QUALITY, toSonarQubeImpactSeverity(ruleSeverityForNewTaxonomy)); mapLocations(result, newExternalIssue); return newExternalIssue; } - private static Severity toSonarQubeSeverity(@Nullable String ruleSeverity) { + protected static org.sonar.api.issue.impact.Severity toSonarQubeImpactSeverity(@Nullable String ruleSeverity) { + return IMPACT_SEVERITY_MAPPING.getOrDefault(ruleSeverity, DEFAULT_IMPACT_SEVERITY); + } + + protected static Severity toSonarQubeSeverity(@Nullable String ruleSeverity) { return SEVERITY_MAPPING.getOrDefault(ruleSeverity, DEFAULT_SEVERITY); } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/RuleMapper.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/RuleMapper.java new file mode 100644 index 00000000000..8dfeccc2b1c --- /dev/null +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/RuleMapper.java @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.scanner.externalissue.sarif; + +import javax.annotation.Nullable; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.rule.NewAdHocRule; +import org.sonar.api.scanner.ScannerSide; +import org.sonar.core.sarif.Rule; + +import static java.lang.String.join; + +@ScannerSide +public class RuleMapper { + + private final SensorContext sensorContext; + + public RuleMapper(SensorContext sensorContext) { + this.sensorContext = sensorContext; + } + + NewAdHocRule mapRule(Rule rule, String driverName, @Nullable String ruleSeverity, @Nullable String ruleSeverityForNewTaxonomy) { + return sensorContext.newAdHocRule() + .severity(ResultMapper.toSonarQubeSeverity(ruleSeverity)) + .type(ResultMapper.DEFAULT_TYPE) + .ruleId(rule.getId()) + .engineId(driverName) + .name(join(":", driverName, rule.getId())) + .cleanCodeAttribute(ResultMapper.DEFAULT_CLEAN_CODE_ATTRIBUTE) + .addDefaultImpact(ResultMapper.DEFAULT_SOFTWARE_QUALITY, ResultMapper.toSonarQubeImpactSeverity(ruleSeverityForNewTaxonomy)); + } +} diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/RulesSeverityDetector.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/RulesSeverityDetector.java index 10141fd8215..e026e795722 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/RulesSeverityDetector.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/RulesSeverityDetector.java @@ -26,7 +26,6 @@ import java.util.Optional; import java.util.Set; import java.util.function.Predicate; import javax.annotation.Nullable; -import org.sonar.api.batch.rule.Severity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.core.sarif.DefaultConfiguration; @@ -36,15 +35,15 @@ import org.sonar.core.sarif.Rule; import org.sonar.core.sarif.Run; import org.sonar.core.sarif.Tool; -import static java.lang.String.format; import static java.util.Collections.emptyMap; import static java.util.Collections.emptySet; import static java.util.stream.Collectors.toMap; +import static org.sonar.scanner.externalissue.sarif.ResultMapper.DEFAULT_IMPACT_SEVERITY; import static org.sonar.scanner.externalissue.sarif.ResultMapper.DEFAULT_SEVERITY; public class RulesSeverityDetector { private static final Logger LOG = LoggerFactory.getLogger(RulesSeverityDetector.class); - public static final String UNSUPPORTED_RULE_SEVERITIES_WARNING = "Unable to detect rules severity for issue detected by tool %s, falling back to default rule severity: %s"; + private static final String UNSUPPORTED_RULE_SEVERITIES_WARNING = "Unable to detect rules severity for issue detected by tool {}, falling back to default rule severity: {}"; private RulesSeverityDetector() {} @@ -67,7 +66,24 @@ public class RulesSeverityDetector { return extensionDefinedRuleSeverities; } - LOG.warn(composeUnsupportedRuleSeveritiesDefinitionWarningMessage(driverName, DEFAULT_SEVERITY)); + LOG.warn(UNSUPPORTED_RULE_SEVERITIES_WARNING, driverName, DEFAULT_SEVERITY.name()); + return emptyMap(); + } + + public static Map<String, String> detectRulesSeveritiesForNewTaxonomy(Run run, String driverName) { + Map<String, String> driverDefinedRuleSeverities = getDriverDefinedRuleSeverities(run); + + if (!driverDefinedRuleSeverities.isEmpty()) { + return driverDefinedRuleSeverities; + } + + Map<String, String> extensionDefinedRuleSeverities = getExtensionsDefinedRuleSeverities(run); + + if (!extensionDefinedRuleSeverities.isEmpty()) { + return extensionDefinedRuleSeverities; + } + + LOG.warn(UNSUPPORTED_RULE_SEVERITIES_WARNING, driverName, DEFAULT_IMPACT_SEVERITY.name()); return emptyMap(); } @@ -111,7 +127,4 @@ public class RulesSeverityDetector { .isPresent(); } - private static String composeUnsupportedRuleSeveritiesDefinitionWarningMessage(String driverName, Severity defaultSeverity) { - return format(UNSUPPORTED_RULE_SEVERITIES_WARNING, driverName, defaultSeverity); - } } diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/RunMapper.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/RunMapper.java index 6131daa1763..b711648d658 100644 --- a/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/RunMapper.java +++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/externalissue/sarif/RunMapper.java @@ -22,43 +22,51 @@ package org.sonar.scanner.externalissue.sarif; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; +import java.util.stream.Stream; import javax.annotation.Nullable; -import org.sonar.api.batch.sensor.issue.NewExternalIssue; -import org.sonar.api.scanner.ScannerSide; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.sonar.api.batch.sensor.issue.NewExternalIssue; +import org.sonar.api.batch.sensor.rule.NewAdHocRule; +import org.sonar.api.scanner.ScannerSide; import org.sonar.core.sarif.Driver; import org.sonar.core.sarif.Result; +import org.sonar.core.sarif.Rule; import org.sonar.core.sarif.Run; import org.sonar.core.sarif.Tool; import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toSet; import static org.sonar.api.utils.Preconditions.checkArgument; +import static org.sonar.scanner.externalissue.sarif.RulesSeverityDetector.detectRulesSeverities; +import static org.sonar.scanner.externalissue.sarif.RulesSeverityDetector.detectRulesSeveritiesForNewTaxonomy; @ScannerSide public class RunMapper { private static final Logger LOG = LoggerFactory.getLogger(RunMapper.class); private final ResultMapper resultMapper; + private final RuleMapper ruleMapper; - RunMapper(ResultMapper resultMapper) { + RunMapper(ResultMapper resultMapper, RuleMapper ruleMapper) { this.resultMapper = resultMapper; + this.ruleMapper = ruleMapper; } - List<NewExternalIssue> mapRun(Run run) { + RunMapperResult mapRun(Run run) { if (run.getResults().isEmpty()) { - return emptyList(); + return new RunMapperResult(); } + String driverName = getToolDriverName(run); - Map<String, String> ruleSeveritiesByRuleId = RulesSeverityDetector.detectRulesSeverities(run, driverName); + Map<String, String> ruleSeveritiesByRuleId = detectRulesSeverities(run, driverName); + Map<String, String> ruleSeveritiesByRuleIdForNewCCT = detectRulesSeveritiesForNewTaxonomy(run, driverName); - return run.getResults() - .stream() - .map(result -> toNewExternalIssue(driverName, ruleSeveritiesByRuleId.get(result.getRuleId()), result)) - .filter(Optional::isPresent) - .map(Optional::get) - .collect(toList()); + return new RunMapperResult() + .newAdHocRules(toNewAdHocRules(run, driverName, ruleSeveritiesByRuleId, ruleSeveritiesByRuleIdForNewCCT)) + .newExternalIssues(toNewExternalIssues(run, driverName, ruleSeveritiesByRuleId, ruleSeveritiesByRuleIdForNewCCT)); } private static String getToolDriverName(Run run) throws IllegalArgumentException { @@ -66,20 +74,84 @@ public class RunMapper { return run.getTool().getDriver().getName(); } - private Optional<NewExternalIssue> toNewExternalIssue(String driverName, @Nullable String ruleSeverity, Result result) { + private static boolean hasToolDriverNameDefined(Run run) { + return Optional.ofNullable(run) + .map(Run::getTool) + .map(Tool::getDriver) + .map(Driver::getName) + .isPresent(); + } + + private List<NewAdHocRule> toNewAdHocRules(Run run, String driverName, Map<String, String> ruleSeveritiesByRuleId, Map<String, String> ruleSeveritiesByRuleIdForNewCCT) { + Set<Rule> driverRules = run.getTool().getDriver().getRules(); + Set<Rule> extensionRules = hasExtensions(run.getTool()) + ? run.getTool().getExtensions().stream().flatMap(extension -> extension.getRules().stream()).collect(toSet()) + : Set.of(); + return Stream.concat(driverRules.stream(), extensionRules.stream()) + .distinct() + .map(rule -> ruleMapper.mapRule(rule, driverName, ruleSeveritiesByRuleId.get(rule.getId()), ruleSeveritiesByRuleIdForNewCCT.get(rule.getId()))) + .collect(toList()); + } + + private static boolean hasExtensions(Tool tool) { + return tool.getExtensions() != null && !tool.getExtensions().isEmpty(); + } + + private List<NewExternalIssue> toNewExternalIssues(Run run, String driverName, Map<String, String> ruleSeveritiesByRuleId, Map<String, String> ruleSeveritiesByRuleIdForNewCCT) { + return run.getResults() + .stream() + .map(result -> toNewExternalIssue(driverName, ruleSeveritiesByRuleId.get(result.getRuleId()), ruleSeveritiesByRuleIdForNewCCT.get(result.getRuleId()), result)) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(toList()); + } + + private Optional<NewExternalIssue> toNewExternalIssue(String driverName, @Nullable String ruleSeverity, @Nullable String ruleSeverityForNewTaxonomy, Result result) { try { - return Optional.of(resultMapper.mapResult(driverName, ruleSeverity, result)); + return Optional.of(resultMapper.mapResult(driverName, ruleSeverity, ruleSeverityForNewTaxonomy, result)); } catch (Exception exception) { LOG.warn("Failed to import an issue raised by tool {}, error: {}", driverName, exception.getMessage()); return Optional.empty(); } } - private static boolean hasToolDriverNameDefined(Run run) { - return Optional.ofNullable(run) - .map(Run::getTool) - .map(Tool::getDriver) - .map(Driver::getName) - .isPresent(); + static class RunMapperResult { + private List<NewExternalIssue> newExternalIssues; + private List<NewAdHocRule> newAdHocRules; + private boolean success; + + public RunMapperResult() { + this.newExternalIssues = emptyList(); + this.newAdHocRules = emptyList(); + this.success = true; + } + + public RunMapperResult newExternalIssues(List<NewExternalIssue> newExternalIssues) { + this.newExternalIssues = newExternalIssues; + return this; + } + + public RunMapperResult newAdHocRules(List<NewAdHocRule> newAdHocRules) { + this.newAdHocRules = newAdHocRules; + return this; + } + + public RunMapperResult success(boolean success) { + this.success = success; + return this; + } + + public List<NewExternalIssue> getNewExternalIssues() { + return newExternalIssues; + } + + public List<NewAdHocRule> getNewAdHocRules() { + return newAdHocRules; + } + + public boolean isSuccess() { + return success; + } } + } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/DefaultSarif210ImporterTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/DefaultSarif210ImporterTest.java index e8cf14b5adb..2a7658e870f 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/DefaultSarif210ImporterTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/DefaultSarif210ImporterTest.java @@ -33,6 +33,7 @@ import org.sonar.api.batch.sensor.issue.NewExternalIssue; import org.sonar.api.testfixtures.log.LogTester; import org.sonar.core.sarif.Run; import org.sonar.core.sarif.Sarif210; +import org.sonar.scanner.externalissue.sarif.RunMapper.RunMapperResult; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatNullPointerException; @@ -64,8 +65,8 @@ public class DefaultSarif210ImporterTest extends TestCase { NewExternalIssue issue1run1 = mock(NewExternalIssue.class); NewExternalIssue issue2run1 = mock(NewExternalIssue.class); NewExternalIssue issue1run2 = mock(NewExternalIssue.class); - when(runMapper.mapRun(run1)).thenReturn(List.of(issue1run1, issue2run1)); - when(runMapper.mapRun(run2)).thenReturn(List.of(issue1run2)); + when(runMapper.mapRun(run1)).thenReturn(new RunMapperResult().newExternalIssues(List.of(issue1run1, issue2run1))); + when(runMapper.mapRun(run2)).thenReturn(new RunMapperResult().newExternalIssues(List.of(issue1run2))); SarifImportResults sarifImportResults = sarif210Importer.importSarif(sarif210); @@ -88,7 +89,7 @@ public class DefaultSarif210ImporterTest extends TestCase { Exception testException = new RuntimeException("test"); when(runMapper.mapRun(run1)).thenThrow(testException); NewExternalIssue issue1run2 = mock(NewExternalIssue.class); - when(runMapper.mapRun(run2)).thenReturn(List.of(issue1run2)); + when(runMapper.mapRun(run2)).thenReturn(new RunMapperResult().newExternalIssues(List.of(issue1run2))); SarifImportResults sarifImportResults = sarif210Importer.importSarif(sarif210); diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/ResultMapperTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/ResultMapperTest.java index 309a8ed9503..7b156de96c3 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/ResultMapperTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/ResultMapperTest.java @@ -44,7 +44,9 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static org.sonar.scanner.externalissue.sarif.ResultMapper.DEFAULT_IMPACT_SEVERITY; import static org.sonar.scanner.externalissue.sarif.ResultMapper.DEFAULT_SEVERITY; +import static org.sonar.scanner.externalissue.sarif.ResultMapper.DEFAULT_SOFTWARE_QUALITY; @RunWith(DataProviderRunner.class) public class ResultMapperTest { @@ -84,7 +86,7 @@ public class ResultMapperTest { @Test public void mapResult_mapsSimpleFieldsCorrectly() { - NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, result); + NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result); verify(newExternalIssue).type(RuleType.VULNERABILITY); verify(newExternalIssue).engineId(DRIVER_NAME); @@ -96,7 +98,7 @@ public class ResultMapperTest { public void mapResult_ifRuleIdMissing_fails() { when(result.getRuleId()).thenReturn(null); assertThatNullPointerException() - .isThrownBy(() -> resultMapper.mapResult(DRIVER_NAME, WARNING, result)) + .isThrownBy(() -> resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result)) .withMessage("No ruleId found for issue thrown by driver driverName"); } @@ -105,7 +107,7 @@ public class ResultMapperTest { Location location = mock(Location.class); when(result.getLocations()).thenReturn(Set.of(location)); - NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, result); + NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result); verify(locationMapper).fillIssueInFileLocation(result, newExternalIssueLocation, location); verifyNoMoreInteractions(locationMapper); @@ -120,7 +122,7 @@ public class ResultMapperTest { when(result.getLocations()).thenReturn(Set.of(location)); when(locationMapper.fillIssueInFileLocation(any(), any(), any())).thenReturn(null); - NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, result); + NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result); verify(locationMapper).fillIssueInProjectLocation(result, newExternalIssueLocation); verify(newExternalIssue).at(newExternalIssueLocation); @@ -130,7 +132,7 @@ public class ResultMapperTest { @Test public void mapResult_whenLocationsIsEmpty_createsProjectLocation() { - NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, result); + NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result); verify(locationMapper).fillIssueInProjectLocation(result, newExternalIssueLocation); verifyNoMoreInteractions(locationMapper); @@ -142,7 +144,7 @@ public class ResultMapperTest { @Test public void mapResult_whenLocationsIsNull_createsProjectLocation() { when(result.getLocations()).thenReturn(null); - NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, result); + NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result); verify(locationMapper).fillIssueInProjectLocation(result, newExternalIssueLocation); verifyNoMoreInteractions(locationMapper); @@ -151,29 +153,30 @@ public class ResultMapperTest { verify(newExternalIssue, never()).addFlow(any()); } - @Test - public void mapResult_mapsErrorLevel_toCriticalSeverity() { - NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, ERROR, result); - verify(newExternalIssue).severity(Severity.CRITICAL); - } - @DataProvider public static Object[][] rule_severity_to_sonarqube_severity_mapping() { return new Object[][] { - {"error", Severity.CRITICAL}, - {"warning", Severity.MAJOR}, - {"note", Severity.MINOR}, - {"none", Severity.INFO}, - {"anything else", DEFAULT_SEVERITY}, - {null, DEFAULT_SEVERITY}, + {"error", Severity.CRITICAL, org.sonar.api.issue.impact.Severity.HIGH}, + {"warning", Severity.MAJOR, org.sonar.api.issue.impact.Severity.MEDIUM}, + {"note", Severity.MINOR, org.sonar.api.issue.impact.Severity.LOW}, + {"none", Severity.INFO, org.sonar.api.issue.impact.Severity.LOW}, + {"anything else", DEFAULT_SEVERITY, DEFAULT_IMPACT_SEVERITY}, + {null, DEFAULT_SEVERITY, DEFAULT_IMPACT_SEVERITY}, }; } @Test @UseDataProvider("rule_severity_to_sonarqube_severity_mapping") - public void mapResult_mapsCorrectlyLevelToSeverity(String ruleSeverity, Severity sonarQubeSeverity) { - NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, ruleSeverity, result); + public void mapResult_mapsCorrectlyLevelToSeverity(String ruleSeverity, Severity sonarQubeSeverity, org.sonar.api.issue.impact.Severity impactSeverity) { + NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, ruleSeverity, ruleSeverity, result); verify(newExternalIssue).severity(sonarQubeSeverity); + verify(newExternalIssue).addImpact(DEFAULT_SOFTWARE_QUALITY, impactSeverity); + } + + @Test + public void mapResult_mapsCorrectlyCleanCodeAttribute() { + NewExternalIssue newExternalIssue = resultMapper.mapResult(DRIVER_NAME, WARNING, WARNING, result); + verify(newExternalIssue).cleanCodeAttribute(ResultMapper.DEFAULT_CLEAN_CODE_ATTRIBUTE); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/RuleMapperTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/RuleMapperTest.java new file mode 100644 index 00000000000..b42c5011d9a --- /dev/null +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/RuleMapperTest.java @@ -0,0 +1,73 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.scanner.externalissue.sarif; + +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.rule.NewAdHocRule; +import org.sonar.api.batch.sensor.rule.internal.DefaultAdHocRule; +import org.sonar.core.sarif.Rule; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +@RunWith(DataProviderRunner.class) +public class RuleMapperTest { + + private static final String WARNING = "warning"; + private static final String RULE_ID = "test_rules_id"; + private static final String DRIVER_NAME = "driverName"; + + @Mock + private SensorContext sensorContext; + + @InjectMocks + RuleMapper ruleMapper; + + @Before + public void setUp() { + MockitoAnnotations.openMocks(this); + when(sensorContext.newAdHocRule()).thenReturn(new DefaultAdHocRule()); + } + + @Test + public void mapRule_shouldCorrectlyMapToNewAdHocRule() { + Rule rule = Rule.builder().id(RULE_ID).build(); + NewAdHocRule expected = new DefaultAdHocRule() + .severity(ResultMapper.DEFAULT_SEVERITY) + .type(ResultMapper.DEFAULT_TYPE) + .ruleId(RULE_ID) + .engineId(DRIVER_NAME) + .name(String.join(":", DRIVER_NAME, RULE_ID)) + .cleanCodeAttribute(ResultMapper.DEFAULT_CLEAN_CODE_ATTRIBUTE) + .addDefaultImpact(ResultMapper.DEFAULT_SOFTWARE_QUALITY, org.sonar.api.issue.impact.Severity.MEDIUM); + + NewAdHocRule result = ruleMapper.mapRule(rule, DRIVER_NAME, WARNING, WARNING); + + assertThat(result).usingRecursiveComparison().isEqualTo(expected); + } + +} diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/RulesSeverityDetectorTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/RulesSeverityDetectorTest.java index a06e2324ff5..01398ce62d5 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/RulesSeverityDetectorTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/RulesSeverityDetectorTest.java @@ -23,11 +23,10 @@ import java.util.Map; import java.util.Set; import org.assertj.core.api.Assertions; import org.assertj.core.groups.Tuple; +import org.junit.Before; import org.junit.Test; import org.slf4j.event.Level; -import org.sonar.api.batch.rule.Severity; import org.sonar.api.testfixtures.log.LogTester; -import org.sonar.api.utils.log.LoggerLevel; import org.sonar.core.sarif.DefaultConfiguration; import org.sonar.core.sarif.Driver; import org.sonar.core.sarif.Extension; @@ -41,8 +40,8 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.tuple; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.sonar.scanner.externalissue.sarif.ResultMapper.DEFAULT_IMPACT_SEVERITY; import static org.sonar.scanner.externalissue.sarif.ResultMapper.DEFAULT_SEVERITY; -import static org.sonar.scanner.externalissue.sarif.RulesSeverityDetector.UNSUPPORTED_RULE_SEVERITIES_WARNING; public class RulesSeverityDetectorTest { private static final String DRIVER_NAME = "Test"; @@ -50,7 +49,7 @@ public class RulesSeverityDetectorTest { private static final String RULE_ID = "RULE_ID"; @org.junit.Rule - public LogTester logTester = new LogTester().setLevel(LoggerLevel.TRACE); + public LogTester logTester = new LogTester().setLevel(Level.TRACE); private final Run run = mock(Run.class); private final Rule rule = mock(Rule.class); @@ -60,6 +59,14 @@ public class RulesSeverityDetectorTest { private final Extension extension = mock(Extension.class); private final DefaultConfiguration defaultConfiguration = mock(DefaultConfiguration.class); + @Before + public void setUp() { + when(run.getResults()).thenReturn(Set.of(result)); + when(run.getTool()).thenReturn(tool); + when(tool.getDriver()).thenReturn(driver); + } + + // We keep this test for backward compatibility until we remove the deprecated severity @Test public void detectRulesSeverities_detectsCorrectlyResultDefinedRuleSeverities() { Run run = mockResultDefinedRuleSeverities(); @@ -71,10 +78,26 @@ public class RulesSeverityDetectorTest { } @Test + public void detectRulesSeveritiesForNewTaxonomy_shouldReturnsEmptyMapAndLogsWarning_whenOnlyResultDefinedRuleSeverities() { + Run run = mockResultDefinedRuleSeverities(); + + Map<String, String> rulesSeveritiesByRuleId = RulesSeverityDetector.detectRulesSeveritiesForNewTaxonomy(run, DRIVER_NAME); + + assertWarningLog(DEFAULT_IMPACT_SEVERITY.name()); + assertDetectedRuleSeverities(rulesSeveritiesByRuleId); + } + + @Test public void detectRulesSeverities_detectsCorrectlyDriverDefinedRuleSeverities() { Run run = mockDriverDefinedRuleSeverities(); - Map<String, String> rulesSeveritiesByRuleId = RulesSeverityDetector.detectRulesSeverities(run, DRIVER_NAME); + Map<String, String> rulesSeveritiesByRuleId = RulesSeverityDetector.detectRulesSeveritiesForNewTaxonomy(run, DRIVER_NAME); + + assertNoLogs(); + assertDetectedRuleSeverities(rulesSeveritiesByRuleId, tuple(RULE_ID, WARNING)); + + // We keep this below for backward compatibility until we remove the deprecated severity + rulesSeveritiesByRuleId = RulesSeverityDetector.detectRulesSeverities(run, DRIVER_NAME); assertNoLogs(); assertDetectedRuleSeverities(rulesSeveritiesByRuleId, tuple(RULE_ID, WARNING)); @@ -84,7 +107,13 @@ public class RulesSeverityDetectorTest { public void detectRulesSeverities_detectsCorrectlyExtensionsDefinedRuleSeverities() { Run run = mockExtensionsDefinedRuleSeverities(); - Map<String, String> rulesSeveritiesByRuleId = RulesSeverityDetector.detectRulesSeverities(run, DRIVER_NAME); + Map<String, String> rulesSeveritiesByRuleId = RulesSeverityDetector.detectRulesSeveritiesForNewTaxonomy(run, DRIVER_NAME); + + assertNoLogs(); + assertDetectedRuleSeverities(rulesSeveritiesByRuleId, tuple(RULE_ID, WARNING)); + + // We keep this below for backward compatibility until we remove the deprecated severity + rulesSeveritiesByRuleId = RulesSeverityDetector.detectRulesSeverities(run, DRIVER_NAME); assertNoLogs(); assertDetectedRuleSeverities(rulesSeveritiesByRuleId, tuple(RULE_ID, WARNING)); @@ -94,9 +123,15 @@ public class RulesSeverityDetectorTest { public void detectRulesSeverities_returnsEmptyMapAndLogsWarning_whenUnableToDetectSeverities() { Run run = mockUnsupportedRuleSeveritiesDefinition(); - Map<String, String> rulesSeveritiesByRuleId = RulesSeverityDetector.detectRulesSeverities(run, DRIVER_NAME); + Map<String, String> rulesSeveritiesByRuleId = RulesSeverityDetector.detectRulesSeveritiesForNewTaxonomy(run, DRIVER_NAME); + + assertWarningLog(DEFAULT_IMPACT_SEVERITY.name()); + assertDetectedRuleSeverities(rulesSeveritiesByRuleId); + + // We keep this below for backward compatibility until we remove the deprecated severity + rulesSeveritiesByRuleId = RulesSeverityDetector.detectRulesSeverities(run, DRIVER_NAME); - assertWarningLog(DRIVER_NAME, DEFAULT_SEVERITY); + assertWarningLog(DEFAULT_SEVERITY.name()); assertDetectedRuleSeverities(rulesSeveritiesByRuleId); } @@ -104,31 +139,24 @@ public class RulesSeverityDetectorTest { when(run.getResults()).thenReturn(Set.of(result)); when(result.getLevel()).thenReturn(WARNING); when(result.getRuleId()).thenReturn(RULE_ID); - return run; } private Run mockDriverDefinedRuleSeverities() { - when(run.getTool()).thenReturn(tool); - when(tool.getDriver()).thenReturn(driver); when(driver.getRules()).thenReturn(Set.of(rule)); when(rule.getId()).thenReturn(RULE_ID); when(rule.getDefaultConfiguration()).thenReturn(defaultConfiguration); when(defaultConfiguration.getLevel()).thenReturn(WARNING); - return run; } private Run mockExtensionsDefinedRuleSeverities() { - when(run.getTool()).thenReturn(tool); - when(tool.getDriver()).thenReturn(driver); when(driver.getRules()).thenReturn(Set.of()); when(tool.getExtensions()).thenReturn(Set.of(extension)); when(extension.getRules()).thenReturn(Set.of(rule)); when(rule.getId()).thenReturn(RULE_ID); when(rule.getDefaultConfiguration()).thenReturn(defaultConfiguration); when(defaultConfiguration.getLevel()).thenReturn(WARNING); - return run; } @@ -138,7 +166,6 @@ public class RulesSeverityDetectorTest { when(driver.getRules()).thenReturn(Set.of()); when(tool.getExtensions()).thenReturn(Set.of(extension)); when(extension.getRules()).thenReturn(Set.of()); - return run; } @@ -152,10 +179,9 @@ public class RulesSeverityDetectorTest { .containsExactly(expectedSeverities); } - private void assertWarningLog(String driverName, Severity defaultSeverity) { - assertThat(logTester.logs()).hasSize(1); + private void assertWarningLog(String defaultSeverity) { assertThat(logTester.logs(Level.WARN)) - .containsOnly(format(UNSUPPORTED_RULE_SEVERITIES_WARNING, driverName, defaultSeverity)); + .contains(format("Unable to detect rules severity for issue detected by tool %s, falling back to default rule severity: %s", DRIVER_NAME, defaultSeverity)); } } diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/RunMapperTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/RunMapperTest.java index 6146886d1fe..ce0068d9342 100644 --- a/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/RunMapperTest.java +++ b/sonar-scanner-engine/src/test/java/org/sonar/scanner/externalissue/sarif/RunMapperTest.java @@ -19,9 +19,9 @@ */ package org.sonar.scanner.externalissue.sarif; -import java.util.List; import java.util.Map; import java.util.Set; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,9 +32,12 @@ import org.mockito.MockedStatic; import org.mockito.junit.MockitoJUnitRunner; import org.slf4j.event.Level; import org.sonar.api.batch.sensor.issue.NewExternalIssue; +import org.sonar.api.batch.sensor.rule.NewAdHocRule; import org.sonar.api.testfixtures.log.LogTester; +import org.sonar.core.sarif.Extension; import org.sonar.core.sarif.Result; import org.sonar.core.sarif.Run; +import org.sonar.scanner.externalissue.sarif.RunMapper.RunMapperResult; import static java.util.Collections.emptySet; import static org.assertj.core.api.Assertions.assertThat; @@ -52,30 +55,78 @@ public class RunMapperTest { @Mock private ResultMapper resultMapper; + @Mock + private RuleMapper ruleMapper; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Run run; + @Mock + private org.sonar.core.sarif.Rule rule; + @Rule public LogTester logTester = new LogTester(); @InjectMocks private RunMapper runMapper; - @Test - public void mapRun_delegatesToMapResult() { + @Before + public void setUp() { when(run.getTool().getDriver().getName()).thenReturn(TEST_DRIVER); + when(run.getTool().getExtensions()).thenReturn(null); + when(rule.getId()).thenReturn(RULE_ID); + } + + @Test + public void mapRun_shouldMapExternalIssues() { Result result1 = mock(Result.class); Result result2 = mock(Result.class); when(run.getResults()).thenReturn(Set.of(result1, result2)); - NewExternalIssue externalIssue1 = mockMappedResult(result1); - NewExternalIssue externalIssue2 = mockMappedResult(result2); + NewExternalIssue externalIssue1 = mockMappedExternalIssue(result1); + NewExternalIssue externalIssue2 = mockMappedExternalIssue(result2); try (MockedStatic<RulesSeverityDetector> detector = mockStatic(RulesSeverityDetector.class)) { detector.when(() -> RulesSeverityDetector.detectRulesSeverities(run, TEST_DRIVER)).thenReturn(Map.of(RULE_ID, WARNING)); + detector.when(() -> RulesSeverityDetector.detectRulesSeveritiesForNewTaxonomy(run, TEST_DRIVER)).thenReturn(Map.of(RULE_ID, WARNING)); - List<NewExternalIssue> newExternalIssues = runMapper.mapRun(run); + RunMapperResult runMapperResult = runMapper.mapRun(run); - assertThat(newExternalIssues).containsOnly(externalIssue1, externalIssue2); + assertThat(runMapperResult.getNewExternalIssues()).containsOnly(externalIssue1, externalIssue2); + assertThat(logTester.logs()).isEmpty(); + } + } + + @Test + public void mapRun_shouldMapExternalRules_whenDriverHasRulesAndNoExtensions() { + when(run.getTool().getDriver().getRules()).thenReturn(Set.of(rule)); + NewAdHocRule externalRule = mockMappedExternalRule(); + + try (MockedStatic<RulesSeverityDetector> detector = mockStatic(RulesSeverityDetector.class)) { + detector.when(() -> RulesSeverityDetector.detectRulesSeverities(run, TEST_DRIVER)).thenReturn(Map.of(RULE_ID, WARNING)); + detector.when(() -> RulesSeverityDetector.detectRulesSeveritiesForNewTaxonomy(run, TEST_DRIVER)).thenReturn(Map.of(RULE_ID, WARNING)); + + RunMapperResult runMapperResult = runMapper.mapRun(run); + + assertThat(runMapperResult.getNewAdHocRules()).containsOnly(externalRule); + assertThat(logTester.logs()).isEmpty(); + } + } + + @Test + public void mapRun_shouldMapExternalRules_whenRulesInExtensions() { + when(run.getTool().getDriver().getRules()).thenReturn(Set.of()); + Extension extension = mock(Extension.class); + when(extension.getRules()).thenReturn(Set.of(rule)); + when(run.getTool().getExtensions()).thenReturn(Set.of(extension)); + NewAdHocRule externalRule = mockMappedExternalRule(); + + try (MockedStatic<RulesSeverityDetector> detector = mockStatic(RulesSeverityDetector.class)) { + detector.when(() -> RulesSeverityDetector.detectRulesSeverities(run, TEST_DRIVER)).thenReturn(Map.of(RULE_ID, WARNING)); + detector.when(() -> RulesSeverityDetector.detectRulesSeveritiesForNewTaxonomy(run, TEST_DRIVER)).thenReturn(Map.of(RULE_ID, WARNING)); + + RunMapperResult runMapperResult = runMapper.mapRun(run); + + assertThat(runMapperResult.getNewAdHocRules()).containsOnly(externalRule); assertThat(logTester.logs()).isEmpty(); } } @@ -84,27 +135,27 @@ public class RunMapperTest { public void mapRun_ifRunIsEmpty_returnsEmptyList() { when(run.getResults()).thenReturn(emptySet()); - List<NewExternalIssue> newExternalIssues = runMapper.mapRun(run); + RunMapperResult runMapperResult = runMapper.mapRun(run); - assertThat(newExternalIssues).isEmpty(); + assertThat(runMapperResult.getNewExternalIssues()).isEmpty(); } @Test public void mapRun_ifExceptionThrownByResultMapper_logsThemAndContinueProcessing() { - when(run.getTool().getDriver().getName()).thenReturn(TEST_DRIVER); Result result1 = mock(Result.class); Result result2 = mock(Result.class); when(run.getResults()).thenReturn(Set.of(result1, result2)); - NewExternalIssue externalIssue2 = mockMappedResult(result2); + NewExternalIssue externalIssue2 = mockMappedExternalIssue(result2); when(result1.getRuleId()).thenReturn(RULE_ID); - when(resultMapper.mapResult(TEST_DRIVER, WARNING, result1)).thenThrow(new IllegalArgumentException("test")); + when(resultMapper.mapResult(TEST_DRIVER, WARNING, WARNING, result1)).thenThrow(new IllegalArgumentException("test")); try (MockedStatic<RulesSeverityDetector> detector = mockStatic(RulesSeverityDetector.class)) { detector.when(() -> RulesSeverityDetector.detectRulesSeverities(run, TEST_DRIVER)).thenReturn(Map.of(RULE_ID, WARNING)); + detector.when(() -> RulesSeverityDetector.detectRulesSeveritiesForNewTaxonomy(run, TEST_DRIVER)).thenReturn(Map.of(RULE_ID, WARNING)); - List<NewExternalIssue> newExternalIssues = runMapper.mapRun(run); + RunMapperResult runMapperResult = runMapper.mapRun(run); - assertThat(newExternalIssues) + assertThat(runMapperResult.getNewExternalIssues()) .containsExactly(externalIssue2); assertThat(logTester.logs(Level.WARN)).containsOnly("Failed to import an issue raised by tool Test driver, error: test"); } @@ -137,11 +188,17 @@ public class RunMapperTest { .withMessage("The run does not have a tool driver name defined."); } - private NewExternalIssue mockMappedResult(Result result) { + private NewExternalIssue mockMappedExternalIssue(Result result) { NewExternalIssue externalIssue = mock(NewExternalIssue.class); when(result.getRuleId()).thenReturn(RULE_ID); - when(resultMapper.mapResult(TEST_DRIVER, WARNING, result)).thenReturn(externalIssue); + when(resultMapper.mapResult(TEST_DRIVER, WARNING, WARNING, result)).thenReturn(externalIssue); return externalIssue; } + private NewAdHocRule mockMappedExternalRule() { + NewAdHocRule externalRule = mock(NewAdHocRule.class); + when(ruleMapper.mapRule(rule, TEST_DRIVER, WARNING, WARNING)).thenReturn(externalRule); + return externalRule; + } + } |