]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-20607 CaYC compliancy check should support legacy cayc conditions
authorZipeng WU <zipeng.wu@sonarsource.com>
Thu, 9 Nov 2023 13:10:25 +0000 (14:10 +0100)
committersonartech <sonartech@sonarsource.com>
Mon, 13 Nov 2023 20:02:32 +0000 (20:02 +0000)
server/sonar-webserver-webapi/src/it/java/org/sonar/server/qualitygate/QualityGateCaycCheckerIT.java
server/sonar-webserver-webapi/src/main/java/org/sonar/server/qualitygate/QualityGateCaycChecker.java

index d5d151227bc2e31eed087e102ae9abd2a1b6b617..5734ab43c484ed83785b37d5025028e04eee39b4 100644 (file)
  */
 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<Metric>  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<Metric>  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<Metric>  caycMetrics, Map<String, Double> 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())
index f2c82248ad1a2b91134b96ee9e4fbb2124d033b8..17b672936736a2741cd9b88bae6722eabff0859a 100644 (file)
@@ -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<String> 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<String, Double> 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<Metric<? extends Serializable>> 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<MetricDto> metrics, Map<String, QualityGateConditionDto> 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;