From 0383f5c2c7ad2eafd0a02153b3279bf21fb13984 Mon Sep 17 00:00:00 2001 From: Zipeng WU Date: Thu, 9 Nov 2023 14:10:25 +0100 Subject: [PATCH] SONAR-20607 CaYC compliancy check should support legacy cayc conditions --- .../qualitygate/QualityGateCaycCheckerIT.java | 43 +++++++++++++--- .../qualitygate/QualityGateCaycChecker.java | 49 +++++++++++++++---- 2 files changed, 76 insertions(+), 16 deletions(-) diff --git a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/QualityGateCaycCheckerIT.java b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/QualityGateCaycCheckerIT.java index d5d151227bc..5734ab43c48 100644 --- a/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/QualityGateCaycCheckerIT.java +++ b/server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/QualityGateCaycCheckerIT.java @@ -19,9 +19,15 @@ */ package org.sonar.server.qualitygate; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; import java.util.List; +import java.util.Map; +import java.util.Set; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import org.sonar.api.measures.Metric; import org.sonar.core.util.Uuids; import org.sonar.db.DbTester; @@ -41,10 +47,13 @@ import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED; import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS; import static org.sonar.server.qualitygate.QualityGateCaycChecker.BEST_VALUE_REQUIREMENTS; import static org.sonar.server.qualitygate.QualityGateCaycChecker.CAYC_METRICS; +import static org.sonar.server.qualitygate.QualityGateCaycChecker.LEGACY_BEST_VALUE_REQUIREMENTS; +import static org.sonar.server.qualitygate.QualityGateCaycChecker.LEGACY_CAYC_METRICS; import static org.sonar.server.qualitygate.QualityGateCaycStatus.COMPLIANT; import static org.sonar.server.qualitygate.QualityGateCaycStatus.NON_COMPLIANT; import static org.sonar.server.qualitygate.QualityGateCaycStatus.OVER_COMPLIANT; +@RunWith(DataProviderRunner.class) public class QualityGateCaycCheckerIT { @Rule @@ -52,16 +61,18 @@ public class QualityGateCaycCheckerIT { QualityGateCaycChecker underTest = new QualityGateCaycChecker(db.getDbClient()); @Test - public void checkCaycCompliant_when_contains_all_and_only_complicant_conditions_should_return_compliant() { + @UseDataProvider("caycMetrics") + public void checkCaycCompliant_when_contains_all_and_only_compliant_conditions_should_return_compliant(Set caycMetrics) { String qualityGateUuid = "abcd"; - CAYC_METRICS.forEach(metric -> insertCondition(insertMetric(metric), qualityGateUuid, metric.getBestValue())); + caycMetrics.forEach(metric -> insertCondition(insertMetric(metric), qualityGateUuid, metric.getBestValue())); assertEquals(COMPLIANT, underTest.checkCaycCompliant(db.getSession(), qualityGateUuid)); } @Test - public void checkCaycCompliant_when_extra_conditions_should_return_over_compliant() { + @UseDataProvider("caycMetrics") + public void checkCaycCompliant_when_extra_conditions_should_return_over_compliant(Set caycMetrics) { String qualityGateUuid = "abcd"; - CAYC_METRICS.forEach(metric -> insertCondition(insertMetric(metric), qualityGateUuid, metric.getBestValue())); + caycMetrics.forEach(metric -> insertCondition(insertMetric(metric), qualityGateUuid, metric.getBestValue())); // extra conditions outside of CAYC requirements List.of(LINE_COVERAGE, DUPLICATED_LINES).forEach(metric -> insertCondition(insertMetric(metric), qualityGateUuid, @@ -71,12 +82,13 @@ public class QualityGateCaycCheckerIT { } @Test - public void checkCaycCompliant_when_conditions_have_lesser_threshold_value_should_return_non_compliant() { - var metrics = CAYC_METRICS.stream().map(this::insertMetric).toList(); + @UseDataProvider("caycMetricsAndBestValueRequirements") + public void checkCaycCompliant_when_conditions_have_lesser_threshold_value_should_return_non_compliant(Set caycMetrics, Map bestValueRequirements) { + var metrics = caycMetrics.stream().map(this::insertMetric).toList(); String qualityGateUuid = "abcd"; for (var metric : metrics) { - if (BEST_VALUE_REQUIREMENTS.keySet().contains(metric.getKey())) { + if (bestValueRequirements.keySet().contains(metric.getKey())) { insertCondition(metric, qualityGateUuid, metric.getBestValue() - 1); } else { insertCondition(metric, qualityGateUuid, metric.getBestValue()); @@ -89,6 +101,8 @@ public class QualityGateCaycCheckerIT { public void isCaycCondition_when_check_compliant_condition_should_return_true() { CAYC_METRICS.stream().map(this::toMetricDto) .forEach(metricDto -> assertTrue(underTest.isCaycCondition(metricDto))); + LEGACY_CAYC_METRICS.stream().map(this::toMetricDto) + .forEach(metricDto -> assertTrue(underTest.isCaycCondition(metricDto))); } @Test @@ -117,6 +131,21 @@ public class QualityGateCaycCheckerIT { assertEquals(COMPLIANT, underTest.checkCaycCompliant(db.getSession(), qualityGateUuid)); } + @DataProvider + public static Object[][] caycMetrics() { + return new Object[][]{ + {CAYC_METRICS}, {LEGACY_CAYC_METRICS} + }; + } + + @DataProvider + public static Object[][] caycMetricsAndBestValueRequirements() { + return new Object[][]{ + {CAYC_METRICS, BEST_VALUE_REQUIREMENTS}, + {LEGACY_CAYC_METRICS, LEGACY_BEST_VALUE_REQUIREMENTS} + }; + } + private void insertCondition(MetricDto metricDto, String qualityGateUuid, Double threshold) { QualityGateConditionDto newCondition = new QualityGateConditionDto().setQualityGateUuid(qualityGateUuid) .setUuid(Uuids.create()) diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/QualityGateCaycChecker.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/QualityGateCaycChecker.java index f2c82248ad1..17b67293673 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/QualityGateCaycChecker.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/QualityGateCaycChecker.java @@ -20,6 +20,7 @@ package org.sonar.server.qualitygate; import java.io.Serializable; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -37,7 +38,10 @@ import static org.sonar.api.measures.CoreMetrics.NEW_COVERAGE; import static org.sonar.api.measures.CoreMetrics.NEW_COVERAGE_KEY; import static org.sonar.api.measures.CoreMetrics.NEW_DUPLICATED_LINES_DENSITY; import static org.sonar.api.measures.CoreMetrics.NEW_DUPLICATED_LINES_DENSITY_KEY; +import static org.sonar.api.measures.CoreMetrics.NEW_MAINTAINABILITY_RATING; +import static org.sonar.api.measures.CoreMetrics.NEW_RELIABILITY_RATING; import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_HOTSPOTS_REVIEWED; +import static org.sonar.api.measures.CoreMetrics.NEW_SECURITY_RATING; import static org.sonar.api.measures.CoreMetrics.NEW_VIOLATIONS; import static org.sonar.server.qualitygate.QualityGateCaycStatus.COMPLIANT; import static org.sonar.server.qualitygate.QualityGateCaycStatus.NON_COMPLIANT; @@ -49,6 +53,7 @@ public class QualityGateCaycChecker { NEW_VIOLATIONS, NEW_SECURITY_HOTSPOTS_REVIEWED ).collect(toMap(Metric::getKey, Metric::getBestValue)); + static final Set EXISTENCY_REQUIREMENTS = Set.of( NEW_DUPLICATED_LINES_DENSITY_KEY, NEW_COVERAGE_KEY @@ -60,6 +65,22 @@ public class QualityGateCaycChecker { NEW_COVERAGE ); + // To be removed after transition + static final Map LEGACY_BEST_VALUE_REQUIREMENTS = Stream.of( + NEW_MAINTAINABILITY_RATING, + NEW_RELIABILITY_RATING, + NEW_SECURITY_HOTSPOTS_REVIEWED, + NEW_SECURITY_RATING + ).collect(toMap(Metric::getKey, Metric::getBestValue)); + static final Set> LEGACY_CAYC_METRICS = Set.of( + NEW_MAINTAINABILITY_RATING, + NEW_RELIABILITY_RATING, + NEW_SECURITY_HOTSPOTS_REVIEWED, + NEW_SECURITY_RATING, + NEW_DUPLICATED_LINES_DENSITY, + NEW_COVERAGE + ); + private final DbClient dbClient; public QualityGateCaycChecker(DbClient dbClient) { @@ -80,16 +101,24 @@ public class QualityGateCaycChecker { .filter(MetricDto::isEnabled) .toList(); + var caycStatus = checkCaycConditions(metrics, conditionsByMetricId, false); + if (caycStatus == NON_COMPLIANT) { + caycStatus = checkCaycConditions(metrics, conditionsByMetricId, true); + } + return caycStatus; + } + + private static QualityGateCaycStatus checkCaycConditions(List metrics, Map conditionsByMetricId, boolean legacy) { + var caycMetrics = legacy ? LEGACY_CAYC_METRICS : CAYC_METRICS; + long count = metrics.stream() - .filter(metric -> checkMetricCaycCompliant(conditionsByMetricId.get(metric.getUuid()), metric)) + .filter(metric -> checkMetricCaycCompliant(conditionsByMetricId.get(metric.getUuid()), metric, legacy)) .count(); - - if (metrics.size() == count && count == CAYC_METRICS.size()) { + if (metrics.size() == count && count == caycMetrics.size()) { return COMPLIANT; - } else if (metrics.size() > count && count == CAYC_METRICS.size()) { + } else if (metrics.size() > count && count == caycMetrics.size()) { return OVER_COMPLIANT; } - return NON_COMPLIANT; } @@ -101,15 +130,17 @@ public class QualityGateCaycChecker { } public boolean isCaycCondition(MetricDto metric) { - return CAYC_METRICS.stream().map(Metric::getKey).anyMatch(metric.getKey()::equals); + return Stream.concat(CAYC_METRICS.stream(), LEGACY_CAYC_METRICS.stream()) + .map(Metric::getKey).anyMatch(metric.getKey()::equals); } - private static boolean checkMetricCaycCompliant(QualityGateConditionDto condition, MetricDto metric) { + private static boolean checkMetricCaycCompliant(QualityGateConditionDto condition, MetricDto metric, boolean legacy) { + var bestValueRequirements = legacy ? LEGACY_BEST_VALUE_REQUIREMENTS : BEST_VALUE_REQUIREMENTS; if (EXISTENCY_REQUIREMENTS.contains(metric.getKey())) { return true; - } else if (BEST_VALUE_REQUIREMENTS.containsKey(metric.getKey())) { + } else if (bestValueRequirements.containsKey(metric.getKey())) { Double errorThreshold = Double.valueOf(condition.getErrorThreshold()); - Double caycRequiredThreshold = BEST_VALUE_REQUIREMENTS.get(metric.getKey()); + Double caycRequiredThreshold = bestValueRequirements.get(metric.getKey()); return caycRequiredThreshold.compareTo(errorThreshold) == 0; } else { return false; -- 2.39.5