package org.sonar.server.qualitygate;
import java.util.List;
-import java.util.stream.IntStream;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.measures.Metric;
import org.sonar.db.qualitygate.QualityGateConditionDto;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.sonar.api.measures.CoreMetrics.BLOCKER_VIOLATIONS;
import static org.sonar.api.measures.CoreMetrics.DUPLICATED_LINES;
+import static org.sonar.api.measures.CoreMetrics.FUNCTION_COMPLEXITY;
import static org.sonar.api.measures.CoreMetrics.LINE_COVERAGE;
import static org.sonar.api.measures.CoreMetrics.NEW_COVERAGE;
import static org.sonar.api.measures.CoreMetrics.NEW_DUPLICATED_LINES_DENSITY;
-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.QualityGateCaycChecker.BEST_VALUE_REQUIREMENTS;
import static org.sonar.server.qualitygate.QualityGateCaycChecker.CAYC_METRICS;
import static org.sonar.server.qualitygate.QualityGateCaycStatus.COMPLIANT;
import static org.sonar.server.qualitygate.QualityGateCaycStatus.NON_COMPLIANT;
QualityGateCaycChecker underTest = new QualityGateCaycChecker(db.getDbClient());
@Test
- public void checkCaycCompliant() {
+ public void checkCaycCompliant_when_contains_all_and_only_complicant_conditions_should_return_compliant() {
String qualityGateUuid = "abcd";
CAYC_METRICS.forEach(metric -> insertCondition(insertMetric(metric), qualityGateUuid, metric.getBestValue()));
assertEquals(COMPLIANT, underTest.checkCaycCompliant(db.getSession(), qualityGateUuid));
}
@Test
- public void check_Cayc_non_compliant_with_extra_conditions() {
+ public void checkCaycCompliant_when_extra_conditions_should_return_over_compliant() {
String qualityGateUuid = "abcd";
CAYC_METRICS.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, metric.getBestValue()));
+ List.of(LINE_COVERAGE, DUPLICATED_LINES).forEach(metric -> insertCondition(insertMetric(metric), qualityGateUuid,
+ metric.getBestValue()));
assertEquals(OVER_COMPLIANT, underTest.checkCaycCompliant(db.getSession(), qualityGateUuid));
}
@Test
- public void check_Cayc_NonCompliant_with_lesser_threshold_value() {
+ public void checkCaycCompliant_when_conditions_have_lesser_threshold_value_should_return_non_compliant() {
var metrics = CAYC_METRICS.stream().map(this::insertMetric).toList();
- IntStream.range(0, 4).forEach(idx -> {
- String qualityGateUuid = "abcd" + idx;
- for (int i = 0; i < metrics.size(); i++) {
- var metric = metrics.get(i);
- insertCondition(metric, qualityGateUuid, idx == i ? metric.getWorstValue() : metric.getBestValue());
+ String qualityGateUuid = "abcd";
+ for (var metric : metrics) {
+ if (BEST_VALUE_REQUIREMENTS.keySet().contains(metric.getKey())) {
+ insertCondition(metric, qualityGateUuid, metric.getBestValue() - 1);
+ } else {
+ insertCondition(metric, qualityGateUuid, metric.getBestValue());
}
- assertEquals(NON_COMPLIANT, underTest.checkCaycCompliant(db.getSession(), qualityGateUuid));
- });
+ }
+ assertEquals(NON_COMPLIANT, underTest.checkCaycCompliant(db.getSession(), qualityGateUuid));
+ }
+
+ @Test
+ public void isCaycCondition_when_check_compliant_condition_should_return_true() {
+ CAYC_METRICS.stream().map(this::toMetricDto)
+ .forEach(metricDto -> assertTrue(underTest.isCaycCondition(metricDto)));
+ }
+
+ @Test
+ public void isCaycCondition_when_check_non_compliant_condition_should_return_false() {
+ List.of(BLOCKER_VIOLATIONS, FUNCTION_COMPLEXITY)
+ .stream().map(this::toMetricDto)
+ .forEach(metricDto -> assertFalse(underTest.isCaycCondition(metricDto)));
}
+
@Test
- public void check_Cayc_NonCompliant_with_missing_metric() {
+ public void checkCaycCompliant_when_missing_compliant_condition_should_return_non_compliant() {
String qualityGateUuid = "abcd";
- List.of(NEW_MAINTAINABILITY_RATING, NEW_RELIABILITY_RATING, NEW_SECURITY_HOTSPOTS_REVIEWED, NEW_DUPLICATED_LINES_DENSITY)
+ List.of(NEW_VIOLATIONS, NEW_SECURITY_HOTSPOTS_REVIEWED)
.forEach(metric -> insertCondition(insertMetric(metric), qualityGateUuid, metric.getBestValue()));
assertEquals(NON_COMPLIANT, underTest.checkCaycCompliant(db.getSession(), qualityGateUuid));
}
@Test
public void existency_requirements_check_only_existency() {
String qualityGateUuid = "abcd";
- List.of(NEW_MAINTAINABILITY_RATING, NEW_RELIABILITY_RATING, NEW_SECURITY_HOTSPOTS_REVIEWED, NEW_SECURITY_RATING)
+ List.of(NEW_VIOLATIONS, NEW_SECURITY_HOTSPOTS_REVIEWED)
.forEach(metric -> insertCondition(insertMetric(metric), qualityGateUuid, metric.getBestValue()));
List.of(NEW_COVERAGE, NEW_DUPLICATED_LINES_DENSITY)
.forEach(metric -> insertCondition(insertMetric(metric), qualityGateUuid, metric.getWorstValue()));
.setValueType(metric.getType().name())
.setHidden(false)
.setBestValue(metric.getBestValue())
- .setBestValue(metric.getWorstValue())
+ .setWorstValue(metric.getWorstValue())
.setDirection(metric.getDirection()));
}
+
+ private MetricDto toMetricDto(Metric metric) {
+ return new MetricDto()
+ .setKey(metric.key())
+ .setValueType(metric.getType().name())
+ .setBestValue(metric.getBestValue())
+ .setWorstValue(metric.getWorstValue())
+ .setDirection(metric.getDirection());
+ }
}
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;
import org.sonar.api.server.ws.WebService;
import org.sonar.core.util.UuidFactoryFast;
private final DbClient dbClient = db.getDbClient();
private final DbSession dbSession = db.getSession();
- private final CreateAction underTest = new CreateAction(dbClient, userSession, new QualityGateUpdater(dbClient, UuidFactoryFast.getInstance()),
+ private final CreateAction underTest = new CreateAction(dbClient, userSession, new QualityGateUpdater(dbClient,
+ UuidFactoryFast.getInstance()),
new QualityGateConditionsUpdater(dbClient));
private final WsActionTester ws = new WsActionTester(underTest);
var conditions = getConditions(dbSession, qualityGateDto);
CAYC_METRICS.stream()
- .map(m -> dbClient.metricDao().selectByKey(dbSession, m.getKey()))
+ .map(metric -> dbClient.metricDao().selectByKey(dbSession, metric.getKey()))
.forEach(metricDto -> assertThat(conditions)
.anyMatch(c -> metricDto.getUuid().equals(c.getMetricUuid()) && c.getErrorThreshold().equals(String.valueOf(getDefaultCaycValue(metricDto)))));
}
@DataProvider
public static Object[][] nullOrEmpty() {
- return new Object[][] {
+ return new Object[][]{
{null},
{""},
{" "}
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;
import java.util.function.Function;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.sonar.api.measures.Metric;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.metric.MetricDto;
import org.sonar.db.qualitygate.QualityGateConditionDto;
-import static java.util.stream.Collectors.toUnmodifiableMap;
+import static java.util.stream.Collectors.toMap;
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;
import static org.sonar.server.qualitygate.QualityGateCaycStatus.OVER_COMPLIANT;
public class QualityGateCaycChecker {
- public static final List<Metric<? extends Serializable>> CAYC_METRICS = List.of(
- NEW_MAINTAINABILITY_RATING,
- NEW_RELIABILITY_RATING,
+ static final Map<String, Double> BEST_VALUE_REQUIREMENTS = Stream.of(
+ 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
+ );
+ public static final Set<Metric<? extends Serializable>> CAYC_METRICS = Set.of(
+ NEW_VIOLATIONS,
NEW_SECURITY_HOTSPOTS_REVIEWED,
- NEW_SECURITY_RATING,
NEW_DUPLICATED_LINES_DENSITY,
NEW_COVERAGE
);
- private static final Set<String> EXISTENCY_REQUIREMENTS = Set.of(
- NEW_DUPLICATED_LINES_DENSITY_KEY,
- NEW_COVERAGE_KEY
- );
-
- private static final Map<String, Double> BEST_VALUE_REQUIREMENTS = CAYC_METRICS.stream()
- .filter(metric -> !EXISTENCY_REQUIREMENTS.contains(metric.getKey()))
- .collect(toUnmodifiableMap(Metric::getKey, Metric::getBestValue));
-
private final DbClient dbClient;
public QualityGateCaycChecker(DbClient dbClient) {
.orElse(NON_COMPLIANT);
}
+ public boolean isCaycCondition(MetricDto metric) {
+ return CAYC_METRICS.stream().map(Metric::getKey).anyMatch(metric.getKey()::equals);
+ }
+
private static boolean checkMetricCaycCompliant(QualityGateConditionDto condition, MetricDto metric) {
if (EXISTENCY_REQUIREMENTS.contains(metric.getKey())) {
return true;
}
private void addCaycConditions(DbSession dbSession, QualityGateDto newQualityGate) {
- CAYC_METRICS.forEach(m ->
- qualityGateConditionsUpdater.createCondition(dbSession, newQualityGate, m.getKey(), OPERATORS_BY_DIRECTION.get(m.getDirection()).getDbValue(),
- String.valueOf(getDefaultCaycValue(m)))
+ CAYC_METRICS.forEach(metric ->
+ qualityGateConditionsUpdater.createCondition(dbSession, newQualityGate, metric.getKey(), OPERATORS_BY_DIRECTION.get(metric.getDirection()).getDbValue(),
+ String.valueOf(getDefaultCaycValue(metric)))
);
}
return dbClient.metricDao().selectByUuids(dbSession, metricUuids).stream().filter(MetricDto::isEnabled).collect(Collectors.toMap(MetricDto::getUuid, Function.identity()));
}
- private ShowWsResponse buildResponse(DbSession dbSession, QualityGateDto qualityGate, QualityGateDto defaultQualityGate, Collection<QualityGateConditionDto> conditions,
- Map<String, MetricDto> metricsByUuid, QualityGateCaycStatus caycStatus) {
+ private ShowWsResponse buildResponse(DbSession dbSession, QualityGateDto qualityGate, QualityGateDto defaultQualityGate,
+ Collection<QualityGateConditionDto> conditions, Map<String, MetricDto> metricsByUuid, QualityGateCaycStatus caycStatus) {
return ShowWsResponse.newBuilder()
.setName(qualityGate.getName())
.setIsBuiltIn(qualityGate.isBuiltIn())
.build();
}
- private static Function<QualityGateConditionDto, ShowWsResponse.Condition> toWsCondition(Map<String, MetricDto> metricsByUuid) {
+ private Function<QualityGateConditionDto, ShowWsResponse.Condition> toWsCondition(Map<String, MetricDto> metricsByUuid) {
return condition -> {
String metricUuid = condition.getMetricUuid();
MetricDto metric = metricsByUuid.get(metricUuid);
ShowWsResponse.Condition.Builder builder = ShowWsResponse.Condition.newBuilder()
.setId(condition.getUuid())
.setMetric(metric.getKey())
+ .setIsCaycCondition(qualityGateCaycChecker.isCaycCondition(metric))
.setOp(condition.getOperator());
ofNullable(condition.getErrorThreshold()).ifPresent(builder::setError);
return builder.build();
optional string caycStatus = 6;
message Condition {
- optional string id = 1;
- optional string metric = 2;
- optional string op = 4;
+ required string id = 1;
+ required string metric = 2;
+ required string op = 4;
optional string error = 6;
+ required bool isCaycCondition = 7;
}
}