diff options
author | Dejan Milisavljevic <dejan.milisavljevic@sonarsource.com> | 2024-03-18 11:09:18 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-03-25 20:02:42 +0000 |
commit | 494316d9f27f7a64b762e37d4f8bc34e4b4370d7 (patch) | |
tree | 99614caafba41b900439722a96483c1b7a9b0421 /server/sonar-ce-task-projectanalysis | |
parent | d4518aca0c74114be84a81b9958027255453628d (diff) | |
download | sonarqube-494316d9f27f7a64b762e37d4f8bc34e4b4370d7.tar.gz sonarqube-494316d9f27f7a64b762e37d4f8bc34e4b4370d7.zip |
SONAR-21770 Accept new metrics 'new_maintainability_issues', 'new_reliability_issues', 'new_security_issues'
Diffstat (limited to 'server/sonar-ce-task-projectanalysis')
2 files changed, 104 insertions, 42 deletions
diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueCounter.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueCounter.java index b2b8f2cd0e7..f2e4de123ad 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueCounter.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/issue/IssueCounter.java @@ -50,7 +50,7 @@ import static org.sonar.api.measures.CoreMetrics.CRITICAL_VIOLATIONS_KEY; import static org.sonar.api.measures.CoreMetrics.FALSE_POSITIVE_ISSUES_KEY; import static org.sonar.api.measures.CoreMetrics.HIGH_IMPACT_ACCEPTED_ISSUES_KEY; import static org.sonar.api.measures.CoreMetrics.INFO_VIOLATIONS_KEY; -import static org.sonar.api.measures.CoreMetrics.MAINTAINABILITY_ISSUES; +import static org.sonar.api.measures.CoreMetrics.MAINTAINABILITY_ISSUES_KEY; import static org.sonar.api.measures.CoreMetrics.MAJOR_VIOLATIONS_KEY; import static org.sonar.api.measures.CoreMetrics.MINOR_VIOLATIONS_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_ACCEPTED_ISSUES_KEY; @@ -59,16 +59,19 @@ import static org.sonar.api.measures.CoreMetrics.NEW_BUGS_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_CODE_SMELLS_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_CRITICAL_VIOLATIONS_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_INFO_VIOLATIONS_KEY; +import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_ISSUES_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_MAJOR_VIOLATIONS_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_MINOR_VIOLATIONS_KEY; +import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_ISSUES_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_KEY; +import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_ISSUES_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_VULNERABILITIES_KEY; import static org.sonar.api.measures.CoreMetrics.OPEN_ISSUES_KEY; -import static org.sonar.api.measures.CoreMetrics.RELIABILITY_ISSUES; +import static org.sonar.api.measures.CoreMetrics.RELIABILITY_ISSUES_KEY; import static org.sonar.api.measures.CoreMetrics.REOPENED_ISSUES_KEY; import static org.sonar.api.measures.CoreMetrics.SECURITY_HOTSPOTS_KEY; -import static org.sonar.api.measures.CoreMetrics.SECURITY_ISSUES; +import static org.sonar.api.measures.CoreMetrics.SECURITY_ISSUES_KEY; import static org.sonar.api.measures.CoreMetrics.VIOLATIONS_KEY; import static org.sonar.api.measures.CoreMetrics.VULNERABILITIES_KEY; import static org.sonar.api.rule.Severity.BLOCKER; @@ -109,9 +112,14 @@ public class IssueCounter extends IssueVisitor { INFO, NEW_INFO_VIOLATIONS_KEY); static final Map<String, String> IMPACT_TO_METRIC_KEY = Map.of( - SoftwareQuality.SECURITY.name(), SECURITY_ISSUES.key(), - SoftwareQuality.RELIABILITY.name(), RELIABILITY_ISSUES.key(), - SoftwareQuality.MAINTAINABILITY.name(), MAINTAINABILITY_ISSUES.key()); + SoftwareQuality.SECURITY.name(), SECURITY_ISSUES_KEY, + SoftwareQuality.RELIABILITY.name(), RELIABILITY_ISSUES_KEY, + SoftwareQuality.MAINTAINABILITY.name(), MAINTAINABILITY_ISSUES_KEY); + + static final Map<String, String> IMPACT_TO_NEW_METRIC_KEY = Map.of( + SoftwareQuality.SECURITY.name(), NEW_SECURITY_ISSUES_KEY, + SoftwareQuality.RELIABILITY.name(), NEW_RELIABILITY_ISSUES_KEY, + SoftwareQuality.MAINTAINABILITY.name(), NEW_MAINTAINABILITY_ISSUES_KEY); private static final Map<RuleType, String> TYPE_TO_METRIC_KEY = ImmutableMap.<RuleType, String>builder() .put(CODE_SMELL, CODE_SMELLS_KEY) @@ -222,9 +230,7 @@ public class IssueCounter extends IssueVisitor { String severity = entry.getKey(); String metricKey = entry.getValue(); Multiset<String> bag = currentCounters.counterForPeriod().severityBag; - Metric metric = metricRepository.getByKey(metricKey); - measureRepository.add(component, metric, Measure.newMeasureBuilder() - .create(bag.count(severity))); + addMeasure(component, metricKey, bag.count(severity)); } // waiting for Java 8 lambda in order to factor this loop with the previous one @@ -233,9 +239,12 @@ public class IssueCounter extends IssueVisitor { RuleType type = entry.getKey(); String metricKey = entry.getValue(); Multiset<RuleType> bag = currentCounters.counterForPeriod().typeBag; - Metric metric = metricRepository.getByKey(metricKey); - measureRepository.add(component, metric, Measure.newMeasureBuilder() - .create(bag.count(type))); + addMeasure(component, metricKey, bag.count(type)); + } + + for (Map.Entry<String, Map<String, Long>> impactEntry : currentCounters.counterForPeriod().impactsBag.entrySet()) { + String json = ImpactMeasureBuilder.fromMap(impactEntry.getValue()).buildAsString(); + addMeasure(component, IMPACT_TO_NEW_METRIC_KEY.get(impactEntry.getKey()), json); } addMeasure(component, NEW_ACCEPTED_ISSUES_KEY, currentCounters.counterForPeriod().accepted); diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueCounterTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueCounterTest.java index 49d8ca5bd2f..7ad66ed9b40 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueCounterTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/issue/IssueCounterTest.java @@ -27,8 +27,8 @@ import java.util.Map; import java.util.Set; import javax.annotation.Nullable; import org.assertj.core.data.MapEntry; -import org.junit.Rule; -import org.junit.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; import org.sonar.api.issue.impact.Severity; import org.sonar.api.issue.impact.SoftwareQuality; import org.sonar.api.rules.RuleType; @@ -92,11 +92,14 @@ import static org.sonar.api.measures.CoreMetrics.NEW_CODE_SMELLS_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_CRITICAL_VIOLATIONS; import static org.sonar.api.measures.CoreMetrics.NEW_CRITICAL_VIOLATIONS_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_INFO_VIOLATIONS; +import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_ISSUES; import static org.sonar.api.measures.CoreMetrics.NEW_MAJOR_VIOLATIONS; import static org.sonar.api.measures.CoreMetrics.NEW_MAJOR_VIOLATIONS_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_MINOR_VIOLATIONS; +import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_ISSUES; import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS; import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_KEY; +import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_ISSUES; import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS; import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_VULNERABILITIES; @@ -120,24 +123,25 @@ import static org.sonar.api.rules.RuleType.CODE_SMELL; import static org.sonar.api.rules.RuleType.SECURITY_HOTSPOT; import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder; import static org.sonar.ce.task.projectanalysis.issue.IssueCounter.IMPACT_TO_METRIC_KEY; +import static org.sonar.ce.task.projectanalysis.issue.IssueCounter.IMPACT_TO_NEW_METRIC_KEY; import static org.sonar.ce.task.projectanalysis.measure.Measure.newMeasureBuilder; import static org.sonar.ce.task.projectanalysis.measure.MeasureRepoEntry.entryOf; -public class IssueCounterTest { +class IssueCounterTest { private static final Component FILE1 = builder(Component.Type.FILE, 1).build(); private static final Component FILE2 = builder(Component.Type.FILE, 2).build(); private static final Component FILE3 = builder(Component.Type.FILE, 3).build(); private static final Component PROJECT = builder(Component.Type.PROJECT, 4).addChildren(FILE1, FILE2, FILE3).build(); - @Rule - public BatchReportReaderRule reportReader = new BatchReportReaderRule(); + @RegisterExtension + private final BatchReportReaderRule reportReader = new BatchReportReaderRule(); - @Rule - public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); + @RegisterExtension + private final TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); - @Rule - public MetricRepositoryRule metricRepository = new MetricRepositoryRule() + @RegisterExtension + private final MetricRepositoryRule metricRepository = new MetricRepositoryRule() .add(VIOLATIONS) .add(OPEN_ISSUES) .add(REOPENED_ISSUES) @@ -167,15 +171,19 @@ public class IssueCounterTest { .add(HIGH_IMPACT_ACCEPTED_ISSUES) .add(RELIABILITY_ISSUES) .add(MAINTAINABILITY_ISSUES) - .add(SECURITY_ISSUES); + .add(SECURITY_ISSUES) + .add(NEW_RELIABILITY_ISSUES) + .add(NEW_MAINTAINABILITY_ISSUES) + .add(NEW_SECURITY_ISSUES); - @Rule - public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); - private NewIssueClassifier newIssueClassifier = mock(NewIssueClassifier.class); - private IssueCounter underTest = new IssueCounter(metricRepository, measureRepository, newIssueClassifier); + @RegisterExtension + private final MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); + private final NewIssueClassifier newIssueClassifier = mock(NewIssueClassifier.class); + private final IssueCounter underTest = new IssueCounter(metricRepository, measureRepository, newIssueClassifier); + private static int issueCounter; @Test - public void count_issues_by_status() { + void count_issues_by_status() { // bottom-up traversal -> from files to project underTest.beforeComponent(FILE1); underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER)); @@ -203,7 +211,7 @@ public class IssueCounterTest { } @Test - public void count_issues_by_resolution() { + void count_issues_by_resolution() { // bottom-up traversal -> from files to project underTest.beforeComponent(FILE1); underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER)); @@ -233,7 +241,7 @@ public class IssueCounterTest { } @Test - public void count_unresolved_issues_by_severity() { + void count_unresolved_issues_by_severity() { // bottom-up traversal -> from files to project underTest.beforeComponent(FILE1); underTest.onIssue(FILE1, createIssue(null, STATUS_OPEN, BLOCKER)); @@ -257,7 +265,7 @@ public class IssueCounterTest { } @Test - public void count_unresolved_issues_by_type() { + void count_unresolved_issues_by_type() { // bottom-up traversal -> from files to project // file1 : one open code smell, one closed code smell (which will be excluded from metric) underTest.beforeComponent(FILE1); @@ -286,7 +294,7 @@ public class IssueCounterTest { } @Test - public void count_new_issues() { + void count_new_issues() { when(newIssueClassifier.isEnabled()).thenReturn(true); underTest.beforeComponent(FILE1); @@ -315,7 +323,7 @@ public class IssueCounterTest { } @Test - public void count_new_accepted_issues() { + void count_new_accepted_issues() { when(newIssueClassifier.isEnabled()).thenReturn(true); underTest.beforeComponent(FILE1); @@ -338,7 +346,7 @@ public class IssueCounterTest { } @Test - public void count_impacts() { + void onIssue_shouldCountOverallSoftwareQualitiesMeasures() { when(newIssueClassifier.isEnabled()).thenReturn(true); underTest.beforeComponent(FILE1); @@ -360,9 +368,43 @@ public class IssueCounterTest { Set<Map.Entry<String, Measure>> entries = measureRepository.getRawMeasures(FILE1).entrySet(); - assertSoftwareQualityMeasures(SoftwareQuality.MAINTAINABILITY, getImpactMeasure(4, 2, 2, 0), entries); - assertSoftwareQualityMeasures(SoftwareQuality.SECURITY, getImpactMeasure(2, 1, 1, 0), entries); - assertSoftwareQualityMeasures(SoftwareQuality.RELIABILITY, getImpactMeasure(0, 0, 0, 0), entries); + assertOverallSoftwareQualityMeasures(SoftwareQuality.MAINTAINABILITY, getImpactMeasure(4, 2, 2, 0), entries); + assertOverallSoftwareQualityMeasures(SoftwareQuality.SECURITY, getImpactMeasure(2, 1, 1, 0), entries); + assertOverallSoftwareQualityMeasures(SoftwareQuality.RELIABILITY, getImpactMeasure(0, 0, 0, 0), entries); + } + + @Test + void onIssue_shouldCountNewSoftwareQualitiesMeasures() { + when(newIssueClassifier.isEnabled()).thenReturn(true); + + underTest.beforeComponent(FILE1); + underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, HIGH)); + underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, HIGH)); + underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, SoftwareQuality.MAINTAINABILITY, HIGH)); + underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.MAINTAINABILITY, MEDIUM)); + + underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.RELIABILITY, HIGH)); + underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.RELIABILITY, LOW)); + underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, SoftwareQuality.RELIABILITY, HIGH)); + underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.RELIABILITY, MEDIUM)); + + underTest.onIssue(FILE1, createIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, MEDIUM)); + underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, LOW)); + underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, HIGH)); + underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, HIGH)); + underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_RESOLVED, SoftwareQuality.SECURITY, HIGH)); + underTest.onIssue(FILE1, createNewIssue(RESOLUTION_WONT_FIX, STATUS_OPEN, SoftwareQuality.SECURITY, MEDIUM)); + + underTest.afterComponent(FILE1); + + underTest.beforeComponent(PROJECT); + underTest.afterComponent(PROJECT); + + Set<Map.Entry<String, Measure>> entries = measureRepository.getRawMeasures(FILE1).entrySet(); + + assertNewSoftwareQualityMeasures(SoftwareQuality.MAINTAINABILITY, getImpactMeasure(2, 1, 1, 0), entries); + assertNewSoftwareQualityMeasures(SoftwareQuality.RELIABILITY, getImpactMeasure(2, 0, 1, 1), entries); + assertNewSoftwareQualityMeasures(SoftwareQuality.SECURITY, getImpactMeasure(4, 2, 1, 1), entries); } private static Map<String, Long> getImpactMeasure(long total, long high, long medium, long low) { @@ -374,11 +416,21 @@ public class IssueCounterTest { return map; } - private void assertSoftwareQualityMeasures(SoftwareQuality softwareQuality, Map<? extends String, Long> expectedMap, + private void assertOverallSoftwareQualityMeasures(SoftwareQuality softwareQuality, Map<? extends String, Long> expectedMap, Set<Map.Entry<String, Measure>> actualRaw) { + assertSoftwareQualityMeasures(softwareQuality, expectedMap, actualRaw, IMPACT_TO_METRIC_KEY); + } + + private void assertNewSoftwareQualityMeasures(SoftwareQuality softwareQuality, Map<? extends String, Long> expectedMap, + Set<Map.Entry<String, Measure>> actualRaw) { + assertSoftwareQualityMeasures(softwareQuality, expectedMap, actualRaw, IMPACT_TO_NEW_METRIC_KEY); + } + + private void assertSoftwareQualityMeasures(SoftwareQuality softwareQuality, Map<? extends String, Long> expectedMap, + Set<Map.Entry<String, Measure>> actualRaw, Map<String, String> impactToMetricMap) { Map.Entry<String, Measure> softwareQualityMap = actualRaw.stream() - .filter(e -> e.getKey().equals(IMPACT_TO_METRIC_KEY.get(softwareQuality.name()))) + .filter(e -> e.getKey().equals(impactToMetricMap.get(softwareQuality.name()))) .findFirst() .get(); @@ -386,7 +438,7 @@ public class IssueCounterTest { } @Test - public void count_high_impact_accepted_issues() { + void count_high_impact_accepted_issues() { when(newIssueClassifier.isEnabled()).thenReturn(true); underTest.beforeComponent(FILE1); @@ -413,7 +465,7 @@ public class IssueCounterTest { } @Test - public void exclude_hotspots_from_issue_counts() { + void exclude_hotspots_from_issue_counts() { // bottom-up traversal -> from files to project underTest.beforeComponent(FILE1); underTest.onIssue(FILE1, createSecurityHotspot()); @@ -437,7 +489,7 @@ public class IssueCounterTest { } @Test - public void exclude_new_hotspots_from_issue_counts() { + void exclude_new_hotspots_from_issue_counts() { when(newIssueClassifier.isEnabled()).thenReturn(true); underTest.beforeComponent(FILE1); @@ -496,7 +548,7 @@ public class IssueCounterTest { private DefaultIssue createNewIssue(@Nullable String resolution, String status, SoftwareQuality softwareQuality, Severity impactSeverity) { DefaultIssue issue = createNewIssue(resolution, status, MAJOR, CODE_SMELL); - issue.addImpact(SoftwareQuality.MAINTAINABILITY, impactSeverity); + issue.addImpact(softwareQuality, impactSeverity); return issue; } @@ -522,6 +574,7 @@ public class IssueCounterTest { private static DefaultIssue createIssue(@Nullable String resolution, String status, String severity, RuleType ruleType) { return new DefaultIssue() + .setKey(String.valueOf(++issueCounter)) .setResolution(resolution).setStatus(status) .setSeverity(severity).setRuleKey(RuleTesting.XOO_X1) .setType(ruleType); |