From 305b3d5937ece0b9aeaaa931fc0d9a4c1e6ba52b Mon Sep 17 00:00:00 2001 From: DDMili <130993898+dejan-milisavljevic-sonarsource@users.noreply.github.com> Date: Fri, 9 Aug 2024 16:35:16 +0200 Subject: [PATCH] SONAR-22727 Add new software qualities rating measures --- ...ilityAndSecurityRatingMeasuresVisitor.java | 46 ++++- ...ilityAndSecurityRatingMeasuresVisitor.java | 54 ++++- ...yAndSecurityRatingMeasuresVisitorTest.java | 191 +++++++++++++++++- ...yAndSecurityRatingMeasuresVisitorTest.java | 171 +++++++++++++--- .../java/org/sonar/server/measure/Rating.java | 22 +- .../metric/SoftwareQualitiesMetrics.java | 10 +- .../metric/SoftwareQualitiesMetricsTest.java | 4 +- 7 files changed, 443 insertions(+), 55 deletions(-) diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitymodel/NewReliabilityAndSecurityRatingMeasuresVisitor.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitymodel/NewReliabilityAndSecurityRatingMeasuresVisitor.java index 245fbe062f2..dc5b216cc09 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitymodel/NewReliabilityAndSecurityRatingMeasuresVisitor.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitymodel/NewReliabilityAndSecurityRatingMeasuresVisitor.java @@ -19,9 +19,10 @@ */ package org.sonar.ce.task.projectanalysis.qualitymodel; -import com.google.common.collect.ImmutableMap; import java.util.Map; import org.sonar.api.ce.measure.Issue; +import org.sonar.api.issue.impact.Severity; +import org.sonar.api.issue.impact.SoftwareQuality; import org.sonar.api.measures.CoreMetrics; import org.sonar.ce.task.projectanalysis.component.Component; import org.sonar.ce.task.projectanalysis.component.PathAwareVisitorAdapter; @@ -33,6 +34,7 @@ import org.sonar.ce.task.projectanalysis.metric.Metric; import org.sonar.ce.task.projectanalysis.metric.MetricRepository; import org.sonar.core.issue.DefaultIssue; import org.sonar.server.measure.Rating; +import org.sonar.server.metric.SoftwareQualitiesMetrics; import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING_KEY; @@ -51,15 +53,19 @@ import static org.sonar.server.measure.Rating.B; import static org.sonar.server.measure.Rating.C; import static org.sonar.server.measure.Rating.D; import static org.sonar.server.measure.Rating.E; +import static org.sonar.server.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY; +import static org.sonar.server.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY; /** * Compute following measures : * {@link CoreMetrics#NEW_RELIABILITY_RATING_KEY} * {@link CoreMetrics#NEW_SECURITY_RATING_KEY} + * {@link SoftwareQualitiesMetrics#NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY} + * {@link SoftwareQualitiesMetrics#NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY} */ public class NewReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisitorAdapter { - private static final Map RATING_BY_SEVERITY = ImmutableMap.of( + private static final Map RATING_BY_SEVERITY = Map.of( BLOCKER, E, CRITICAL, D, MAJOR, C, @@ -78,9 +84,11 @@ public class NewReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVis this.componentIssuesRepository = componentIssuesRepository; // Output metrics - this.metricsByKey = ImmutableMap.of( + this.metricsByKey = Map.of( NEW_RELIABILITY_RATING_KEY, metricRepository.getByKey(NEW_RELIABILITY_RATING_KEY), - NEW_SECURITY_RATING_KEY, metricRepository.getByKey(NEW_SECURITY_RATING_KEY)); + NEW_SECURITY_RATING_KEY, metricRepository.getByKey(NEW_SECURITY_RATING_KEY), + NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, metricRepository.getByKey(NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY), + NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, metricRepository.getByKey(NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY)); this.newIssueClassifier = newIssueClassifier; } @@ -105,6 +113,7 @@ public class NewReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVis } initRatingsToA(path); processIssues(component, path); + processIssuesForSoftwareQuality(component, path); path.current().newRatingValueByMetric.entrySet() .stream() .filter(entry -> entry.getValue().isSet()) @@ -128,6 +137,13 @@ public class NewReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVis .forEach(issue -> path.current().processIssue(issue)); } + private void processIssuesForSoftwareQuality(Component component, Path path) { + componentIssuesRepository.getIssues(component) + .stream() + .filter(issue -> issue.resolution() == null) + .forEach(issue -> path.current().processIssueForSoftwareQuality(issue)); + } + private static void addToParent(Path path) { if (!path.isRoot()) { path.parent().add(path.current()); @@ -137,7 +153,9 @@ public class NewReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVis static class Counter { private final Map newRatingValueByMetric = Map.of( NEW_RELIABILITY_RATING_KEY, new RatingValue(), - NEW_SECURITY_RATING_KEY, new RatingValue()); + NEW_SECURITY_RATING_KEY, new RatingValue(), + NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, new RatingValue(), + NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, new RatingValue()); private final NewIssueClassifier newIssueClassifier; private final Component component; @@ -160,6 +178,24 @@ public class NewReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVis } } } + + void processIssueForSoftwareQuality(Issue issue) { + if (newIssueClassifier.isNew(component, (DefaultIssue) issue)) { + processSoftwareQualityRating(issue, SoftwareQuality.RELIABILITY, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY); + processSoftwareQualityRating(issue, SoftwareQuality.SECURITY, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY); + } + } + + private void processSoftwareQualityRating(Issue issue, SoftwareQuality softwareQuality, String metricKey) { + Severity severity = issue.impacts().get(softwareQuality); + if (severity != null) { + Rating rating = Rating.RATING_BY_SOFTWARE_QUALITY_SEVERITY.get(severity); + + if (rating != null) { + newRatingValueByMetric.get(metricKey).increment(rating); + } + } + } } private static final class CounterFactory extends SimpleStackElementFactory { diff --git a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitor.java b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitor.java index 25c0d344935..6ecb9f0c3e7 100644 --- a/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitor.java +++ b/server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitor.java @@ -19,8 +19,9 @@ */ package org.sonar.ce.task.projectanalysis.qualitymodel; -import com.google.common.collect.ImmutableMap; import java.util.Map; +import org.sonar.api.issue.impact.Severity; +import org.sonar.api.issue.impact.SoftwareQuality; import org.sonar.api.measures.CoreMetrics; import org.sonar.ce.task.projectanalysis.component.Component; import org.sonar.ce.task.projectanalysis.component.PathAwareVisitorAdapter; @@ -30,7 +31,9 @@ import org.sonar.ce.task.projectanalysis.measure.MeasureRepository; import org.sonar.ce.task.projectanalysis.measure.RatingMeasures; import org.sonar.ce.task.projectanalysis.metric.Metric; import org.sonar.ce.task.projectanalysis.metric.MetricRepository; +import org.sonar.core.issue.DefaultIssue; import org.sonar.server.measure.Rating; +import org.sonar.server.metric.SoftwareQualitiesMetrics; import static org.sonar.api.measures.CoreMetrics.RELIABILITY_RATING_KEY; import static org.sonar.api.measures.CoreMetrics.SECURITY_RATING_KEY; @@ -38,11 +41,15 @@ import static org.sonar.api.rules.RuleType.BUG; import static org.sonar.api.rules.RuleType.VULNERABILITY; import static org.sonar.ce.task.projectanalysis.component.CrawlerDepthLimit.FILE; import static org.sonar.server.measure.Rating.RATING_BY_SEVERITY; +import static org.sonar.server.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING_KEY; +import static org.sonar.server.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING_KEY; /** * Compute following measures for projects and descendants: * {@link CoreMetrics#RELIABILITY_RATING_KEY} * {@link CoreMetrics#SECURITY_RATING_KEY} + * {@link SoftwareQualitiesMetrics#SOFTWARE_QUALITY_RELIABILITY_RATING_KEY} + * {@link SoftwareQualitiesMetrics#SOFTWARE_QUALITY_SECURITY_RATING_KEY} */ public class ReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisitorAdapter { @@ -58,10 +65,15 @@ public class ReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisito // Output metrics Metric reliabilityRatingMetric = metricRepository.getByKey(RELIABILITY_RATING_KEY); Metric securityRatingMetric = metricRepository.getByKey(SECURITY_RATING_KEY); + Metric softwareQualityReliabilityRatingMetric = metricRepository.getByKey(SOFTWARE_QUALITY_RELIABILITY_RATING_KEY); + Metric softwareQualitySecurityRatingMetric = metricRepository.getByKey(SOFTWARE_QUALITY_SECURITY_RATING_KEY); - this.metricsByKey = ImmutableMap.of( + this.metricsByKey = Map.of( RELIABILITY_RATING_KEY, reliabilityRatingMetric, - SECURITY_RATING_KEY, securityRatingMetric); + SECURITY_RATING_KEY, securityRatingMetric, + SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, softwareQualityReliabilityRatingMetric, + SOFTWARE_QUALITY_SECURITY_RATING_KEY, softwareQualitySecurityRatingMetric) + ; } @Override @@ -95,19 +107,39 @@ public class ReliabilityAndSecurityRatingMeasuresVisitor extends PathAwareVisito .stream() .filter(issue -> issue.resolution() == null) .forEach(issue -> { - Rating rating = RATING_BY_SEVERITY.get(issue.severity()); - if (issue.type().equals(BUG)) { - path.current().ratingValueByMetric.get(RELIABILITY_RATING_KEY).increment(rating); - } else if (issue.type().equals(VULNERABILITY)) { - path.current().ratingValueByMetric.get(SECURITY_RATING_KEY).increment(rating); - } + processIssue(path, issue); }); } + private static void processIssue(Path path, DefaultIssue issue) { + Rating rating = RATING_BY_SEVERITY.get(issue.severity()); + if (issue.type().equals(BUG)) { + path.current().ratingValueByMetric.get(RELIABILITY_RATING_KEY).increment(rating); + } else if (issue.type().equals(VULNERABILITY)) { + path.current().ratingValueByMetric.get(SECURITY_RATING_KEY).increment(rating); + } + + processSoftwareQualityRating(path, issue, SoftwareQuality.RELIABILITY, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY); + processSoftwareQualityRating(path, issue, SoftwareQuality.SECURITY, SOFTWARE_QUALITY_SECURITY_RATING_KEY); + } + + private static void processSoftwareQualityRating(Path path, DefaultIssue issue, SoftwareQuality softwareQuality, String metricKey) { + Severity severity = issue.impacts().get(softwareQuality); + if (severity != null) { + Rating rating = Rating.RATING_BY_SOFTWARE_QUALITY_SEVERITY.get(severity); + + if (rating != null) { + path.current().ratingValueByMetric.get(metricKey).increment(rating); + } + } + } + static final class Counter { - private Map ratingValueByMetric = ImmutableMap.of( + private final Map ratingValueByMetric = Map.of( RELIABILITY_RATING_KEY, new RatingValue(), - SECURITY_RATING_KEY, new RatingValue()); + SECURITY_RATING_KEY, new RatingValue(), + SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, new RatingValue(), + SOFTWARE_QUALITY_SECURITY_RATING_KEY, new RatingValue()); private Counter() { // prevents instantiation diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/NewReliabilityAndSecurityRatingMeasuresVisitorTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/NewReliabilityAndSecurityRatingMeasuresVisitorTest.java index 4074bf6b7b6..db3e90f845d 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/NewReliabilityAndSecurityRatingMeasuresVisitorTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/NewReliabilityAndSecurityRatingMeasuresVisitorTest.java @@ -24,6 +24,8 @@ import java.util.Date; import org.junit.jupiter.api.BeforeEach; 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; import org.sonar.api.utils.Duration; import org.sonar.ce.task.projectanalysis.component.Component; @@ -39,6 +41,7 @@ import org.sonar.ce.task.projectanalysis.measure.MeasureRepositoryRule; import org.sonar.ce.task.projectanalysis.metric.MetricRepositoryRule; import org.sonar.core.issue.DefaultIssue; import org.sonar.core.util.UuidFactoryFast; +import org.sonar.core.util.Uuids; import org.sonar.server.measure.Rating; import static org.assertj.core.api.Assertions.assertThat; @@ -68,6 +71,10 @@ import static org.sonar.server.measure.Rating.B; import static org.sonar.server.measure.Rating.C; import static org.sonar.server.measure.Rating.D; import static org.sonar.server.measure.Rating.E; +import static org.sonar.server.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING; +import static org.sonar.server.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY; +import static org.sonar.server.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING; +import static org.sonar.server.metric.SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY; class NewReliabilityAndSecurityRatingMeasuresVisitorTest { @@ -101,7 +108,9 @@ class NewReliabilityAndSecurityRatingMeasuresVisitorTest { @RegisterExtension private final MetricRepositoryRule metricRepository = new MetricRepositoryRule() .add(NEW_SECURITY_RATING) - .add(NEW_RELIABILITY_RATING); + .add(NEW_RELIABILITY_RATING) + .add(NEW_SOFTWARE_QUALITY_RELIABILITY_RATING) + .add(NEW_SOFTWARE_QUALITY_SECURITY_RATING); @RegisterExtension private final MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); @@ -130,6 +139,8 @@ class NewReliabilityAndSecurityRatingMeasuresVisitorTest { verifyAddedRawMeasureOnLeakPeriod(1, NEW_SECURITY_RATING_KEY, A); verifyAddedRawMeasureOnLeakPeriod(1, NEW_RELIABILITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(1, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(1, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, A); } @Test @@ -166,6 +177,29 @@ class NewReliabilityAndSecurityRatingMeasuresVisitorTest { verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, E); } + @Test + void compute_new_software_quality_security_rating() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, + newImpactIssue(SoftwareQuality.SECURITY, Severity.MEDIUM), + // Should not be taken into account + oldImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH)); + fillComponentIssuesVisitorRule.setIssues(FILE_2_REF, + newImpactIssue(SoftwareQuality.SECURITY, Severity.LOW), + newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH), + // Should not be taken into account + oldImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH)); + fillComponentIssuesVisitorRule.setIssues(ROOT_DIR_REF, newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH)); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasureOnLeakPeriod(FILE_1_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, C); + verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, D); + verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, D); + verifyAddedRawMeasureOnLeakPeriod(ROOT_DIR_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, D); + verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, D); + } + @Test void compute_new_security_rating_to_A_when_no_issue() { treeRootHolder.setRoot(ROOT_PROJECT); @@ -180,6 +214,20 @@ class NewReliabilityAndSecurityRatingMeasuresVisitorTest { verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, A); } + @Test + void compute_new_software_quality_security_rating_to_A_when_no_issue() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasureOnLeakPeriod(FILE_1_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(ROOT_DIR_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, A); + } + @Test void compute_new_security_rating_to_A_when_no_new_issue() { treeRootHolder.setRoot(ROOT_PROJECT); @@ -194,6 +242,20 @@ class NewReliabilityAndSecurityRatingMeasuresVisitorTest { verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, A); } + @Test + void compute_new_software_quality_security_rating_to_A_when_no_new_issue() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, oldImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH)); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasureOnLeakPeriod(FILE_1_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(ROOT_DIR_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, A); + } + @Test void compute_new_reliability_rating() { treeRootHolder.setRoot(ROOT_PROJECT); @@ -219,6 +281,29 @@ class NewReliabilityAndSecurityRatingMeasuresVisitorTest { verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, E); } + @Test + void compute_new_software_quality_reliability_rating() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, + newImpactIssue(SoftwareQuality.RELIABILITY, Severity.MEDIUM), + // Should not be taken into account + oldImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH)); + fillComponentIssuesVisitorRule.setIssues(FILE_2_REF, + newImpactIssue(SoftwareQuality.RELIABILITY, Severity.LOW), + newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH), + // Should not be taken into account + oldImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH)); + fillComponentIssuesVisitorRule.setIssues(ROOT_DIR_REF, newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH)); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasureOnLeakPeriod(FILE_1_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, C); + verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, D); + verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, D); + verifyAddedRawMeasureOnLeakPeriod(ROOT_DIR_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, D); + verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, D); + } + @Test void compute_new_reliability_rating_to_A_when_no_issue() { treeRootHolder.setRoot(ROOT_PROJECT); @@ -233,6 +318,20 @@ class NewReliabilityAndSecurityRatingMeasuresVisitorTest { verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, A); } + @Test + void compute_new_software_quality_reliability_rating_to_A_when_no_issue() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasureOnLeakPeriod(FILE_1_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(ROOT_DIR_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A); + } + @Test void compute_new_reliability_rating_to_A_when_no_new_issue() { treeRootHolder.setRoot(ROOT_PROJECT); @@ -247,6 +346,20 @@ class NewReliabilityAndSecurityRatingMeasuresVisitorTest { verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_RELIABILITY_RATING_KEY, A); } + @Test + void compute_new_software_quality_reliability_rating_to_A_when_no_new_issue() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, oldImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH)); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasureOnLeakPeriod(FILE_1_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(FILE_2_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(DIRECTORY_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(ROOT_DIR_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A); + } + @Test void compute_E_reliability_and_security_rating_on_blocker_issue() { treeRootHolder.setRoot(ROOT_PROJECT); @@ -277,6 +390,21 @@ class NewReliabilityAndSecurityRatingMeasuresVisitorTest { verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, D); } + @Test + void compute_D_software_quality_reliability_and_security_rating_on_high_severity_issue() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, + newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH), + newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH), + // Should not be taken into account + newCodeSmellIssue(1L, MAJOR)); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, D); + verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, D); + } + @Test void compute_C_reliability_and_security_rating_on_major_issue() { treeRootHolder.setRoot(ROOT_PROJECT); @@ -292,6 +420,21 @@ class NewReliabilityAndSecurityRatingMeasuresVisitorTest { verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, C); } + @Test + void compute_C_software_quality_reliability_and_security_rating_on_medium_severity_issue() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, + newImpactIssue(SoftwareQuality.RELIABILITY, Severity.MEDIUM), + newImpactIssue(SoftwareQuality.SECURITY, Severity.MEDIUM), + // Should not be taken into account + newCodeSmellIssue(1L, MAJOR)); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, C); + verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, C); + } + @Test void compute_B_reliability_and_security_rating_on_minor_issue() { treeRootHolder.setRoot(ROOT_PROJECT); @@ -307,6 +450,21 @@ class NewReliabilityAndSecurityRatingMeasuresVisitorTest { verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, B); } + @Test + void compute_B_software_quality_reliability_and_security_rating_on_low_severity_issue() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, + newImpactIssue(SoftwareQuality.RELIABILITY, Severity.LOW), + newImpactIssue(SoftwareQuality.SECURITY, Severity.LOW), + // Should not be taken into account + newCodeSmellIssue(1L, MAJOR)); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, B); + verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, B); + } + @Test void compute_A_reliability_and_security_rating_on_info_issue() { treeRootHolder.setRoot(ROOT_PROJECT); @@ -322,6 +480,19 @@ class NewReliabilityAndSecurityRatingMeasuresVisitorTest { verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SECURITY_RATING_KEY, A); } + @Test + void compute_A_software_quality_reliability_and_security_rating_when_no_issue() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, + // Should not be taken into account + newCodeSmellIssue(1L, MAJOR)); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A); + verifyAddedRawMeasureOnLeakPeriod(PROJECT_REF, NEW_SOFTWARE_QUALITY_SECURITY_RATING_KEY, A); + } + private void verifyAddedRawMeasureOnLeakPeriod(int componentRef, String metricKey, Rating rating) { MeasureAssert.assertThat(measureRepository.getAddedRawMeasure(componentRef, metricKey)).hasValue(rating.getIndex()); } @@ -346,6 +517,14 @@ class NewReliabilityAndSecurityRatingMeasuresVisitorTest { return createIssue(effort, severity, CODE_SMELL, true); } + private DefaultIssue newImpactIssue(SoftwareQuality softwareQuality, Severity severity) { + return createIssue(softwareQuality, severity, true); + } + + private DefaultIssue oldImpactIssue(SoftwareQuality softwareQuality, Severity severity) { + return createIssue(softwareQuality, severity, false); + } + private DefaultIssue createIssue(long effort, String severity, RuleType type, boolean isNew) { DefaultIssue issue = createIssue(severity, type) .setEffort(Duration.create(effort)); @@ -361,4 +540,14 @@ class NewReliabilityAndSecurityRatingMeasuresVisitorTest { .setCreationDate(DEFAULT_ISSUE_CREATION_DATE); } + private DefaultIssue createIssue(SoftwareQuality softwareQuality, Severity severity, boolean isNew) { + DefaultIssue issue = new DefaultIssue() + .setKey(Uuids.create()) + .addImpact(softwareQuality, severity) + .setType(BUG) + .setSeverity("BLOCKER") + .setCreationDate(new Date(1000L)); + when(newIssueClassifier.isNew(any(), eq(issue))).thenReturn(isNew); + return issue; + } } diff --git a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitorTest.java b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitorTest.java index c1e28c9b759..d89c7fbae1e 100644 --- a/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitorTest.java +++ b/server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitymodel/ReliabilityAndSecurityRatingMeasuresVisitorTest.java @@ -21,8 +21,10 @@ package org.sonar.ce.task.projectanalysis.qualitymodel; import java.util.Arrays; import java.util.Date; -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; import org.sonar.api.utils.Duration; import org.sonar.ce.task.projectanalysis.component.Component; @@ -65,8 +67,13 @@ import static org.sonar.server.measure.Rating.B; import static org.sonar.server.measure.Rating.C; import static org.sonar.server.measure.Rating.D; import static org.sonar.server.measure.Rating.E; +import static org.sonar.server.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING_KEY; +import static org.sonar.server.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING; +import static org.sonar.server.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING_KEY; +import static org.sonar.server.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING; +import static org.sonar.server.metric.SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING_KEY; -public class ReliabilityAndSecurityRatingMeasuresVisitorTest { +class ReliabilityAndSecurityRatingMeasuresVisitorTest { static final String LANGUAGE_KEY_1 = "lKey1"; @@ -74,38 +81,41 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorTest { static final int DIRECTORY_REF = 123; static final int FILE_1_REF = 1231; static final int FILE_2_REF = 1232; + static final int FILE_3_REF = 1233; static final Component ROOT_PROJECT = builder(Component.Type.PROJECT, PROJECT_REF).setKey("project") .addChildren( builder(DIRECTORY, DIRECTORY_REF).setKey("directory") .addChildren( builder(FILE, FILE_1_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_KEY_1, 1)).setKey("file1").build(), - builder(FILE, FILE_2_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_KEY_1, 1)).setKey("file2").build()) + builder(FILE, FILE_2_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_KEY_1, 1)).setKey("file2").build(), + builder(FILE, FILE_3_REF).setFileAttributes(new FileAttributes(false, LANGUAGE_KEY_1, 1)).setKey("file3").build()) .build()) .build(); - @Rule - public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); + @RegisterExtension + TreeRootHolderRule treeRootHolder = new TreeRootHolderRule(); - @Rule - public MetricRepositoryRule metricRepository = new MetricRepositoryRule() + @RegisterExtension + MetricRepositoryRule metricRepository = new MetricRepositoryRule() .add(RELIABILITY_RATING) - .add(SECURITY_RATING); + .add(SECURITY_RATING) + .add(SOFTWARE_QUALITY_RELIABILITY_RATING) + .add(SOFTWARE_QUALITY_SECURITY_RATING); - @Rule - public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); + @RegisterExtension + MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository); - @Rule - public ComponentIssuesRepositoryRule componentIssuesRepositoryRule = new ComponentIssuesRepositoryRule(treeRootHolder); + private final ComponentIssuesRepositoryRule componentIssuesRepositoryRule = new ComponentIssuesRepositoryRule(treeRootHolder); - @Rule + @RegisterExtension public FillComponentIssuesVisitorRule fillComponentIssuesVisitorRule = new FillComponentIssuesVisitorRule(componentIssuesRepositoryRule, treeRootHolder); VisitorsCrawler underTest = new VisitorsCrawler( Arrays.asList(fillComponentIssuesVisitorRule, new ReliabilityAndSecurityRatingMeasuresVisitor(metricRepository, measureRepository, componentIssuesRepositoryRule))); @Test - public void measures_created_for_project_are_all_A_when_they_have_no_FILE_child() { + void measures_created_for_project_are_all_A_when_they_have_no_FILE_child() { ReportComponent root = builder(PROJECT, 1).build(); treeRootHolder.setRoot(root); @@ -115,11 +125,13 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorTest { .entrySet().stream().map(e -> entryOf(e.getKey(), e.getValue()))) .containsOnly( entryOf(RELIABILITY_RATING_KEY, createRatingMeasure(A)), - entryOf(SECURITY_RATING_KEY, createRatingMeasure(A))); + entryOf(SECURITY_RATING_KEY, createRatingMeasure(A)), + entryOf(SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, createRatingMeasure(A)), + entryOf(SOFTWARE_QUALITY_SECURITY_RATING_KEY, createRatingMeasure(A))); } @Test - public void compute_reliability_rating() { + void compute_reliability_rating() { treeRootHolder.setRoot(ROOT_PROJECT); fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, MAJOR), newBugIssue(1L, MAJOR), // Should not be taken into account @@ -138,7 +150,33 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorTest { } @Test - public void compute_security_rating() { + void compute_software_quality_reliability_rating() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, + newImpactIssue(SoftwareQuality.RELIABILITY, Severity.LOW), + // Should not be taken into account + newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH)); + fillComponentIssuesVisitorRule.setIssues(FILE_2_REF, + newImpactIssue(SoftwareQuality.RELIABILITY, Severity.MEDIUM), + // Should not be taken into account + newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH)); + fillComponentIssuesVisitorRule.setIssues(FILE_3_REF, + // Should not be taken into account + newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH)); + + fillComponentIssuesVisitorRule.setIssues(PROJECT_REF, newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH)); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasure(FILE_1_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, B); + verifyAddedRawMeasure(FILE_2_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, C); + verifyAddedRawMeasure(FILE_3_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A); + verifyAddedRawMeasure(DIRECTORY_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, C); + verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, D); + } + + @Test + void compute_security_rating() { treeRootHolder.setRoot(ROOT_PROJECT); fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newVulnerabilityIssue(10L, MAJOR), newVulnerabilityIssue(1L, MAJOR), // Should not be taken into account @@ -157,7 +195,33 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorTest { } @Test - public void compute_E_reliability_and_security_rating_on_blocker_issue() { + void compute_software_quality_security_rating() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, + newImpactIssue(SoftwareQuality.SECURITY, Severity.LOW), + // Should not be taken into account + newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH)); + fillComponentIssuesVisitorRule.setIssues(FILE_2_REF, + newImpactIssue(SoftwareQuality.SECURITY, Severity.MEDIUM), + // Should not be taken into account + newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH)); + fillComponentIssuesVisitorRule.setIssues(FILE_3_REF, + // Should not be taken into account + newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH)); + + fillComponentIssuesVisitorRule.setIssues(PROJECT_REF, newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH)); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasure(FILE_1_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, B); + verifyAddedRawMeasure(FILE_2_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, C); + verifyAddedRawMeasure(FILE_3_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, A); + verifyAddedRawMeasure(DIRECTORY_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, C); + verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, D); + } + + @Test + void compute_E_reliability_and_security_rating_on_blocker_issue() { treeRootHolder.setRoot(ROOT_PROJECT); fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, BLOCKER), newVulnerabilityIssue(1L, BLOCKER), // Should not be taken into account @@ -170,7 +234,7 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorTest { } @Test - public void compute_D_reliability_and_security_rating_on_critical_issue() { + void compute_D_reliability_and_security_rating_on_critical_issue() { treeRootHolder.setRoot(ROOT_PROJECT); fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, CRITICAL), newVulnerabilityIssue(15L, CRITICAL), // Should not be taken into account @@ -183,7 +247,20 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorTest { } @Test - public void compute_C_reliability_and_security_rating_on_major_issue() { + void compute_D_software_quality_reliability_and_security_rating_on_high_issue() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newImpactIssue(SoftwareQuality.RELIABILITY, Severity.HIGH), newImpactIssue(SoftwareQuality.SECURITY, Severity.HIGH), + // Should not be taken into account + newImpactIssue(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, D); + verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, D); + } + + @Test + void compute_C_reliability_and_security_rating_on_major_issue() { treeRootHolder.setRoot(ROOT_PROJECT); fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, MAJOR), newVulnerabilityIssue(15L, MAJOR), // Should not be taken into account @@ -196,7 +273,20 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorTest { } @Test - public void compute_B_reliability_and_security_rating_on_minor_issue() { + void compute_C_software_quality_reliability_and_security_rating_on_medium_issue() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newImpactIssue(SoftwareQuality.RELIABILITY, Severity.MEDIUM), newImpactIssue(SoftwareQuality.SECURITY, Severity.MEDIUM), + // Should not be taken into account + newImpactIssue(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, C); + verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, C); + } + + @Test + void compute_B_reliability_and_security_rating_on_minor_issue() { treeRootHolder.setRoot(ROOT_PROJECT); fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, MINOR), newVulnerabilityIssue(15L, MINOR), // Should not be taken into account @@ -209,7 +299,20 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorTest { } @Test - public void compute_A_reliability_and_security_rating_on_info_issue() { + void compute_B_software_quality_reliability_and_security_rating_on_low_issue() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newImpactIssue(SoftwareQuality.RELIABILITY, Severity.LOW), newImpactIssue(SoftwareQuality.SECURITY, Severity.LOW), + // Should not be taken into account + newImpactIssue(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, B); + verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, B); + } + + @Test + void compute_A_reliability_and_security_rating_on_info_issue() { treeRootHolder.setRoot(ROOT_PROJECT); fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, newBugIssue(10L, INFO), newVulnerabilityIssue(15L, INFO), // Should not be taken into account @@ -221,6 +324,19 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorTest { verifyAddedRawMeasure(PROJECT_REF, SECURITY_RATING_KEY, A); } + @Test + void compute_A_software_quality_reliability_and_security_rating_when_no_issue() { + treeRootHolder.setRoot(ROOT_PROJECT); + fillComponentIssuesVisitorRule.setIssues(FILE_1_REF, + // Should not be taken into account + newImpactIssue(SoftwareQuality.MAINTAINABILITY, Severity.HIGH)); + + underTest.visit(ROOT_PROJECT); + + verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, A); + verifyAddedRawMeasure(PROJECT_REF, SOFTWARE_QUALITY_SECURITY_RATING_KEY, A); + } + private void verifyAddedRawMeasure(int componentRef, String metricKey, Rating rating) { assertThat(toEntries(measureRepository.getAddedRawMeasures(componentRef))).contains(entryOf(metricKey, newMeasureBuilder().create(rating.getIndex(), rating.name()))); } @@ -254,4 +370,13 @@ public class ReliabilityAndSecurityRatingMeasuresVisitorTest { .setCreationDate(new Date(1000L)); } + private static DefaultIssue newImpactIssue(SoftwareQuality softwareQuality, Severity severity) { + return new DefaultIssue() + .setKey(Uuids.create()) + .addImpact(softwareQuality, severity) + .setType(BUG) + .setSeverity("BLOCKER") + .setCreationDate(new Date(1000L)); + } + } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/measure/Rating.java b/server/sonar-server-common/src/main/java/org/sonar/server/measure/Rating.java index 885360be295..f00b8796dd8 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/measure/Rating.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/measure/Rating.java @@ -19,8 +19,8 @@ */ package org.sonar.server.measure; -import com.google.common.collect.ImmutableMap; import java.util.Map; +import org.sonar.api.issue.impact.Severity; import static java.lang.String.format; import static java.util.Arrays.stream; @@ -37,6 +37,18 @@ public enum Rating { B(2), A(1); + public static final Map RATING_BY_SEVERITY = Map.of( + BLOCKER, E, + CRITICAL, D, + MAJOR, C, + MINOR, B, + INFO, A); + + public static final Map RATING_BY_SOFTWARE_QUALITY_SEVERITY = Map.of( + Severity.HIGH, Rating.D, + Severity.MEDIUM, Rating.C, + Severity.LOW, Rating.B); + private final int index; Rating(int index) { @@ -54,14 +66,6 @@ public enum Rating { .orElseThrow(() -> new IllegalArgumentException(format("Unknown value '%s'", index))); } - public static final Map RATING_BY_SEVERITY = ImmutableMap.of( - BLOCKER, E, - CRITICAL, D, - MAJOR, C, - MINOR, B, - INFO, A); - - public static Rating ratingFromValue(String value) { return valueOf(Integer.parseInt(value)); } diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/metric/SoftwareQualitiesMetrics.java b/server/sonar-server-common/src/main/java/org/sonar/server/metric/SoftwareQualitiesMetrics.java index 229e9ebb76f..de1e0c8476b 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/metric/SoftwareQualitiesMetrics.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/metric/SoftwareQualitiesMetrics.java @@ -59,7 +59,8 @@ public class SoftwareQualitiesMetrics implements Metrics { public static final String SOFTWARE_QUALITY_RELIABILITY_RATING_KEY = "software_quality_reliability_rating"; - public static final Metric RELIABILITY_RATING = new Metric.Builder(SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, "Software Quality Reliability Rating", Metric.ValueType.RATING) + public static final Metric SOFTWARE_QUALITY_RELIABILITY_RATING = new Metric.Builder(SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, + "Software Quality Reliability Rating", Metric.ValueType.RATING) .setDescription("Software quality reliability rating") .setDomain(DOMAIN_RELIABILITY) .setDirection(Metric.DIRECTION_WORST) @@ -70,7 +71,8 @@ public class SoftwareQualitiesMetrics implements Metrics { public static final String NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY = "new_software_quality_reliability_rating"; - public static final Metric NEW_RELIABILITY_RATING = new Metric.Builder(NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, + public static final Metric NEW_SOFTWARE_QUALITY_RELIABILITY_RATING = + new Metric.Builder(NEW_SOFTWARE_QUALITY_RELIABILITY_RATING_KEY, "Software Quality Reliability Rating on New Code", Metric.ValueType.RATING) .setDescription("Software quality reliability rating on new code") .setDomain(DOMAIN_RELIABILITY) @@ -264,8 +266,8 @@ public class SoftwareQualitiesMetrics implements Metrics { return List.of( SOFTWARE_QUALITY_MAINTAINABILITY_RATING, NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING, - RELIABILITY_RATING, - NEW_RELIABILITY_RATING, + SOFTWARE_QUALITY_RELIABILITY_RATING, + NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, SOFTWARE_QUALITY_SECURITY_RATING, NEW_SOFTWARE_QUALITY_SECURITY_RATING, SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, diff --git a/server/sonar-server-common/src/test/java/org/sonar/server/metric/SoftwareQualitiesMetricsTest.java b/server/sonar-server-common/src/test/java/org/sonar/server/metric/SoftwareQualitiesMetricsTest.java index b4315ffaa51..2c8f51177a5 100644 --- a/server/sonar-server-common/src/test/java/org/sonar/server/metric/SoftwareQualitiesMetricsTest.java +++ b/server/sonar-server-common/src/test/java/org/sonar/server/metric/SoftwareQualitiesMetricsTest.java @@ -30,8 +30,8 @@ class SoftwareQualitiesMetricsTest { .containsExactlyInAnyOrder( SoftwareQualitiesMetrics.SOFTWARE_QUALITY_MAINTAINABILITY_RATING, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_MAINTAINABILITY_RATING, - SoftwareQualitiesMetrics.RELIABILITY_RATING, - SoftwareQualitiesMetrics.NEW_RELIABILITY_RATING, + SoftwareQualitiesMetrics.SOFTWARE_QUALITY_RELIABILITY_RATING, + SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_RELIABILITY_RATING, SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_RATING, SoftwareQualitiesMetrics.NEW_SOFTWARE_QUALITY_SECURITY_RATING, SoftwareQualitiesMetrics.SOFTWARE_QUALITY_SECURITY_REVIEW_RATING, -- 2.39.5