Browse Source

SONAR-11570 Drop period from web services

tags/7.6
Janos Gyerik 5 years ago
parent
commit
1547d5cc2b
65 changed files with 427 additions and 766 deletions
  1. 9
    4
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/ConditionImpl.java
  2. 0
    3
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/ConditionToCondition.java
  3. 3
    3
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsData.java
  4. 7
    11
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/Condition.java
  5. 20
    24
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/ConditionEvaluator.java
  6. 1
    24
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/EvaluationResultTextConverterImpl.java
  7. 2
    3
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImpl.java
  8. 1
    5
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/QualityGateMeasuresStep.java
  9. 1
    1
      server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/webhook/WebhookPostTask.java
  10. 2
    4
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/api/posttask/ConditionImplTest.java
  11. 3
    14
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/api/posttask/ConditionToConditionTest.java
  12. 1
    1
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutorTest.java
  13. 6
    1
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/qualitygatedetails/EvaluatedConditionTest.java
  14. 1
    4
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsDataTest.java
  15. 49
    28
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/ConditionEvaluatorTest.java
  16. 12
    9
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/ConditionTest.java
  17. 4
    57
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/EvaluationResultTextConverterTest.java
  18. 11
    8
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImplTest.java
  19. 3
    27
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/QualityGateMeasuresStepTest.java
  20. 1
    1
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/SmallChangesetQualityGateSpecialCaseTest.java
  21. 2
    2
      server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/webhook/WebhookPostTaskTest.java
  22. 0
    12
      server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateConditionDto.java
  23. 3
    4
      server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/QualityGateConditionMapper.xml
  24. 4
    5
      server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/QualityGateConditionDaoTest.java
  25. 5
    10
      server/sonar-db-dao/src/test/resources/org/sonar/db/qualitygate/QualityGateConditionDaoTest/selectForQualityGate.xml
  26. 5
    10
      server/sonar-db-dao/src/test/resources/org/sonar/db/qualitygate/QualityGateConditionDaoTest/update-result.xml
  27. 4
    7
      server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/Condition.java
  28. 2
    2
      server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/ConditionEvaluator.java
  29. 1
    1
      server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/QualityGateEvaluator.java
  30. 10
    44
      server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/QualityGateEvaluatorImpl.java
  31. 5
    11
      server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/ShortLivingBranchQualityGate.java
  32. 0
    1
      server/sonar-server-common/src/main/java/org/sonar/server/webhook/WebhookPayloadFactoryImpl.java
  33. 3
    3
      server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/ConditionEvaluatorTest.java
  34. 22
    26
      server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/ConditionTest.java
  35. 5
    5
      server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/EvaluatedConditionTest.java
  36. 3
    3
      server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/EvaluatedQualityGateTest.java
  37. 64
    0
      server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/QualityGateEvaluatorImplTest.java
  38. 7
    7
      server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/QualityGateTest.java
  39. 3
    3
      server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/ShortLivingBranchQualityGateTest.java
  40. 2
    4
      server/sonar-server-common/src/test/java/org/sonar/server/webhook/WebhookPayloadFactoryImplTest.java
  41. 2
    4
      server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveQualityGateComputerImpl.java
  42. 15
    39
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java
  43. 0
    3
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConverter.java
  44. 1
    1
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java
  45. 9
    23
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java
  46. 1
    4
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateConditionAction.java
  47. 0
    5
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWs.java
  48. 0
    1
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsParameters.java
  49. 0
    1
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java
  50. 1
    4
      server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/UpdateConditionAction.java
  51. 0
    1
      server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json
  52. 13
    11
      server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveQualityGateComputerImplTest.java
  53. 39
    138
      server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConditionsUpdaterTest.java
  54. 12
    13
      server/sonar-server/src/test/java/org/sonar/server/qualitygate/RegisterQualityGatesTest.java
  55. 2
    2
      server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CopyActionTest.java
  56. 2
    7
      server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateConditionActionTest.java
  57. 9
    8
      server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java
  58. 13
    39
      server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/UpdateConditionActionTest.java
  59. 15
    7
      sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/PostProjectAnalysisTaskTester.java
  60. 4
    1
      sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/QualityGate.java
  61. 2
    25
      sonar-plugin-api/src/test/java/org/sonar/api/ce/posttask/ConditionBuilder_PostProjectAnalysisTaskTesterTest.java
  62. 0
    16
      sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygates/CreateConditionRequest.java
  63. 0
    2
      sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygates/QualitygatesService.java
  64. 0
    16
      sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygates/UpdateConditionRequest.java
  65. 0
    3
      sonar-ws/src/main/protobuf/ws-qualitygates.proto

+ 9
- 4
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/ConditionImpl.java View File

@@ -53,7 +53,7 @@ class ConditionImpl implements QualityGate.Condition {
this.operator = builder.operator;
this.errorThreshold = builder.errorThreshold;
this.warningThreshold = builder.warningThreshold;
this.onLeakPeriod = builder.onLeakPeriod;
this.onLeakPeriod = builder.metricKey.startsWith("new_");
this.value = builder.value;
}

@@ -82,7 +82,6 @@ class ConditionImpl implements QualityGate.Condition {
private String errorThreshold;
@CheckForNull
private String warningThreshold;
private boolean onLeakPeriod;
@CheckForNull
private String value;
private QualityGate.EvaluationStatus status;
@@ -111,8 +110,11 @@ class ConditionImpl implements QualityGate.Condition {
return this;
}

/**
* @deprecated in 7.6. This method has no longer any effect.
*/
@Deprecated
public Builder setOnLeakPeriod(boolean onLeakPeriod) {
this.onLeakPeriod = onLeakPeriod;
return this;
}

@@ -156,6 +158,10 @@ class ConditionImpl implements QualityGate.Condition {
return warningThreshold;
}

/**
* @deprecated in 7.6. Conditions "on leak period" were removed. Use "New X" conditions instead.
*/
@Deprecated
@Override
public boolean isOnLeakPeriod() {
return onLeakPeriod;
@@ -176,7 +182,6 @@ class ConditionImpl implements QualityGate.Condition {
", operator=" + operator +
", errorThreshold='" + errorThreshold + '\'' +
", warningThreshold='" + warningThreshold + '\'' +
", onLeakPeriod=" + onLeakPeriod +
", value='" + value + '\'' +
'}';
}

+ 0
- 3
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/api/posttask/ConditionToCondition.java View File

@@ -25,8 +25,6 @@ import javax.annotation.Nonnull;
import org.sonar.api.ce.posttask.QualityGate;
import org.sonar.ce.task.projectanalysis.qualitygate.Condition;
import org.sonar.ce.task.projectanalysis.qualitygate.ConditionStatus;
import org.sonar.ce.task.projectanalysis.qualitygate.Condition;
import org.sonar.ce.task.projectanalysis.qualitygate.ConditionStatus;

import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;
@@ -55,7 +53,6 @@ class ConditionToCondition implements Function<Condition, QualityGate.Condition>
.setOperator(convert(input.getOperator()))
.setErrorThreshold(input.getErrorThreshold())
.setWarningThreshold(input.getWarningThreshold())
.setOnLeakPeriod(input.hasPeriod())
.setValue(conditionStatus.getValue())
.build();
}

+ 3
- 3
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsData.java View File

@@ -25,8 +25,6 @@ import java.util.List;
import javax.annotation.concurrent.Immutable;
import org.sonar.ce.task.projectanalysis.measure.Measure;
import org.sonar.ce.task.projectanalysis.qualitygate.Condition;
import org.sonar.ce.task.projectanalysis.measure.Measure;
import org.sonar.ce.task.projectanalysis.qualitygate.Condition;

import static com.google.common.collect.FluentIterable.from;
import static java.util.Objects.requireNonNull;
@@ -64,7 +62,9 @@ public class QualityGateDetailsData {
JsonObject result = new JsonObject();
result.addProperty("metric", condition.getMetric().getKey());
result.addProperty("op", condition.getOperator().getDbValue());
if (condition.hasPeriod()) {
if (condition.useVariation()) {
// without this for new_ metrics, the UI will show "-" instead of
// the actual value in the QG failure reason
result.addProperty("period", 1);
}
if (condition.getWarningThreshold() != null) {

+ 7
- 11
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/Condition.java View File

@@ -24,7 +24,6 @@ import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import org.sonar.ce.task.projectanalysis.metric.Metric;
import org.sonar.ce.task.projectanalysis.metric.Metric;

import static java.util.Objects.hash;
import static java.util.Objects.requireNonNull;
@@ -52,14 +51,13 @@ public class Condition {
private final String warningThreshold;
@CheckForNull
private final String errorThreshold;
private final boolean hasPeriod;
private final boolean useVariation;

public Condition(Metric metric, String operator,
@Nullable String errorThreshold, @Nullable String warningThreshold,
boolean hasPeriod) {
@Nullable String errorThreshold, @Nullable String warningThreshold) {
this.metric = requireNonNull(metric);
this.operator = parseFromDbValue(requireNonNull(operator));
this.hasPeriod = hasPeriod;
this.useVariation = metric.getKey().startsWith("new_");
this.errorThreshold = errorThreshold;
this.warningThreshold = warningThreshold;
}
@@ -77,8 +75,8 @@ public class Condition {
return metric;
}

public boolean hasPeriod() {
return hasPeriod;
public boolean useVariation() {
return useVariation;
}

public Operator getOperator() {
@@ -104,20 +102,18 @@ public class Condition {
return false;
}
Condition that = (Condition) o;
return java.util.Objects.equals(metric, that.metric)
&& java.util.Objects.equals(hasPeriod, that.hasPeriod);
return java.util.Objects.equals(metric, that.metric);
}

@Override
public int hashCode() {
return hash(metric, hasPeriod);
return hash(metric);
}

@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("metric", metric)
.add("hasPeriod", hasPeriod)
.add("operator", operator)
.add("warningThreshold", warningThreshold)
.add("errorThreshold", errorThreshold)

+ 20
- 24
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/ConditionEvaluator.java View File

@@ -24,7 +24,6 @@ import javax.annotation.CheckForNull;
import org.apache.commons.lang.StringUtils;
import org.sonar.ce.task.projectanalysis.metric.Metric;
import org.sonar.ce.task.projectanalysis.measure.Measure;
import org.sonar.ce.task.projectanalysis.metric.Metric;

import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Optional.of;
@@ -116,7 +115,7 @@ public final class ConditionEvaluator {

@CheckForNull
private static Comparable parseMeasure(Condition condition, Measure measure) {
if (condition.hasPeriod()) {
if (condition.useVariation()) {
return parseMeasureFromVariation(condition, measure);
}
switch (measure.getValueType()) {
@@ -142,29 +141,26 @@ public final class ConditionEvaluator {

@CheckForNull
private static Comparable parseMeasureFromVariation(Condition condition, Measure measure) {
Optional<Double> periodValue = getPeriodValue(measure);
if (periodValue.isPresent()) {
switch (condition.getMetric().getType().getValueType()) {
case BOOLEAN:
return periodValue.get().intValue() == 1;
case INT:
return periodValue.get().intValue();
case LONG:
return periodValue.get().longValue();
case DOUBLE:
return periodValue.get();
case NO_VALUE:
case STRING:
case LEVEL:
default:
throw new IllegalArgumentException("Period conditions are not supported for metric type " + condition.getMetric().getType());
}
if (!measure.hasVariation()) {
return null;
}
return null;
}

private static Optional<Double> getPeriodValue(Measure measure) {
return measure.hasVariation() ? Optional.of(measure.getVariation()) : Optional.empty();
Double variation = measure.getVariation();
Metric.MetricType metricType = condition.getMetric().getType();
switch (metricType.getValueType()) {
case BOOLEAN:
return variation.intValue() == 1;
case INT:
return variation.intValue();
case LONG:
return variation.longValue();
case DOUBLE:
return variation;
case NO_VALUE:
case STRING:
case LEVEL:
default:
throw new IllegalArgumentException("Unsupported metric type " + metricType);
}
}

}

+ 1
- 24
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/EvaluationResultTextConverterImpl.java View File

@@ -24,23 +24,15 @@ import java.util.Locale;
import java.util.Map;
import javax.annotation.CheckForNull;
import org.sonar.api.i18n.I18n;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
import org.sonar.ce.task.projectanalysis.metric.Metric;
import org.sonar.ce.task.projectanalysis.period.Period;
import org.sonar.core.timemachine.Periods;
import org.sonar.ce.task.projectanalysis.measure.Measure;
import org.sonar.ce.task.projectanalysis.metric.Metric;
import org.sonar.ce.task.projectanalysis.period.Period;
import org.sonar.ce.task.projectanalysis.period.PeriodHolder;

import static java.util.Objects.requireNonNull;
import static org.sonar.ce.task.projectanalysis.measure.Measure.Level.ERROR;

public final class EvaluationResultTextConverterImpl implements EvaluationResultTextConverter {
private static final String VARIATION_METRIC_PREFIX = "new_";
private static final String VARIATION = "variation";
private static final Map<Condition.Operator, String> OPERATOR_LABELS = ImmutableMap.of(
Condition.Operator.EQUALS, "=",
Condition.Operator.NOT_EQUALS, "!=",
@@ -49,14 +41,10 @@ public final class EvaluationResultTextConverterImpl implements EvaluationResult

private final I18n i18n;
private final Durations durations;
private final Periods periods;
private final PeriodHolder periodHolder;

public EvaluationResultTextConverterImpl(I18n i18n, Durations durations, Periods periods, PeriodHolder periodHolder) {
public EvaluationResultTextConverterImpl(I18n i18n, Durations durations) {
this.i18n = i18n;
this.durations = durations;
this.periods = periods;
this.periodHolder = periodHolder;
}

@Override
@@ -70,26 +58,15 @@ public final class EvaluationResultTextConverterImpl implements EvaluationResult
}

private String getAlertLabel(Condition condition, Measure.Level level) {
boolean hasPeriod = condition.hasPeriod();
String metric = i18n.message(Locale.ENGLISH, "metric." + condition.getMetric().getKey() + ".name", condition.getMetric().getName());

StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(metric);

if (hasPeriod && !condition.getMetric().getKey().startsWith(VARIATION_METRIC_PREFIX)) {
String variation = i18n.message(Locale.ENGLISH, VARIATION, VARIATION).toLowerCase(Locale.ENGLISH);
stringBuilder.append(" ").append(variation);
}

stringBuilder
.append(" ").append(OPERATOR_LABELS.get(condition.getOperator())).append(" ")
.append(alertValue(condition, level));

if (hasPeriod) {
Period period = periodHolder.getPeriod();
stringBuilder.append(" ").append(periods.label(period.getMode(), period.getModeParameter(), DateUtils.longToDate(period.getSnapshotDate())));
}

return stringBuilder.toString();
}


+ 2
- 3
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImpl.java View File

@@ -28,7 +28,6 @@ import org.sonar.db.DbSession;
import org.sonar.db.qualitygate.QualityGateConditionDto;
import org.sonar.db.qualitygate.QualityGateDto;
import org.sonar.ce.task.projectanalysis.analysis.Organization;
import org.sonar.ce.task.projectanalysis.metric.MetricRepository;
import org.sonar.server.qualitygate.ShortLivingBranchQualityGate;

import static org.sonar.core.util.stream.MoreCollectors.toList;
@@ -73,7 +72,7 @@ public class QualityGateServiceImpl implements QualityGateService {

Iterable<Condition> conditions = dtos.stream()
.map(input -> metricRepository.getOptionalById(input.getMetricId())
.map(metric -> new Condition(metric, input.getOperator(), input.getErrorThreshold(), input.getWarningThreshold(), input.getPeriod() != null))
.map(metric -> new Condition(metric, input.getOperator(), input.getErrorThreshold(), input.getWarningThreshold()))
.orElse(null))
.filter(Objects::nonNull)
.collect(toList(dtos.size()));
@@ -86,7 +85,7 @@ public class QualityGateServiceImpl implements QualityGateService {
ShortLivingBranchQualityGate.ID,
ShortLivingBranchQualityGate.NAME,
ShortLivingBranchQualityGate.CONDITIONS.stream()
.map(c -> new Condition(metricRepository.getByKey(c.getMetricKey()), c.getOperator(), c.getErrorThreshold(), c.getWarnThreshold(), c.isOnLeak()))
.map(c -> new Condition(metricRepository.getByKey(c.getMetricKey()), c.getOperator(), c.getErrorThreshold(), c.getWarnThreshold()))
.collect(toList(ShortLivingBranchQualityGate.CONDITIONS.size())));
}


+ 1
- 5
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/step/QualityGateMeasuresStep.java View File

@@ -22,7 +22,6 @@ package org.sonar.ce.task.projectanalysis.step;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -74,9 +73,6 @@ import static org.sonar.ce.task.projectanalysis.qualitygate.ConditionStatus.crea
* It must be executed after the computation of differential measures {@link ComputeMeasureVariationsStep}
*/
public class QualityGateMeasuresStep implements ComputationStep {
// Condition on period should come first
private static final Ordering<Condition> PERIOD_ORDERING = Ordering.natural().reverse().onResultOf(Condition::hasPeriod);

private final TreeRootHolder treeRootHolder;
private final QualityGateHolder qualityGateHolder;
private final MutableQualityGateStatusHolder qualityGateStatusHolder;
@@ -206,7 +202,7 @@ public class QualityGateMeasuresStep implements ComputationStep {
private static MetricEvaluationResult evaluateQualityGate(Measure measure, Collection<Condition> conditions) {
ConditionEvaluator conditionEvaluator = new ConditionEvaluator();
MetricEvaluationResult metricEvaluationResult = null;
for (Condition newCondition : PERIOD_ORDERING.immutableSortedCopy(conditions)) {
for (Condition newCondition : conditions) {
EvaluationResult newEvaluationResult = conditionEvaluator.evaluate(newCondition, measure);
if (metricEvaluationResult == null || newEvaluationResult.getLevel().ordinal() > metricEvaluationResult.evaluationResult.getLevel().ordinal()) {
metricEvaluationResult = new MetricEvaluationResult(newEvaluationResult, newCondition);

+ 1
- 1
server/sonar-ce-task-projectanalysis/src/main/java/org/sonar/ce/task/projectanalysis/webhook/WebhookPostTask.java View File

@@ -65,7 +65,7 @@ public class WebhookPostTask implements PostProjectAnalysisTask {
Set<Condition> conditions = qg.getConditions().stream()
.map(q -> {
Condition condition = new Condition(q.getMetricKey(), Condition.Operator.valueOf(q.getOperator().name()),
q.getErrorThreshold(), q.getWarningThreshold(), q.isOnLeakPeriod());
q.getErrorThreshold(), q.getWarningThreshold());
builder.addCondition(condition,
EvaluatedCondition.EvaluationStatus.valueOf(q.getStatus().name()),
q.getStatus() == org.sonar.api.ce.posttask.QualityGate.EvaluationStatus.NO_VALUE ? null : q.getValue());

+ 2
- 4
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/api/posttask/ConditionImplTest.java View File

@@ -46,7 +46,6 @@ public class ConditionImplTest {
.setOperator(QualityGate.Operator.GREATER_THAN)
.setErrorThreshold(ERROR_THRESHOLD)
.setWarningThreshold(WARN_THRESHOLD)
.setOnLeakPeriod(true)
.setValue(VALUE);

@Test
@@ -140,7 +139,7 @@ public class ConditionImplTest {
public void toString_ConditionImpl_of_type_different_from_NO_VALUE() {
assertThat(builder.build().toString())
.isEqualTo(
"ConditionImpl{status=OK, metricKey='metricKey', operator=GREATER_THAN, errorThreshold='error threshold', warningThreshold='warn threshold', onLeakPeriod=true, value='value'}");
"ConditionImpl{status=OK, metricKey='metricKey', operator=GREATER_THAN, errorThreshold='error threshold', warningThreshold='warn threshold', value='value'}");
}

@Test
@@ -150,7 +149,7 @@ public class ConditionImplTest {

assertThat(builder.build().toString())
.isEqualTo(
"ConditionImpl{status=NO_VALUE, metricKey='metricKey', operator=GREATER_THAN, errorThreshold='error threshold', warningThreshold='warn threshold', onLeakPeriod=true, value='null'}");
"ConditionImpl{status=NO_VALUE, metricKey='metricKey', operator=GREATER_THAN, errorThreshold='error threshold', warningThreshold='warn threshold', value='null'}");
}

@Test
@@ -162,7 +161,6 @@ public class ConditionImplTest {
assertThat(underTest.getOperator()).isEqualTo(QualityGate.Operator.GREATER_THAN);
assertThat(underTest.getErrorThreshold()).isEqualTo(ERROR_THRESHOLD);
assertThat(underTest.getWarningThreshold()).isEqualTo(WARN_THRESHOLD);
assertThat(underTest.isOnLeakPeriod()).isEqualTo(true);
assertThat(underTest.getValue()).isEqualTo(VALUE);
}
}

+ 3
- 14
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/api/posttask/ConditionToConditionTest.java View File

@@ -46,7 +46,7 @@ public class ConditionToConditionTest {
private static final Map<Condition, ConditionStatus> NO_STATUS_PER_CONDITIONS = Collections.emptyMap();
private static final String SOME_VALUE = "some value";
private static final ConditionStatus SOME_CONDITION_STATUS = ConditionStatus.create(ConditionStatus.EvaluationStatus.OK, SOME_VALUE);
private static final Condition SOME_CONDITION = new Condition(newMetric(METRIC_KEY), Condition.Operator.EQUALS.getDbValue(), ERROR_THRESHOLD, WARN_THRESHOLD, true);
private static final Condition SOME_CONDITION = new Condition(newMetric(METRIC_KEY), Condition.Operator.EQUALS.getDbValue(), ERROR_THRESHOLD, WARN_THRESHOLD);

@Rule
public ExpectedException expectedException = ExpectedException.none();
@@ -98,26 +98,15 @@ public class ConditionToConditionTest {
@Test
@UseDataProvider("allOperatorValues")
public void apply_converts_all_values_of_operator(Condition.Operator operator) {
Condition condition = new Condition(newMetric(METRIC_KEY), operator.getDbValue(), ERROR_THRESHOLD, WARN_THRESHOLD, true);
Condition condition = new Condition(newMetric(METRIC_KEY), operator.getDbValue(), ERROR_THRESHOLD, WARN_THRESHOLD);
ConditionToCondition underTest = new ConditionToCondition(of(condition, SOME_CONDITION_STATUS));

assertThat(underTest.apply(condition).getOperator().name()).isEqualTo(operator.name());
}

@Test
public void apply_sets_onLeakPeriod_flag_when_Condition_has_non_null_Period() {
Condition noPeriodCondition = new Condition(newMetric(METRIC_KEY), Condition.Operator.NOT_EQUALS.getDbValue(), ERROR_THRESHOLD, WARN_THRESHOLD, false);
ConditionToCondition underTest = new ConditionToCondition(of(
SOME_CONDITION, SOME_CONDITION_STATUS,
noPeriodCondition, SOME_CONDITION_STATUS));

assertThat(underTest.apply(SOME_CONDITION).isOnLeakPeriod()).isTrue();
assertThat(underTest.apply(noPeriodCondition).isOnLeakPeriod()).isFalse();
}

@Test
public void apply_copies_value() {
Condition otherCondition = new Condition(newMetric(METRIC_KEY), Condition.Operator.NOT_EQUALS.getDbValue(), ERROR_THRESHOLD, WARN_THRESHOLD, false);
Condition otherCondition = new Condition(newMetric(METRIC_KEY), Condition.Operator.NOT_EQUALS.getDbValue(), ERROR_THRESHOLD, WARN_THRESHOLD);
ConditionToCondition underTest = new ConditionToCondition(of(
SOME_CONDITION, SOME_CONDITION_STATUS,
otherCondition, ConditionStatus.NO_VALUE_STATUS));

+ 1
- 1
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/api/posttask/PostProjectAnalysisTasksExecutorTest.java View File

@@ -391,7 +391,7 @@ public class PostProjectAnalysisTasksExecutorTest {
private static Condition createCondition(String metricKey) {
Metric metric = mock(Metric.class);
when(metric.getKey()).thenReturn(metricKey);
return new Condition(metric, Condition.Operator.EQUALS.getDbValue(), "error threshold", "warn threshold", false);
return new Condition(metric, Condition.Operator.EQUALS.getDbValue(), "error threshold", "warn threshold");
}

}

+ 6
- 1
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/qualitygatedetails/EvaluatedConditionTest.java View File

@@ -26,10 +26,15 @@ import org.sonar.ce.task.projectanalysis.qualitygate.Condition;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class EvaluatedConditionTest {

private static final Condition SOME_CONDITION = new Condition(mock(Metric.class), Condition.Operator.EQUALS.getDbValue(), "1", null, false);
private static final Metric SOME_METRIC = mock(Metric.class);
static {
when(SOME_METRIC.getKey()).thenReturn("dummy key");
}
private static final Condition SOME_CONDITION = new Condition(SOME_METRIC, Condition.Operator.EQUALS.getDbValue(), "1", null);
private static final Measure.Level SOME_LEVEL = Measure.Level.OK;
private static final String SOME_VALUE = "some value";


+ 1
- 4
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/measure/qualitygatedetails/QualityGateDetailsDataTest.java View File

@@ -52,7 +52,7 @@ public class QualityGateDetailsDataTest {
@Test
public void verify_json_for_each_type_of_condition() {
String value = "actualValue";
Condition condition = new Condition(new MetricImpl(1, "key1", "name1", Metric.MetricType.STRING), Condition.Operator.GREATER_THAN.getDbValue(), "errorTh", "warnTh", true);
Condition condition = new Condition(new MetricImpl(1, "key1", "name1", Metric.MetricType.STRING), Condition.Operator.GREATER_THAN.getDbValue(), "errorTh", "warnTh");
ImmutableList<EvaluatedCondition> evaluatedConditions = ImmutableList.of(
new EvaluatedCondition(condition, Measure.Level.OK, value),
new EvaluatedCondition(condition, Measure.Level.WARN, value),
@@ -65,7 +65,6 @@ public class QualityGateDetailsDataTest {
" {" +
" \"metric\":\"key1\"," +
" \"op\":\"GT\"," +
" \"period\":1," +
" \"warning\":\"warnTh\"," +
" \"error\":\"errorTh\"," +
" \"actual\":\"actualValue\"," +
@@ -74,7 +73,6 @@ public class QualityGateDetailsDataTest {
" {" +
" \"metric\":\"key1\"," +
" \"op\":\"GT\"," +
" \"period\":1," +
" \"warning\":\"warnTh\"," +
" \"error\":\"errorTh\"," +
" \"actual\":\"actualValue\"," +
@@ -83,7 +81,6 @@ public class QualityGateDetailsDataTest {
" {" +
" \"metric\":\"key1\"," +
" \"op\":\"GT\"," +
" \"period\":1," +
" \"warning\":\"warnTh\"," +
" \"error\":\"errorTh\"," +
" \"actual\":\"actualValue\"," +

+ 49
- 28
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/ConditionEvaluatorTest.java View File

@@ -19,11 +19,14 @@
*/
package org.sonar.ce.task.projectanalysis.qualitygate;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.sonar.ce.task.projectanalysis.measure.Measure;
import org.sonar.ce.task.projectanalysis.metric.Metric;
import org.sonar.ce.task.projectanalysis.metric.MetricImpl;
@@ -53,6 +56,7 @@ import static org.sonar.ce.task.projectanalysis.qualitygate.Condition.Operator.L
import static org.sonar.ce.task.projectanalysis.qualitygate.Condition.Operator.NOT_EQUALS;
import static org.sonar.ce.task.projectanalysis.qualitygate.EvaluationResultAssert.assertThat;

@RunWith(DataProviderRunner.class)
public class ConditionEvaluatorTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
@@ -241,8 +245,8 @@ public class ConditionEvaluatorTest {
assertThat(underTest.evaluate(createErrorCondition(metric, EQUALS, "10.2"), measure)).hasLevel(ERROR);
assertThat(underTest.evaluate(createErrorCondition(metric, EQUALS, "10.1"), measure)).hasLevel(OK);

assertThat(underTest.evaluate(new Condition(metric, EQUALS.getDbValue(), "10.3", "10.2", false), measure)).hasLevel(Measure.Level.WARN);
assertThat(underTest.evaluate(new Condition(metric, LESS_THAN.getDbValue(), "10.3", "10.2", false), measure)).hasLevel(Measure.Level.ERROR);
assertThat(underTest.evaluate(new Condition(metric, EQUALS.getDbValue(), "10.3", "10.2"), measure)).hasLevel(Measure.Level.WARN);
assertThat(underTest.evaluate(new Condition(metric, LESS_THAN.getDbValue(), "10.3", "10.2"), measure)).hasLevel(Measure.Level.ERROR);
}

@Test
@@ -267,54 +271,71 @@ public class ConditionEvaluatorTest {
}

@Test
public void test_condition_on_period() {
for (MetricType metricType : ImmutableList.of(FLOAT, INT, WORK_DUR)) {
Metric metric = createMetric(metricType);
Measure measure = newMeasureBuilder().setVariation(3d).createNoValue();
@UseDataProvider("numericNewMetricTypes")
public void test_condition_on_numeric_new_metric(MetricType metricType) {
Metric metric = createNewMetric(metricType);
Measure measure = newMeasureBuilder().setVariation(3d).createNoValue();

assertThat(underTest.evaluate(new Condition(metric, GREATER_THAN.getDbValue(), "3", null, true), measure)).hasLevel(OK);
}
assertThat(underTest.evaluate(new Condition(metric, GREATER_THAN.getDbValue(), "3", null), measure)).hasLevel(OK);
assertThat(underTest.evaluate(new Condition(metric, GREATER_THAN.getDbValue(), "2", null), measure)).hasLevel(ERROR);
}

@Test
public void condition_on_period_without_value_is_OK() {
Metric metric = createMetric(FLOAT);
@UseDataProvider("numericNewMetricTypes")
public void condition_on_new_metric_without_value_is_OK(MetricType metricType) {
Metric metric = createNewMetric(metricType);
Measure measure = newMeasureBuilder().createNoValue();

assertThat(underTest.evaluate(new Condition(metric, GREATER_THAN.getDbValue(), "3", null, true), measure)).hasLevel(OK).hasValue(null);
assertThat(underTest.evaluate(new Condition(metric, GREATER_THAN.getDbValue(), "3", null), measure)).hasLevel(OK).hasValue(null);
}

@Test
public void test_condition_on_rating() {
Metric metric = createMetric(RATING);
Measure measure = newMeasureBuilder().create(4, "D");
assertThat(underTest.evaluate(new Condition(metric, GREATER_THAN.getDbValue(), "4", null, false), measure)).hasLevel(OK).hasValue(4);
assertThat(underTest.evaluate(new Condition(metric, GREATER_THAN.getDbValue(), "2", null, false), measure)).hasLevel(ERROR).hasValue(4);
@DataProvider
public static Object[][] numericNewMetricTypes() {
return new Object[][] {
{FLOAT},
{INT},
{WORK_DUR},
};
}

@Test
public void test_condition_on_rating_on_leak_period() {
Metric metric = createMetric(RATING);
Measure measure = newMeasureBuilder().setVariation(4d).createNoValue();
@UseDataProvider("unsupportedNewMetricTypes")
public void condition_on_new_metric_with_unsupported_type(MetricType metricType) {
Metric metric = createNewMetric(metricType);
Measure measure = newMeasureBuilder().setVariation(0d).createNoValue();

assertThat(underTest.evaluate(new Condition(metric, GREATER_THAN.getDbValue(), "5", null, true), measure)).hasLevel(OK).hasValue(4);
assertThat(underTest.evaluate(new Condition(metric, GREATER_THAN.getDbValue(), "2", null, true), measure)).hasLevel(ERROR).hasValue(4);
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Unsupported metric type " + metricType);

underTest.evaluate(new Condition(metric, EQUALS.getDbValue(), "3", null), measure);
}

@DataProvider
public static Object[][] unsupportedNewMetricTypes() {
return new Object[][] {
{STRING},
{LEVEL},
};
}

@Test
public void test_condition_on_rating_on_leak_period_when_variation_is_zero() {
public void test_condition_on_rating() {
Metric metric = createMetric(RATING);
Measure measure = newMeasureBuilder().setVariation(0d).createNoValue();
Measure measure = newMeasureBuilder().create(4, "D");

assertThat(underTest.evaluate(new Condition(metric, GREATER_THAN.getDbValue(), "4", null, true), measure)).hasLevel(OK).hasValue(0);
assertThat(underTest.evaluate(new Condition(metric, GREATER_THAN.getDbValue(), "4", null), measure)).hasLevel(OK).hasValue(4);
assertThat(underTest.evaluate(new Condition(metric, GREATER_THAN.getDbValue(), "2", null), measure)).hasLevel(ERROR).hasValue(4);
}

private static Condition createErrorCondition(Metric metric, Condition.Operator operator, String errorThreshold) {
return new Condition(metric, operator.getDbValue(), errorThreshold, null, false);
return new Condition(metric, operator.getDbValue(), errorThreshold, null);
}

private static MetricImpl createMetric(MetricType metricType) {
return new MetricImpl(1, "key", "name", metricType);
}

private static MetricImpl createNewMetric(MetricType metricType) {
return new MetricImpl(1, "new_key", "name", metricType);
}
}

+ 12
- 9
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/ConditionTest.java View File

@@ -19,6 +19,7 @@
*/
package org.sonar.ce.task.projectanalysis.qualitygate;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -36,14 +37,19 @@ public class ConditionTest {
private static final Metric SOME_METRIC = mock(Metric.class);
private static final String SOME_OPERATOR = "EQ";

@Before
public void setUp() {
when(SOME_METRIC.getKey()).thenReturn("dummy key");
}

@Test(expected = NullPointerException.class)
public void constructor_throws_NPE_for_null_metric_argument() {
new Condition(null, SOME_OPERATOR, null, null, false);
new Condition(null, SOME_OPERATOR, null, null);
}

@Test(expected = NullPointerException.class)
public void constructor_throws_NPE_for_null_operator_argument() {
new Condition(SOME_METRIC, null, null, null, false);
new Condition(SOME_METRIC, null, null, null);
}

@Test
@@ -51,7 +57,7 @@ public class ConditionTest {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Unsupported operator value: 'troloto'");

new Condition(SOME_METRIC, "troloto", null, null, false);
new Condition(SOME_METRIC, "troloto", null, null);
}

@Test
@@ -59,11 +65,10 @@ public class ConditionTest {
String error = "error threshold";
String warning = "warning threshold";

Condition condition = new Condition(SOME_METRIC, SOME_OPERATOR, error, warning, true);
Condition condition = new Condition(SOME_METRIC, SOME_OPERATOR, error, warning);

assertThat(condition.getMetric()).isSameAs(SOME_METRIC);
assertThat(condition.getOperator()).isSameAs(Condition.Operator.EQUALS);
assertThat(condition.hasPeriod()).isTrue();
assertThat(condition.getErrorThreshold()).isEqualTo(error);
assertThat(condition.getWarningThreshold()).isEqualTo(warning);
}
@@ -72,9 +77,7 @@ public class ConditionTest {
public void all_fields_are_displayed_in_toString() {
when(SOME_METRIC.toString()).thenReturn("metric1");

assertThat(new Condition(SOME_METRIC, SOME_OPERATOR, "error_l", "warn", true).toString())
.isEqualTo("Condition{metric=metric1, hasPeriod=true, operator=EQUALS, warningThreshold=warn, errorThreshold=error_l}");

assertThat(new Condition(SOME_METRIC, SOME_OPERATOR, "error_l", "warn").toString())
.isEqualTo("Condition{metric=metric1, operator=EQUALS, warningThreshold=warn, errorThreshold=error_l}");
}

}

+ 4
- 57
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/EvaluationResultTextConverterTest.java View File

@@ -24,10 +24,8 @@ import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.sonar.api.i18n.I18n;
@@ -35,9 +33,6 @@ import org.sonar.api.utils.Durations;
import org.sonar.ce.task.projectanalysis.measure.Measure;
import org.sonar.ce.task.projectanalysis.metric.Metric;
import org.sonar.ce.task.projectanalysis.metric.MetricImpl;
import org.sonar.ce.task.projectanalysis.period.Period;
import org.sonar.ce.task.projectanalysis.period.PeriodHolderRule;
import org.sonar.core.timemachine.Periods;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@@ -49,20 +44,16 @@ import static org.sonar.ce.task.projectanalysis.measure.Measure.Level.WARN;
public class EvaluationResultTextConverterTest {
private static final Metric INT_METRIC = new MetricImpl(1, "key", "int_metric_name", Metric.MetricType.INT);
private static final Metric SOME_VARIATION_METRIC = new MetricImpl(2, "new_variation_of_trololo", "variation_of_trololo_name", Metric.MetricType.INT);
private static final Condition EQ_10_CONDITION = new Condition(INT_METRIC, Condition.Operator.EQUALS.getDbValue(), "10", null, false);
private static final Condition EQ_10_CONDITION = new Condition(INT_METRIC, Condition.Operator.EQUALS.getDbValue(), "10", null);
private static final EvaluationResult OK_EVALUATION_RESULT = new EvaluationResult(Measure.Level.OK, null);
private static final String ERROR_THRESHOLD = "error_threshold";
private static final String WARNING_THRESHOLD = "warning_threshold";
private static final String SOME_MODE = "mode";
private static final String SOME_ANALYSIS_UUID = "u1";

@Rule
public PeriodHolderRule periodsHolder = new PeriodHolderRule();

private I18n i18n = mock(I18n.class);
private Durations durations = mock(Durations.class);
private Periods periods = mock(Periods.class);
private EvaluationResultTextConverter underTest = new EvaluationResultTextConverterImpl(i18n, durations, periods, periodsHolder);
private EvaluationResultTextConverter underTest = new EvaluationResultTextConverterImpl(i18n, durations);

@Test(expected = NullPointerException.class)
public void evaluate_throws_NPE_if_Condition_arg_is_null() {
@@ -98,7 +89,7 @@ public class EvaluationResultTextConverterTest {
when(i18n.message(Locale.ENGLISH, "metric." + INT_METRIC.getKey() + ".name", INT_METRIC.getName()))
.thenReturn(metricMsg);

Condition condition = new Condition(INT_METRIC, operator.getDbValue(), ERROR_THRESHOLD, WARNING_THRESHOLD, false);
Condition condition = new Condition(INT_METRIC, operator.getDbValue(), ERROR_THRESHOLD, WARNING_THRESHOLD);

assertThat(underTest.asText(condition, new EvaluationResult(level, null)))
.isEqualTo(metricMsg + " " + toSign(operator) + " " + getThreshold(level));
@@ -116,56 +107,12 @@ public class EvaluationResultTextConverterTest {
when(i18n.message(Locale.ENGLISH, "metric." + SOME_VARIATION_METRIC.getKey() + ".name", SOME_VARIATION_METRIC.getName()))
.thenReturn(metricMsg);

Condition condition = new Condition(SOME_VARIATION_METRIC, operator.getDbValue(), ERROR_THRESHOLD, WARNING_THRESHOLD, false);
Condition condition = new Condition(SOME_VARIATION_METRIC, operator.getDbValue(), ERROR_THRESHOLD, WARNING_THRESHOLD);

assertThat(underTest.asText(condition, new EvaluationResult(level, null)))
.isEqualTo(metricMsg + " " + toSign(operator) + " " + getThreshold(level));
}

@Test
@UseDataProvider("all_operators_for_error_warning_levels")
public void evaluate_adds_only_period_if_metric_starts_with_new_prefix(Condition.Operator operator, Measure.Level level) {
String metricMsg = "trololo_metric_msg";
int periodIndex = 1;
String periodLabel = "periodLabel";

when(i18n.message(Locale.ENGLISH, "metric." + SOME_VARIATION_METRIC.getKey() + ".name", SOME_VARIATION_METRIC.getName()))
.thenReturn(metricMsg);

Date date = new Date();
Period period = new Period(SOME_MODE, null, date.getTime(), SOME_ANALYSIS_UUID);
periodsHolder.setPeriod(period);
when(periods.label(period.getMode(), period.getModeParameter(), date)).thenReturn(periodLabel);

Condition condition = new Condition(SOME_VARIATION_METRIC, operator.getDbValue(), ERROR_THRESHOLD, WARNING_THRESHOLD, true);

assertThat(underTest.asText(condition, new EvaluationResult(level, null)))
.isEqualTo(metricMsg + " " + toSign(operator) + " " + (getThreshold(level)) + " " + periodLabel);
}

@Test
@UseDataProvider("all_operators_for_error_warning_levels")
public void evaluate_adds_variation_and_period_if_metric_does_not_starts_with_variation_prefix(Condition.Operator operator, Measure.Level level) {
String metricMsg = "trololo_metric_msg";
String variationMsg = "_variation_";
int periodIndex = 1;
String periodLabel = "periodLabel";

when(i18n.message(Locale.ENGLISH, "metric." + INT_METRIC.getKey() + ".name", INT_METRIC.getName()))
.thenReturn(metricMsg);
when(i18n.message(Locale.ENGLISH, "variation", "variation")).thenReturn(variationMsg);

Date date = new Date();
Period period = new Period(SOME_MODE, null, date.getTime(), SOME_ANALYSIS_UUID);
periodsHolder.setPeriod(period);
when(periods.label(period.getMode(), period.getModeParameter(), date)).thenReturn(periodLabel);

Condition condition = new Condition(INT_METRIC, operator.getDbValue(), ERROR_THRESHOLD, WARNING_THRESHOLD, true);

assertThat(underTest.asText(condition, new EvaluationResult(level, null)))
.isEqualTo(metricMsg + " " + variationMsg + " " + toSign(operator) + " " + (getThreshold(level)) + " " + periodLabel);
}

private static String toSign(Condition.Operator operator) {
switch (operator) {
case EQUALS:

+ 11
- 8
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/qualitygate/QualityGateServiceImplTest.java View File

@@ -53,7 +53,7 @@ public class QualityGateServiceImplTest {
private static final long METRIC_ID_2 = 753;
private static final Metric METRIC_1 = mock(Metric.class);
private static final Metric METRIC_2 = mock(Metric.class);
private static final QualityGateConditionDto CONDITION_1 = new QualityGateConditionDto().setId(321).setMetricId(METRIC_ID_1).setOperator("EQ").setPeriod(1)
private static final QualityGateConditionDto CONDITION_1 = new QualityGateConditionDto().setId(321).setMetricId(METRIC_ID_1).setOperator("EQ")
.setWarningThreshold("warnin_th").setErrorThreshold("error_th");
private static final QualityGateConditionDto CONDITION_2 = new QualityGateConditionDto().setId(456).setMetricId(METRIC_ID_2).setOperator("NE");

@@ -67,6 +67,9 @@ public class QualityGateServiceImplTest {
public void setUp() throws Exception {
when(dbClient.qualityGateDao()).thenReturn(qualityGateDao);
when(dbClient.gateConditionDao()).thenReturn(qualityGateConditionDao);

when(METRIC_1.getKey()).thenReturn("metric");
when(METRIC_2.getKey()).thenReturn("new_metric");
}

@Test
@@ -101,8 +104,8 @@ public class QualityGateServiceImplTest {
assertThat(res.get().getId()).isEqualTo(SOME_ID);
assertThat(res.get().getName()).isEqualTo(SOME_NAME);
assertThat(res.get().getConditions()).containsOnly(
new Condition(METRIC_1, CONDITION_1.getOperator(), CONDITION_1.getErrorThreshold(), CONDITION_1.getWarningThreshold(), true),
new Condition(METRIC_2, CONDITION_2.getOperator(), CONDITION_2.getErrorThreshold(), CONDITION_2.getWarningThreshold(), false));
new Condition(METRIC_1, CONDITION_1.getOperator(), CONDITION_1.getErrorThreshold(), CONDITION_1.getWarningThreshold()),
new Condition(METRIC_2, CONDITION_2.getOperator(), CONDITION_2.getErrorThreshold(), CONDITION_2.getWarningThreshold()));
}

@Test
@@ -119,11 +122,11 @@ public class QualityGateServiceImplTest {
assertThat(res.get().getId()).isEqualTo(SOME_ID);
assertThat(res.get().getName()).isEqualTo(SOME_NAME);
assertThat(res.get().getConditions()).containsOnly(
new Condition(METRIC_2, CONDITION_2.getOperator(), CONDITION_2.getErrorThreshold(), CONDITION_2.getWarningThreshold(), false));
new Condition(METRIC_2, CONDITION_2.getOperator(), CONDITION_2.getErrorThreshold(), CONDITION_2.getWarningThreshold()));
}

@Test
public void findById_of_hardcoded_short_living_branch_returns_hardcoded_qp() {
public void findById_of_hardcoded_short_living_branch_returns_hardcoded_qg() {
MetricImpl bugsMetric = mockMetricInRepository(CoreMetrics.BUGS_KEY);
MetricImpl vulnerabilitiesMetric = mockMetricInRepository(CoreMetrics.VULNERABILITIES_KEY);
MetricImpl codeSmellsMetric = mockMetricInRepository(CoreMetrics.CODE_SMELLS_KEY);
@@ -137,10 +140,10 @@ public class QualityGateServiceImplTest {
assertThat(qualityGate.getId()).isEqualTo(ShortLivingBranchQualityGate.ID);
assertThat(qualityGate.getName()).isEqualTo("Hardcoded short living branch quality gate");
assertThat(qualityGate.getConditions())
.extracting(Condition::getMetric, Condition::getOperator, Condition::getErrorThreshold, Condition::getWarningThreshold, Condition::hasPeriod)
.extracting(Condition::getMetric, Condition::getOperator, Condition::getErrorThreshold, Condition::getWarningThreshold)
.containsOnly(
tuple(openedIssueMetric, GREATER_THAN, "0", null, false),
tuple(reOpenedIssueMetric, GREATER_THAN, "0", null, false));
tuple(openedIssueMetric, GREATER_THAN, "0", null),
tuple(reOpenedIssueMetric, GREATER_THAN, "0", null));
}

private MetricImpl mockMetricInRepository(String metricKey) {

+ 3
- 27
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/QualityGateMeasuresStepTest.java View File

@@ -278,7 +278,7 @@ public class QualityGateMeasuresStepTest {
public void new_measure_has_ERROR_level_of_all_conditions_for_a_specific_metric_if_its_the_worst() {
int rawValue = 1;
Condition fixedCondition = createEqualsCondition(INT_METRIC_1, "1", null);
Condition periodCondition = createEqualsCondition(INT_METRIC_1, null, "2", true);
Condition periodCondition = createEqualsCondition(INT_METRIC_1, null, "2");

qualityGateHolder.setQualityGate(new QualityGate(SOME_QG_ID, SOME_QG_NAME, of(fixedCondition, periodCondition)));
Measure measure = newMeasureBuilder().create(rawValue, null);
@@ -292,31 +292,11 @@ public class QualityGateMeasuresStepTest {
.hasQualityGateText(dumbResultTextAnswer(fixedCondition, ERROR, rawValue));
}

@Test
public void new_measure_has_WARN_level_of_all_conditions_for_a_specific_metric_if_its_the_worst() {
int rawValue = 2;
Condition fixedCondition = createEqualsCondition(INT_METRIC_1, "1", null);
Condition periodCondition = createEqualsCondition(INT_METRIC_1, null, "2", true);

qualityGateHolder.setQualityGate(new QualityGate(SOME_QG_ID, SOME_QG_NAME, of(fixedCondition, periodCondition)));
Measure measure = newMeasureBuilder()
.setVariation(rawValue)
.create(rawValue, null);
measureRepository.addRawMeasure(PROJECT_REF, INT_METRIC_1_KEY, measure);

underTest.execute(new TestComputationStepContext());

Optional<Measure> rawMeasure1 = measureRepository.getAddedRawMeasure(PROJECT_REF, INT_METRIC_1_KEY);
assertThat(rawMeasure1.get())
.hasQualityGateLevel(WARN)
.hasQualityGateText(dumbResultTextAnswer(periodCondition, WARN, rawValue));
}

@Test
public void new_measure_has_condition_on_leak_period_when_all_conditions_on_specific_metric_has_same_QG_level() {
int rawValue = 1;
Condition fixedCondition = createEqualsCondition(INT_METRIC_1, "1", null);
Condition periodCondition = createEqualsCondition(INT_METRIC_1, "1", null, true);
Condition periodCondition = createEqualsCondition(INT_METRIC_1, "1", null);

qualityGateHolder.setQualityGate(new QualityGate(SOME_QG_ID, SOME_QG_NAME, of(fixedCondition, periodCondition)));
Measure measure = newMeasureBuilder()
@@ -341,11 +321,7 @@ public class QualityGateMeasuresStepTest {
}

private static Condition createEqualsCondition(Metric metric, @Nullable String errorThreshold, @Nullable String warningThreshold) {
return new Condition(metric, Condition.Operator.EQUALS.getDbValue(), errorThreshold, warningThreshold, false);
}

private static Condition createEqualsCondition(Metric metric, @Nullable String errorThreshold, @Nullable String warningThreshold, boolean hasPeriod) {
return new Condition(metric, Condition.Operator.EQUALS.getDbValue(), errorThreshold, warningThreshold, hasPeriod);
return new Condition(metric, Condition.Operator.EQUALS.getDbValue(), errorThreshold, warningThreshold);
}

private static MetricImpl createIntMetric(int index) {

+ 1
- 1
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/step/SmallChangesetQualityGateSpecialCaseTest.java View File

@@ -149,7 +149,7 @@ public class SmallChangesetQualityGateSpecialCaseTest {

private QualityGateMeasuresStep.MetricEvaluationResult generateEvaluationResult(String metric, Measure.Level level) {
Metric newCoverageMetric = metricRepository.getByKey(metric);
Condition condition = new Condition(newCoverageMetric, "LT", "80", "90", true);
Condition condition = new Condition(newCoverageMetric, "LT", "80", "90");
EvaluationResult evaluationResult = new EvaluationResult(level, mock(Comparable.class));
return new QualityGateMeasuresStep.MetricEvaluationResult(evaluationResult, condition);
}

+ 2
- 2
server/sonar-ce-task-projectanalysis/src/test/java/org/sonar/ce/task/projectanalysis/webhook/WebhookPostTaskTest.java View File

@@ -148,8 +148,8 @@ public class WebhookPostTaskTest {
condition.getMetricKey(),
Condition.Operator.valueOf(condition.getOperator().name()),
condition.getErrorThreshold(),
condition.getWarningThreshold(),
condition.isOnLeakPeriod());
condition.getWarningThreshold()
);
webQualityGate = EvaluatedQualityGate.newBuilder()
.setQualityGate(new org.sonar.server.qualitygate.QualityGate(qualityGate.getId(), qualityGate.getName(), Collections.singleton(qgCondition)))
.setStatus(Metric.Level.valueOf(qualityGate.getStatus().name()))

+ 0
- 12
server/sonar-db-dao/src/main/java/org/sonar/db/qualitygate/QualityGateConditionDto.java View File

@@ -91,8 +91,6 @@ public class QualityGateConditionDto {

private String metricKey;

private Integer period;

private String operator;

private String warningThreshold;
@@ -140,16 +138,6 @@ public class QualityGateConditionDto {
return this;
}

@CheckForNull
public Integer getPeriod() {
return period;
}

public QualityGateConditionDto setPeriod(@Nullable Integer period) {
this.period = period;
return this;
}

public String getOperator() {
return operator;
}

+ 3
- 4
server/sonar-db-dao/src/main/resources/org/sonar/db/qualitygate/QualityGateConditionMapper.xml View File

@@ -4,15 +4,15 @@
<mapper namespace="org.sonar.db.qualitygate.QualityGateConditionMapper">

<insert id="insert" parameterType="QualityGateCondition" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
insert into quality_gate_conditions (qgate_id, metric_id, operator, value_error, value_warning, period, created_at,
insert into quality_gate_conditions (qgate_id, metric_id, operator, value_error, value_warning, created_at,
updated_at)
values (#{qualityGateId}, #{metricId}, #{operator}, #{errorThreshold}, #{warningThreshold}, #{period}, #{createdAt},
values (#{qualityGateId}, #{metricId}, #{operator}, #{errorThreshold}, #{warningThreshold}, #{createdAt},
#{updatedAt})
</insert>

<sql id="conditionColumns">
id, qgate_id as qualityGateId, metric_id as metricId, operator, value_warning as warningThreshold, value_error as
errorThreshold, period,
errorThreshold,
created_at as createdAt, updated_at as updatedAt
</sql>

@@ -39,7 +39,6 @@
operator=#{operator},
value_warning=#{warningThreshold},
value_error=#{errorThreshold},
period=#{period},
updated_at=#{updatedAt}
where id=#{id}
</update>

+ 4
- 5
server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/QualityGateConditionDaoTest.java View File

@@ -30,7 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
public class QualityGateConditionDaoTest {

private static final String[] COLUMNS_WITHOUT_TIMESTAMPS = {
"id", "qgate_id", "metric_id", "operator", "value_warning", "value_error", "period"
"id", "qgate_id", "metric_id", "operator", "value_warning", "value_error"
};

@Rule
@@ -43,12 +43,12 @@ public class QualityGateConditionDaoTest {
public void testInsert() {
dbTester.prepareDbUnit(getClass(), "insert.xml");
QualityGateConditionDto newCondition = new QualityGateConditionDto()
.setQualityGateId(1L).setMetricId(2L).setOperator("GT").setWarningThreshold("10").setErrorThreshold("20").setPeriod(3);
.setQualityGateId(1L).setMetricId(2L).setOperator("GT").setWarningThreshold("10").setErrorThreshold("20");

underTest.insert(newCondition, dbTester.getSession());
dbTester.commit();

dbTester.assertDbUnitTable(getClass(), "insert-result.xml", "quality_gate_conditions", "metric_id", "operator", "error_value", "warning_value", "period");
dbTester.assertDbUnitTable(getClass(), "insert-result.xml", "quality_gate_conditions", "metric_id", "operator", "error_value", "warning_value");
assertThat(newCondition.getId()).isNotNull();
}

@@ -67,7 +67,6 @@ public class QualityGateConditionDaoTest {
assertThat(selectById.getId()).isNotNull().isNotEqualTo(0L);
assertThat(selectById.getMetricId()).isEqualTo(2L);
assertThat(selectById.getOperator()).isEqualTo("<");
assertThat(selectById.getPeriod()).isEqualTo(3);
assertThat(selectById.getQualityGateId()).isEqualTo(1L);
assertThat(selectById.getWarningThreshold()).isEqualTo("10");
assertThat(selectById.getErrorThreshold()).isEqualTo("20");
@@ -88,7 +87,7 @@ public class QualityGateConditionDaoTest {
public void testUpdate() {
dbTester.prepareDbUnit(getClass(), "selectForQualityGate.xml");

underTest.update(new QualityGateConditionDto().setId(1L).setMetricId(7L).setOperator(">").setPeriod(1).setWarningThreshold("50").setErrorThreshold("80"), dbSession);
underTest.update(new QualityGateConditionDto().setId(1L).setMetricId(7L).setOperator(">").setWarningThreshold("50").setErrorThreshold("80"), dbSession);
dbSession.commit();

dbTester.assertDbUnitTable(getClass(), "update-result.xml", "quality_gate_conditions", COLUMNS_WITHOUT_TIMESTAMPS);

+ 5
- 10
server/sonar-db-dao/src/test/resources/org/sonar/db/qualitygate/QualityGateConditionDaoTest/selectForQualityGate.xml View File

@@ -1,14 +1,9 @@
<dataset>

<quality_gate_conditions id="1" qgate_id="1" metric_id="2" operator="&lt;" value_warning="10" value_error="20"
period="3"/>
<quality_gate_conditions id="2" qgate_id="1" metric_id="3" operator="&lt;" value_warning="10" value_error="20"
period="[null]"/>
<quality_gate_conditions id="3" qgate_id="1" metric_id="4" operator="&lt;" value_warning="10" value_error="[null]"
period="1"/>
<quality_gate_conditions id="4" qgate_id="2" metric_id="5" operator="&lt;" value_warning="[null]" value_error="20"
period="3"/>
<quality_gate_conditions id="5" qgate_id="2" metric_id="6" operator="&lt;" value_warning="[null]" value_error="20"
period="[null]"/>
<quality_gate_conditions id="1" qgate_id="1" metric_id="2" operator="&lt;" value_warning="10" value_error="20"/>
<quality_gate_conditions id="2" qgate_id="1" metric_id="3" operator="&lt;" value_warning="10" value_error="20"/>
<quality_gate_conditions id="3" qgate_id="1" metric_id="4" operator="&lt;" value_warning="10" value_error="[null]"/>
<quality_gate_conditions id="4" qgate_id="2" metric_id="5" operator="&lt;" value_warning="[null]" value_error="20"/>
<quality_gate_conditions id="5" qgate_id="2" metric_id="6" operator="&lt;" value_warning="[null]" value_error="20"/>

</dataset>

+ 5
- 10
server/sonar-db-dao/src/test/resources/org/sonar/db/qualitygate/QualityGateConditionDaoTest/update-result.xml View File

@@ -1,14 +1,9 @@
<dataset>

<quality_gate_conditions id="1" qgate_id="1" metric_id="7" operator="&gt;" value_warning="50" value_error="80"
period="1"/>
<quality_gate_conditions id="2" qgate_id="1" metric_id="3" operator="&lt;" value_warning="10" value_error="20"
period="[null]"/>
<quality_gate_conditions id="3" qgate_id="1" metric_id="4" operator="&lt;" value_warning="10" value_error="[null]"
period="1"/>
<quality_gate_conditions id="4" qgate_id="2" metric_id="5" operator="&lt;" value_warning="[null]" value_error="20"
period="3"/>
<quality_gate_conditions id="5" qgate_id="2" metric_id="6" operator="&lt;" value_warning="[null]" value_error="20"
period="[null]"/>
<quality_gate_conditions id="1" qgate_id="1" metric_id="7" operator="&gt;" value_warning="50" value_error="80"/>
<quality_gate_conditions id="2" qgate_id="1" metric_id="3" operator="&lt;" value_warning="10" value_error="20"/>
<quality_gate_conditions id="3" qgate_id="1" metric_id="4" operator="&lt;" value_warning="10" value_error="[null]"/>
<quality_gate_conditions id="4" qgate_id="2" metric_id="5" operator="&lt;" value_warning="[null]" value_error="20"/>
<quality_gate_conditions id="5" qgate_id="2" metric_id="6" operator="&lt;" value_warning="[null]" value_error="20"/>

</dataset>

+ 4
- 7
server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/Condition.java View File

@@ -42,11 +42,10 @@ public class Condition {
private final boolean onLeakPeriod;

public Condition(String metricKey, Operator operator,
@Nullable String errorThreshold, @Nullable String warningThreshold,
boolean onLeakPeriod) {
@Nullable String errorThreshold, @Nullable String warningThreshold) {
this.metricKey = requireNonNull(metricKey, "metricKey can't be null");
this.operator = requireNonNull(operator, "operator can't be null");
this.onLeakPeriod = onLeakPeriod;
this.onLeakPeriod = metricKey.startsWith("new_");
this.errorThreshold = emptyToNull(errorThreshold);
this.warningThreshold = emptyToNull(warningThreshold);
}
@@ -80,8 +79,7 @@ public class Condition {
return false;
}
Condition condition = (Condition) o;
return onLeakPeriod == condition.onLeakPeriod &&
Objects.equals(metricKey, condition.metricKey) &&
return Objects.equals(metricKey, condition.metricKey) &&
operator == condition.operator &&
Objects.equals(warningThreshold, condition.warningThreshold) &&
Objects.equals(errorThreshold, condition.errorThreshold);
@@ -89,7 +87,7 @@ public class Condition {

@Override
public int hashCode() {
return Objects.hash(metricKey, operator, warningThreshold, errorThreshold, onLeakPeriod);
return Objects.hash(metricKey, operator, warningThreshold, errorThreshold);
}

@Override
@@ -99,7 +97,6 @@ public class Condition {
", operator=" + operator +
", warningThreshold=" + toString(warningThreshold) +
", errorThreshold=" + toString(errorThreshold) +
", onLeakPeriod=" + onLeakPeriod +
'}';
}


+ 2
- 2
server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/ConditionEvaluator.java View File

@@ -128,14 +128,14 @@ class ConditionEvaluator {
case DISTRIB:
return measure.getStringValue().orElse(null);
default:
throw new IllegalArgumentException("Condition on leak period is not allowed for type " + measure.getType());
throw new IllegalArgumentException("Condition is not allowed for type " + measure.getType());
}
}

@CheckForNull
private static Comparable getLeakValue(QualityGateEvaluator.Measure measure) {
if (NUMERICAL_TYPES.contains(measure.getType())) {
return measure.getLeakValue().isPresent() ? getNumericValue(measure.getType(), measure.getLeakValue().getAsDouble()) : null;
return measure.getNewMetricValue().isPresent() ? getNumericValue(measure.getType(), measure.getNewMetricValue().getAsDouble()) : null;
}

throw new IllegalArgumentException("Condition on leak period is not allowed for type " + measure.getType());

+ 1
- 1
server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/QualityGateEvaluator.java View File

@@ -55,6 +55,6 @@ public interface QualityGateEvaluator {

Optional<String> getStringValue();

OptionalDouble getLeakValue();
OptionalDouble getNewMetricValue();
}
}

+ 10
- 44
server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/QualityGateEvaluatorImpl.java View File

@@ -20,19 +20,13 @@
package org.sonar.server.qualitygate;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric.Level;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.server.qualitygate.EvaluatedCondition.EvaluationStatus;

import static java.util.Objects.requireNonNull;
import static org.sonar.core.util.stream.MoreCollectors.toEnumSet;

public class QualityGateEvaluatorImpl implements QualityGateEvaluator {
@@ -55,14 +49,9 @@ public class QualityGateEvaluatorImpl implements QualityGateEvaluator {
.setQualityGate(gate);

boolean isSmallChangeset = isSmallChangeset(measures);
Multimap<String, Condition> conditionsPerMetric = gate.getConditions().stream()
.collect(MoreCollectors.index(Condition::getMetricKey, Function.identity()));

for (Map.Entry<String, Collection<Condition>> entry : conditionsPerMetric.asMap().entrySet()) {
String metricKey = entry.getKey();
Collection<Condition> conditionsOnSameMetric = entry.getValue();

EvaluatedCondition evaluation = evaluateConditionsOnMetric(conditionsOnSameMetric, measures);
gate.getConditions().forEach(condition -> {
String metricKey = condition.getMetricKey();
EvaluatedCondition evaluation = ConditionEvaluator.evaluate(condition, measures);

if (isSmallChangeset && evaluation.getStatus() != EvaluationStatus.OK && METRICS_TO_IGNORE_ON_SMALL_CHANGESETS.contains(metricKey)) {
result.addCondition(new EvaluatedCondition(evaluation.getCondition(), EvaluationStatus.OK, evaluation.getValue().orElse(null)));
@@ -70,7 +59,7 @@ public class QualityGateEvaluatorImpl implements QualityGateEvaluator {
} else {
result.addCondition(evaluation);
}
}
});

result.setStatus(overallStatusOf(result.getEvaluatedConditions()));

@@ -90,37 +79,15 @@ public class QualityGateEvaluatorImpl implements QualityGateEvaluator {
private static boolean isSmallChangeset(Measures measures) {
Optional<Measure> newLines = measures.get(CoreMetrics.NEW_LINES_KEY);
return newLines.isPresent() &&
newLines.get().getLeakValue().isPresent() &&
newLines.get().getLeakValue().getAsDouble() < MAXIMUM_NEW_LINES_FOR_SMALL_CHANGESETS;
}

private static EvaluatedCondition evaluateConditionsOnMetric(Collection<Condition> conditionsOnSameMetric, Measures measures) {
EvaluatedCondition leakEvaluation = null;
EvaluatedCondition absoluteEvaluation = null;
for (Condition condition : conditionsOnSameMetric) {
if (condition.isOnLeakPeriod()) {
leakEvaluation = ConditionEvaluator.evaluate(condition, measures);
} else {
absoluteEvaluation = ConditionEvaluator.evaluate(condition, measures);
}
}

if (leakEvaluation == null) {
return requireNonNull(absoluteEvaluation, "Evaluation of absolute value can't be null on conditions " + conditionsOnSameMetric);
}
if (absoluteEvaluation == null) {
return requireNonNull(leakEvaluation, "Evaluation of leak value can't be null on conditions " + conditionsOnSameMetric);
}
// both conditions are present. Take the worse one. In case of equality, take
// the one on the leak period
if (absoluteEvaluation.getStatus().compareTo(leakEvaluation.getStatus()) > 0) {
return absoluteEvaluation;
}
return leakEvaluation;
newLines.get().getNewMetricValue().isPresent() &&
newLines.get().getNewMetricValue().getAsDouble() < MAXIMUM_NEW_LINES_FOR_SMALL_CHANGESETS;
}

private static Level overallStatusOf(Set<EvaluatedCondition> conditions) {
Set<EvaluationStatus> statuses = conditions.stream().map(EvaluatedCondition::getStatus).collect(toEnumSet(EvaluationStatus.class));
Set<EvaluationStatus> statuses = conditions.stream()
.map(EvaluatedCondition::getStatus)
.collect(toEnumSet(EvaluationStatus.class));

if (statuses.contains(EvaluationStatus.ERROR)) {
return Level.ERROR;
}
@@ -129,5 +96,4 @@ public class QualityGateEvaluatorImpl implements QualityGateEvaluator {
}
return Level.OK;
}

}

+ 5
- 11
server/sonar-server-common/src/main/java/org/sonar/server/qualitygate/ShortLivingBranchQualityGate.java View File

@@ -34,12 +34,12 @@ public final class ShortLivingBranchQualityGate {
public static final long ID = -1_963_456_987L;
public static final String NAME = "Hardcoded short living branch quality gate";
public static final List<Condition> CONDITIONS = ImmutableList.of(
new Condition(CoreMetrics.OPEN_ISSUES_KEY, OPERATOR_GREATER_THAN, "0", false),
new Condition(CoreMetrics.REOPENED_ISSUES_KEY, OPERATOR_GREATER_THAN, "0", false));
new Condition(CoreMetrics.OPEN_ISSUES_KEY, OPERATOR_GREATER_THAN, "0"),
new Condition(CoreMetrics.REOPENED_ISSUES_KEY, OPERATOR_GREATER_THAN, "0"));

public static final QualityGate GATE = new QualityGate(String.valueOf(ID), NAME, ImmutableSet.of(
new org.sonar.server.qualitygate.Condition(CoreMetrics.OPEN_ISSUES_KEY, org.sonar.server.qualitygate.Condition.Operator.GREATER_THAN, "0", null, false),
new org.sonar.server.qualitygate.Condition(CoreMetrics.REOPENED_ISSUES_KEY, org.sonar.server.qualitygate.Condition.Operator.GREATER_THAN, "0", null, false)));
new org.sonar.server.qualitygate.Condition(CoreMetrics.OPEN_ISSUES_KEY, org.sonar.server.qualitygate.Condition.Operator.GREATER_THAN, "0", null),
new org.sonar.server.qualitygate.Condition(CoreMetrics.REOPENED_ISSUES_KEY, org.sonar.server.qualitygate.Condition.Operator.GREATER_THAN, "0", null)));

private ShortLivingBranchQualityGate() {
// prevents instantiation
@@ -49,13 +49,11 @@ public final class ShortLivingBranchQualityGate {
private final String metricKey;
private final String operator;
private final String errorThreshold;
private final boolean onLeak;

public Condition(String metricKey, String operator, String errorThreshold, boolean onLeak) {
public Condition(String metricKey, String operator, String errorThreshold) {
this.metricKey = metricKey;
this.operator = operator;
this.errorThreshold = errorThreshold;
this.onLeak = onLeak;
}

public String getMetricKey() {
@@ -74,9 +72,5 @@ public final class ShortLivingBranchQualityGate {
public String getWarnThreshold() {
return null;
}

public boolean isOnLeak() {
return onLeak;
}
}
}

+ 0
- 1
server/sonar-server-common/src/main/java/org/sonar/server/webhook/WebhookPayloadFactoryImpl.java View File

@@ -154,7 +154,6 @@ public class WebhookPayloadFactoryImpl implements WebhookPayloadFactory {
evaluatedCondition.getValue().ifPresent(t -> writer.prop("value", t));
writer
.prop(PROPERTY_STATUS, evaluatedCondition.getStatus().name())
.prop("onLeakPeriod", condition.isOnLeakPeriod())
.prop("errorThreshold", condition.getErrorThreshold().orElse(null))
.prop("warningThreshold", condition.getWarningThreshold().orElse(null))
.endObject();

+ 3
- 3
server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/ConditionEvaluatorTest.java View File

@@ -130,7 +130,7 @@ public class ConditionEvaluatorTest {

private void test(@Nullable QualityGateEvaluator.Measure measure, Condition.Operator operator, String errorThreshold, @Nullable String warningThreshold,
EvaluatedCondition.EvaluationStatus expectedStatus, @Nullable String expectedValue) {
Condition condition = new Condition("foo", operator, errorThreshold, warningThreshold, false);
Condition condition = new Condition("foo", operator, errorThreshold, warningThreshold);

EvaluatedCondition result = ConditionEvaluator.evaluate(condition, new FakeMeasures(measure));

@@ -144,7 +144,7 @@ public class ConditionEvaluatorTest {

private void testOnLeak(QualityGateEvaluator.Measure measure, Condition.Operator operator, String errorThreshold, EvaluatedCondition.EvaluationStatus expectedStatus,
@Nullable String expectedValue) {
Condition condition = new Condition("foo", operator, errorThreshold, null, true);
Condition condition = new Condition("new_foo", operator, errorThreshold, null);

EvaluatedCondition result = ConditionEvaluator.evaluate(condition, new FakeMeasures(measure));

@@ -211,7 +211,7 @@ public class ConditionEvaluatorTest {
}

@Override
public OptionalDouble getLeakValue() {
public OptionalDouble getNewMetricValue() {
return leakValue == null ? OptionalDouble.empty() : OptionalDouble.of(leakValue);
}
}

+ 22
- 26
server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/ConditionTest.java View File

@@ -31,19 +31,18 @@ public class ConditionTest {
private static final Condition.Operator OPERATOR = Condition.Operator.EQUALS;
private static final String ERROR_THRESHOLD = "2";
private static final String WARN_THRESHOLD = "4";
private static final boolean ON_LEAK_PERIOD = true;

@Rule
public ExpectedException expectedException = ExpectedException.none();

private Condition underTest = new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD);
private Condition underTest = new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD);

@Test
public void constructor_throws_NPE_if_metricKey_is_null() {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("metricKey can't be null");

new Condition(null, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD);
new Condition(null, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD);
}

@Test
@@ -51,19 +50,19 @@ public class ConditionTest {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("operator can't be null");

new Condition(METRIC_KEY, null, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD);
new Condition(METRIC_KEY, null, ERROR_THRESHOLD, WARN_THRESHOLD);
}

@Test
public void errorThreshold_can_be_null() {
Condition underTest = new Condition(METRIC_KEY, OPERATOR, null, WARN_THRESHOLD, ON_LEAK_PERIOD);
Condition underTest = new Condition(METRIC_KEY, OPERATOR, null, WARN_THRESHOLD);

assertThat(underTest.getErrorThreshold()).isEmpty();
}

@Test
public void warnThreshold_can_be_null() {
Condition underTest = new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, null, ON_LEAK_PERIOD);
Condition underTest = new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, null);

assertThat(underTest.getWarningThreshold()).isEmpty();
}
@@ -74,20 +73,19 @@ public class ConditionTest {
assertThat(underTest.getOperator()).isEqualTo(OPERATOR);
assertThat(underTest.getErrorThreshold()).contains(ERROR_THRESHOLD);
assertThat(underTest.getWarningThreshold()).contains(WARN_THRESHOLD);
assertThat(underTest.isOnLeakPeriod()).isEqualTo(ON_LEAK_PERIOD);
}

@Test
public void toString_is_override() {
assertThat(underTest.toString())
.isEqualTo("Condition{metricKey='metric_key', operator=EQUALS, warningThreshold='4', errorThreshold='2', onLeakPeriod=true}");
.isEqualTo("Condition{metricKey='metric_key', operator=EQUALS, warningThreshold='4', errorThreshold='2'}");
}

@Test
public void toString_does_not_quote_nulls() {
Condition withNulls = new Condition("metric_key", Condition.Operator.LESS_THAN, null, null, false);
Condition withNulls = new Condition("metric_key", Condition.Operator.LESS_THAN, null, null);
assertThat(withNulls.toString())
.isEqualTo("Condition{metricKey='metric_key', operator=LESS_THAN, warningThreshold=null, errorThreshold=null, onLeakPeriod=false}");
.isEqualTo("Condition{metricKey='metric_key', operator=LESS_THAN, warningThreshold=null, errorThreshold=null}");
}

@Test
@@ -95,17 +93,16 @@ public class ConditionTest {
assertThat(underTest).isEqualTo(underTest);
assertThat(underTest).isNotEqualTo(null);
assertThat(underTest).isNotEqualTo(new Object());
assertThat(underTest).isEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD));
assertThat(underTest).isNotEqualTo(new Condition("other_metric_key", OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD));
assertThat(underTest).isEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD));
assertThat(underTest).isNotEqualTo(new Condition("other_metric_key", OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD));
Arrays.stream(Condition.Operator.values())
.filter(s -> !OPERATOR.equals(s))
.forEach(otherOperator -> assertThat(underTest)
.isNotEqualTo(new Condition(METRIC_KEY, otherOperator, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD)));
assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, null, WARN_THRESHOLD, ON_LEAK_PERIOD));
assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, "other_error_threshold", WARN_THRESHOLD, ON_LEAK_PERIOD));
assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, null, ON_LEAK_PERIOD));
assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, "other_warn_threshold", ON_LEAK_PERIOD));
assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, !ON_LEAK_PERIOD));
.isNotEqualTo(new Condition(METRIC_KEY, otherOperator, ERROR_THRESHOLD, WARN_THRESHOLD)));
assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, null, WARN_THRESHOLD));
assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, "other_error_threshold", WARN_THRESHOLD));
assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, null));
assertThat(underTest).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, "other_warn_threshold"));
}

@Test
@@ -113,16 +110,15 @@ public class ConditionTest {
assertThat(underTest.hashCode()).isEqualTo(underTest.hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(null);
assertThat(underTest.hashCode()).isNotEqualTo(new Object().hashCode());
assertThat(underTest.hashCode()).isEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD).hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new Condition("other_metric_key", OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD).hashCode());
assertThat(underTest.hashCode()).isEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD).hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new Condition("other_metric_key", OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD).hashCode());
Arrays.stream(Condition.Operator.values())
.filter(s -> !OPERATOR.equals(s))
.forEach(otherOperator -> assertThat(underTest.hashCode())
.isNotEqualTo(new Condition(METRIC_KEY, otherOperator, ERROR_THRESHOLD, WARN_THRESHOLD, ON_LEAK_PERIOD).hashCode()));
assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, null, WARN_THRESHOLD, ON_LEAK_PERIOD).hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, "other_error_threshold", WARN_THRESHOLD, ON_LEAK_PERIOD).hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, null, ON_LEAK_PERIOD).hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, "other_warn_threshold", ON_LEAK_PERIOD).hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, WARN_THRESHOLD, !ON_LEAK_PERIOD).hashCode());
.isNotEqualTo(new Condition(METRIC_KEY, otherOperator, ERROR_THRESHOLD, WARN_THRESHOLD).hashCode()));
assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, null, WARN_THRESHOLD).hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, "other_error_threshold", WARN_THRESHOLD).hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, null).hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new Condition(METRIC_KEY, OPERATOR, ERROR_THRESHOLD, "other_warn_threshold").hashCode());
}
}

+ 5
- 5
server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/EvaluatedConditionTest.java View File

@@ -29,7 +29,7 @@ import static org.sonar.server.qualitygate.EvaluatedCondition.EvaluationStatus.O
import static org.sonar.server.qualitygate.EvaluatedCondition.EvaluationStatus.WARN;

public class EvaluatedConditionTest {
private static final Condition CONDITION_1 = new Condition("metricKey", EQUALS, "2", "4", false);
private static final Condition CONDITION_1 = new Condition("metricKey", EQUALS, "2", "4");

@Rule
public ExpectedException expectedException = ExpectedException.none();
@@ -71,7 +71,7 @@ public class EvaluatedConditionTest {
@Test
public void override_toString() {
assertThat(underTest.toString()).isEqualTo("EvaluatedCondition{condition=" +
"Condition{metricKey='metricKey', operator=EQUALS, warningThreshold='4', errorThreshold='2', onLeakPeriod=false}, " +
"Condition{metricKey='metricKey', operator=EQUALS, warningThreshold='4', errorThreshold='2'}, " +
"status=WARN, value='value'}");
}

@@ -80,7 +80,7 @@ public class EvaluatedConditionTest {
EvaluatedCondition underTest = new EvaluatedCondition(CONDITION_1, WARN, null);

assertThat(underTest.toString()).isEqualTo("EvaluatedCondition{condition=" +
"Condition{metricKey='metricKey', operator=EQUALS, warningThreshold='4', errorThreshold='2', onLeakPeriod=false}, " +
"Condition{metricKey='metricKey', operator=EQUALS, warningThreshold='4', errorThreshold='2'}, " +
"status=WARN, value=null}");
}

@@ -90,7 +90,7 @@ public class EvaluatedConditionTest {
assertThat(underTest).isEqualTo(new EvaluatedCondition(CONDITION_1, WARN, "value"));
assertThat(underTest).isNotEqualTo(null);
assertThat(underTest).isNotEqualTo(new Object());
assertThat(underTest).isNotEqualTo(new EvaluatedCondition(new Condition("other_metric", EQUALS, "a", "b", true), WARN, "value"));
assertThat(underTest).isNotEqualTo(new EvaluatedCondition(new Condition("other_metric", EQUALS, "a", "b"), WARN, "value"));
assertThat(underTest).isNotEqualTo(new EvaluatedCondition(CONDITION_1, OK, "value"));
assertThat(underTest).isNotEqualTo(new EvaluatedCondition(CONDITION_1, WARN, null));
assertThat(underTest).isNotEqualTo(new EvaluatedCondition(CONDITION_1, WARN, "other_value"));
@@ -102,7 +102,7 @@ public class EvaluatedConditionTest {
assertThat(underTest.hashCode()).isEqualTo(new EvaluatedCondition(CONDITION_1, WARN, "value").hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(null);
assertThat(underTest.hashCode()).isNotEqualTo(new Object().hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new EvaluatedCondition(new Condition("other_metric", EQUALS, "a", "b", true), WARN, "value").hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new EvaluatedCondition(new Condition("other_metric", EQUALS, "a", "b"), WARN, "value").hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new EvaluatedCondition(CONDITION_1, OK, "value").hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new EvaluatedCondition(CONDITION_1, WARN, null).hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new EvaluatedCondition(CONDITION_1, WARN, "other_value").hashCode());

+ 3
- 3
server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/EvaluatedQualityGateTest.java View File

@@ -36,8 +36,8 @@ public class EvaluatedQualityGateTest {
private static final String QUALITY_GATE_ID = "qg_id";
private static final String QUALITY_GATE_NAME = "qg_name";
private static final QualityGate NO_CONDITION_QUALITY_GATE = new QualityGate(QUALITY_GATE_ID, QUALITY_GATE_NAME, emptySet());
private static final Condition CONDITION_1 = new Condition("metric_key", Condition.Operator.LESS_THAN, "2", "4", true);
private static final Condition CONDITION_2 = new Condition("metric_key_2", Condition.Operator.GREATER_THAN, "6", "12", false);
private static final Condition CONDITION_1 = new Condition("metric_key", Condition.Operator.LESS_THAN, "2", "4");
private static final Condition CONDITION_2 = new Condition("metric_key_2", Condition.Operator.GREATER_THAN, "6", "12");
private static final QualityGate ONE_CONDITION_QUALITY_GATE = new QualityGate(QUALITY_GATE_ID, QUALITY_GATE_NAME, singleton(CONDITION_1));

@Rule
@@ -74,7 +74,7 @@ public class EvaluatedQualityGateTest {
expectedException.expect(NullPointerException.class);
expectedException.expectMessage("status can't be null");

builder.addCondition(new Condition("metric_key", Condition.Operator.LESS_THAN, "2", "4", true), null, "a_value");
builder.addCondition(new Condition("metric_key", Condition.Operator.LESS_THAN, "2", "4"), null, "a_value");
}

@Test

+ 64
- 0
server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/QualityGateEvaluatorImplTest.java View File

@@ -0,0 +1,64 @@
/*
* SonarQube
* Copyright (C) 2009-2019 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.server.qualitygate;

import com.google.common.collect.ImmutableSet;
import java.util.Set;
import java.util.stream.Collectors;
import org.junit.Test;
import org.sonar.api.measures.Metric;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.api.measures.CoreMetrics.NEW_LINES_KEY;

public class QualityGateEvaluatorImplTest {

private final QualityGateEvaluator underTest = new QualityGateEvaluatorImpl();

@Test
public void getMetricKeys_includes_by_default_new_lines() {
QualityGate gate = mock(QualityGate.class);
assertThat(underTest.getMetricKeys(gate)).containsExactly(NEW_LINES_KEY);
}

@Test
public void getMetricKeys_includes_metrics_from_qgate() {
Set<String> metricKeys = ImmutableSet.of("foo", "bar", "baz");
Set<Condition> conditions = metricKeys.stream().map(key -> {
Condition condition = mock(Condition.class);
when(condition.getMetricKey()).thenReturn(key);
return condition;
}).collect(Collectors.toSet());

QualityGate gate = mock(QualityGate.class);
when(gate.getConditions()).thenReturn(conditions);
assertThat(underTest.getMetricKeys(gate)).containsAll(metricKeys);
}

@Test
public void evaluate_is_OK_for_empty_qgate() {
QualityGate gate = mock(QualityGate.class);
QualityGateEvaluator.Measures measures = mock(QualityGateEvaluator.Measures.class);
EvaluatedQualityGate evaluatedQualityGate = underTest.evaluate(gate, measures);
assertThat(evaluatedQualityGate.getStatus()).isEqualTo(Metric.Level.OK);
}
}

+ 7
- 7
server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/QualityGateTest.java View File

@@ -35,8 +35,8 @@ import static org.assertj.core.api.Assertions.assertThat;
public class QualityGateTest {
private static final String QUALIGATE_ID = "qg_id";
private static final String QUALIGATE_NAME = "qg_name";
private static final Condition CONDITION_1 = new Condition("m1", Condition.Operator.EQUALS, "1", "2", false);
private static final Condition CONDITION_2 = new Condition("m2", Condition.Operator.LESS_THAN, "2", "4", true);
private static final Condition CONDITION_1 = new Condition("m1", Condition.Operator.EQUALS, "1", "2");
private static final Condition CONDITION_2 = new Condition("m2", Condition.Operator.LESS_THAN, "2", "4");

@Rule
public ExpectedException expectedException = ExpectedException.none();
@@ -74,10 +74,10 @@ public class QualityGateTest {
Random random = new Random();
Set<Condition> conditions = Stream.of(
IntStream.range(0, random.nextInt(5))
.mapToObj(i -> new Condition("m_before_" + i, Condition.Operator.EQUALS, null, null, false)),
.mapToObj(i -> new Condition("m_before_" + i, Condition.Operator.EQUALS, null, null)),
Stream.of((Condition) null),
IntStream.range(0, random.nextInt(5))
.mapToObj(i -> new Condition("m_after_" + i, Condition.Operator.EQUALS, null, null, false)))
.mapToObj(i -> new Condition("m_after_" + i, Condition.Operator.EQUALS, null, null)))
.flatMap(s -> s)
.collect(Collectors.toSet());

@@ -99,7 +99,7 @@ public class QualityGateTest {
QualityGate underTest = new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_2));

assertThat(underTest.toString()).isEqualTo("QualityGate{id=qg_id, name='qg_name', conditions=[" +
"Condition{metricKey='m2', operator=LESS_THAN, warningThreshold='4', errorThreshold='2', onLeakPeriod=true}" +
"Condition{metricKey='m2', operator=LESS_THAN, warningThreshold='4', errorThreshold='2'}" +
"]}");
}

@@ -115,7 +115,7 @@ public class QualityGateTest {
assertThat(underTest).isNotEqualTo(new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_1)));
assertThat(underTest).isNotEqualTo(new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_2)));
assertThat(underTest).isNotEqualTo(
new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_1, CONDITION_2, new Condition("new", Condition.Operator.GREATER_THAN, "a", "b", false))));
new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_1, CONDITION_2, new Condition("new", Condition.Operator.GREATER_THAN, "a", "b"))));
}

@Test
@@ -130,6 +130,6 @@ public class QualityGateTest {
assertThat(underTest.hashCode()).isNotEqualTo(new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_1)).hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_2)).hashCode());
assertThat(underTest.hashCode()).isNotEqualTo(
new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_1, CONDITION_2, new Condition("new", Condition.Operator.GREATER_THAN, "a", "b", false))).hashCode());
new QualityGate(QUALIGATE_ID, QUALIGATE_NAME, ImmutableSet.of(CONDITION_1, CONDITION_2, new Condition("new", Condition.Operator.GREATER_THAN, "a", "b"))).hashCode());
}
}

+ 3
- 3
server/sonar-server-common/src/test/java/org/sonar/server/qualitygate/ShortLivingBranchQualityGateTest.java View File

@@ -31,10 +31,10 @@ public class ShortLivingBranchQualityGateTest {
@Test
public void defines_short_living_branches_hardcoded_quality_gate_conditions() {
assertThat(ShortLivingBranchQualityGate.CONDITIONS)
.extracting(Condition::getMetricKey, Condition::getOperator, Condition::getErrorThreshold, Condition::getWarnThreshold, Condition::isOnLeak)
.extracting(Condition::getMetricKey, Condition::getOperator, Condition::getErrorThreshold, Condition::getWarnThreshold)
.containsExactly(
tuple(CoreMetrics.OPEN_ISSUES_KEY, "GT", "0", null, false),
tuple(CoreMetrics.REOPENED_ISSUES_KEY, "GT", "0", null, false));
tuple(CoreMetrics.OPEN_ISSUES_KEY, "GT", "0", null),
tuple(CoreMetrics.REOPENED_ISSUES_KEY, "GT", "0", null));
}

}

+ 2
- 4
server/sonar-server-common/src/test/java/org/sonar/server/webhook/WebhookPayloadFactoryImplTest.java View File

@@ -57,7 +57,7 @@ public class WebhookPayloadFactoryImplTest {
@Test
public void create_payload_for_successful_analysis() {
CeTask task = new CeTask("#1", CeTask.Status.SUCCESS);
Condition condition = new Condition("coverage", Condition.Operator.GREATER_THAN, "70.0", "75.0", true);
Condition condition = new Condition("coverage", Condition.Operator.GREATER_THAN, "70.0", "75.0");
EvaluatedQualityGate gate = EvaluatedQualityGate.newBuilder()
.setQualityGate(new QualityGate("G1", "Gate One", singleton(condition)))
.setStatus(Metric.Level.WARN)
@@ -88,7 +88,6 @@ public class WebhookPayloadFactoryImplTest {
" \"operator\": \"GREATER_THAN\"," +
" \"value\": \"74.0\"," +
" \"status\": \"WARN\"," +
" \"onLeakPeriod\": true," +
" \"errorThreshold\": \"70.0\"," +
" \"warningThreshold\": \"75.0\"" +
" }" +
@@ -103,7 +102,7 @@ public class WebhookPayloadFactoryImplTest {
public void create_payload_with_gate_conditions_without_value() {
CeTask task = new CeTask("#1", CeTask.Status.SUCCESS);

Condition condition = new Condition("coverage", Condition.Operator.GREATER_THAN, "70.0", "75.0", false);
Condition condition = new Condition("coverage", Condition.Operator.GREATER_THAN, "70.0", "75.0");
EvaluatedQualityGate gate = EvaluatedQualityGate.newBuilder()
.setQualityGate(new QualityGate("G1", "Gate One", singleton(condition)))
.setStatus(Metric.Level.WARN)
@@ -133,7 +132,6 @@ public class WebhookPayloadFactoryImplTest {
" \"metric\": \"coverage\"," +
" \"operator\": \"GREATER_THAN\"," +
" \"status\": \"NO_VALUE\"," +
" \"onLeakPeriod\": false," +
" \"errorThreshold\": \"70.0\"," +
" \"warningThreshold\": \"75.0\"" +
" }" +

+ 2
- 4
server/sonar-server/src/main/java/org/sonar/server/measure/live/LiveQualityGateComputerImpl.java View File

@@ -22,7 +22,6 @@ package org.sonar.server.measure.live;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.Set;
@@ -81,8 +80,7 @@ public class LiveQualityGateComputerImpl implements LiveQualityGateComputer {
Set<Condition> conditions = conditionDtos.stream().map(conditionDto -> {
String metricKey = metricsById.get((int) conditionDto.getMetricId()).getKey();
Condition.Operator operator = Condition.Operator.fromDbValue(conditionDto.getOperator());
boolean onLeak = Objects.equals(conditionDto.getPeriod(), 1);
return new Condition(metricKey, operator, conditionDto.getErrorThreshold(), conditionDto.getWarningThreshold(), onLeak);
return new Condition(metricKey, operator, conditionDto.getErrorThreshold(), conditionDto.getWarningThreshold());
}).collect(toHashSet(conditionDtos.size()));

return new QualityGate(String.valueOf(gateDto.getId()), gateDto.getName(), conditions);
@@ -144,7 +142,7 @@ public class LiveQualityGateComputerImpl implements LiveQualityGateComputer {
}

@Override
public OptionalDouble getLeakValue() {
public OptionalDouble getNewMetricValue() {
if (dto.getVariation() == null) {
return OptionalDouble.empty();
}

+ 15
- 39
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java View File

@@ -26,7 +26,6 @@ import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.ObjectUtils;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric.ValueType;
import org.sonar.db.DbClient;
@@ -61,34 +60,31 @@ public class QualityGateConditionsUpdater {
}

public QualityGateConditionDto createCondition(DbSession dbSession, QualityGateDto qualityGate, String metricKey, String operator,
@Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
@Nullable String warningThreshold, @Nullable String errorThreshold) {
MetricDto metric = getNonNullMetric(dbSession, metricKey);
validateCondition(metric, operator, warningThreshold, errorThreshold, period);
checkConditionDoesNotAlreadyExistOnSameMetricAndPeriod(getConditions(dbSession, qualityGate.getId(), null), metric, period);
validateCondition(metric, operator, warningThreshold, errorThreshold);
checkConditionDoesNotExistOnSameMetric(getConditions(dbSession, qualityGate.getId()), metric);

QualityGateConditionDto newCondition = new QualityGateConditionDto().setQualityGateId(qualityGate.getId())
.setMetricId(metric.getId()).setMetricKey(metric.getKey())
.setOperator(operator)
.setWarningThreshold(warningThreshold)
.setErrorThreshold(errorThreshold)
.setPeriod(period);
.setErrorThreshold(errorThreshold);
dbClient.gateConditionDao().insert(newCondition, dbSession);
return newCondition;
}

public QualityGateConditionDto updateCondition(DbSession dbSession, QualityGateConditionDto condition, String metricKey, String operator,
@Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
@Nullable String warningThreshold, @Nullable String errorThreshold) {
MetricDto metric = getNonNullMetric(dbSession, metricKey);
validateCondition(metric, operator, warningThreshold, errorThreshold, period);
checkConditionDoesNotAlreadyExistOnSameMetricAndPeriod(getConditions(dbSession, condition.getQualityGateId(), condition.getId()), metric, period);
validateCondition(metric, operator, warningThreshold, errorThreshold);

condition
.setMetricId(metric.getId())
.setMetricKey(metric.getKey())
.setOperator(operator)
.setWarningThreshold(warningThreshold)
.setErrorThreshold(errorThreshold)
.setPeriod(period);
.setErrorThreshold(errorThreshold);
dbClient.gateConditionDao().update(condition, dbSession);
return condition;
}
@@ -101,26 +97,19 @@ public class QualityGateConditionsUpdater {
return metric;
}

private Collection<QualityGateConditionDto> getConditions(DbSession dbSession, long qGateId, @Nullable Long conditionId) {
Collection<QualityGateConditionDto> conditions = dbClient.gateConditionDao().selectForQualityGate(dbSession, qGateId);
if (conditionId == null) {
return conditions;
}
return dbClient.gateConditionDao().selectForQualityGate(dbSession, qGateId).stream()
.filter(condition -> condition.getId() != conditionId)
.collect(Collectors.toList());
private Collection<QualityGateConditionDto> getConditions(DbSession dbSession, long qGateId) {
return dbClient.gateConditionDao().selectForQualityGate(dbSession, qGateId);
}

private static void validateCondition(MetricDto metric, String operator, @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period) {
private static void validateCondition(MetricDto metric, String operator, @Nullable String warningThreshold, @Nullable String errorThreshold) {
List<String> errors = new ArrayList<>();
validateMetric(metric, errors);
checkOperator(metric, operator, errors);
checkThresholds(warningThreshold, errorThreshold, errors);
checkPeriod(metric, period, errors);

validateThresholdValues(metric, warningThreshold, errors);
validateThresholdValues(metric, errorThreshold, errors);
checkRatingMetric(metric, warningThreshold, errorThreshold, period, errors);
checkRatingMetric(metric, warningThreshold, errorThreshold, errors);
checkRequest(errors.isEmpty(), errors);
}

@@ -145,23 +134,13 @@ public class QualityGateConditionsUpdater {
check(warningThreshold != null || errorThreshold != null, errors, "At least one threshold (warning, error) must be set.");
}

private static void checkPeriod(MetricDto metric, @Nullable Integer period, List<String> errors) {
if (period == null) {
check(!metric.getKey().startsWith("new_"), errors, "A period must be selected for differential metrics.");
} else {
check(period == 1, errors, "The only valid quality gate period is 1, the leak period.");
}
}

private static void checkConditionDoesNotAlreadyExistOnSameMetricAndPeriod(Collection<QualityGateConditionDto> conditions, MetricDto metric, @Nullable final Integer period) {
private static void checkConditionDoesNotExistOnSameMetric(Collection<QualityGateConditionDto> conditions, MetricDto metric) {
if (conditions.isEmpty()) {
return;
}

boolean conditionExists = conditions.stream().anyMatch(c -> c.getMetricId() == metric.getId() && ObjectUtils.equals(c.getPeriod(), period));
checkRequest(!conditionExists, period == null
? format("Condition on metric '%s' already exists.", metric.getShortName())
: format("Condition on metric '%s' over leak period already exists.", metric.getShortName()));
boolean conditionExists = conditions.stream().anyMatch(c -> c.getMetricId() == metric.getId());
checkRequest(!conditionExists, format("Condition on metric '%s' already exists.", metric.getShortName()));
}

private static void validateThresholdValues(MetricDto metric, @Nullable String value, List<String> errors) {
@@ -195,16 +174,13 @@ public class QualityGateConditionsUpdater {
}
}

private static void checkRatingMetric(MetricDto metric, @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period, List<String> errors) {
private static void checkRatingMetric(MetricDto metric, @Nullable String warningThreshold, @Nullable String errorThreshold, List<String> errors) {
if (!metric.getValueType().equals(RATING.name())) {
return;
}
if (!isCoreRatingMetric(metric.getKey())) {
errors.add(format("The metric '%s' cannot be used", metric.getShortName()));
}
if (period != null && !metric.getKey().startsWith("new_")) {
errors.add(format("The metric '%s' cannot be used on the leak period", metric.getShortName()));
}
if (!isValidRating(warningThreshold)) {
addInvalidRatingError(warningThreshold, errors);
return;

+ 0
- 3
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConverter.java View File

@@ -49,9 +49,6 @@ public class QualityGateConverter {
JsonObject result = new JsonObject();
result.addProperty("metric", condition.getMetricKey());
result.addProperty("op", condition.getOperator().getDbValue());
if (condition.isOnLeakPeriod()) {
result.addProperty("period", 1);
}
condition.getWarningThreshold().ifPresent(t -> result.addProperty("warning", t));
condition.getErrorThreshold().ifPresent(t -> result.addProperty("error", t));
evaluatedCondition.getValue().ifPresent(v -> result.addProperty("actual", v));

+ 1
- 1
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateUpdater.java View File

@@ -60,7 +60,7 @@ public class QualityGateUpdater {
for (QualityGateConditionDto sourceCondition : dbClient.gateConditionDao().selectForQualityGate(dbSession, qualityGateDto.getId())) {
dbClient.gateConditionDao().insert(new QualityGateConditionDto().setQualityGateId(destinationGate.getId())
.setMetricId(sourceCondition.getMetricId()).setOperator(sourceCondition.getOperator())
.setWarningThreshold(sourceCondition.getWarningThreshold()).setErrorThreshold(sourceCondition.getErrorThreshold()).setPeriod(sourceCondition.getPeriod()),
.setWarningThreshold(sourceCondition.getWarningThreshold()).setErrorThreshold(sourceCondition.getErrorThreshold()),
dbSession);
}


+ 9
- 23
server/sonar-server/src/main/java/org/sonar/server/qualitygate/RegisterQualityGates.java View File

@@ -56,15 +56,14 @@ public class RegisterQualityGates implements Startable {
private static final Logger LOGGER = Loggers.get(RegisterQualityGates.class);

private static final String BUILTIN_QUALITY_GATE_NAME = "Sonar way";
private static final int LEAK_PERIOD = 1;
private static final String A_RATING = Integer.toString(Rating.A.getIndex());

private static final List<QualityGateCondition> QUALITY_GATE_CONDITIONS = asList(
new QualityGateCondition().setMetricKey(NEW_SECURITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setPeriod(LEAK_PERIOD).setErrorThreshold(A_RATING),
new QualityGateCondition().setMetricKey(NEW_RELIABILITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setPeriod(LEAK_PERIOD).setErrorThreshold(A_RATING),
new QualityGateCondition().setMetricKey(NEW_MAINTAINABILITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setPeriod(LEAK_PERIOD).setErrorThreshold(A_RATING),
new QualityGateCondition().setMetricKey(NEW_COVERAGE_KEY).setOperator(OPERATOR_LESS_THAN).setPeriod(LEAK_PERIOD).setErrorThreshold("80"),
new QualityGateCondition().setMetricKey(NEW_DUPLICATED_LINES_DENSITY_KEY).setOperator(OPERATOR_GREATER_THAN).setPeriod(LEAK_PERIOD).setErrorThreshold("3"));
new QualityGateCondition().setMetricKey(NEW_SECURITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold(A_RATING),
new QualityGateCondition().setMetricKey(NEW_RELIABILITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold(A_RATING),
new QualityGateCondition().setMetricKey(NEW_MAINTAINABILITY_RATING_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold(A_RATING),
new QualityGateCondition().setMetricKey(NEW_COVERAGE_KEY).setOperator(OPERATOR_LESS_THAN).setErrorThreshold("80"),
new QualityGateCondition().setMetricKey(NEW_DUPLICATED_LINES_DENSITY_KEY).setOperator(OPERATOR_GREATER_THAN).setErrorThreshold("3"));

private final DbClient dbClient;
private final QualityGateConditionsUpdater qualityGateConditionsUpdater;
@@ -122,16 +121,16 @@ public class RegisterQualityGates implements Startable {
// Those conditions must be deleted
List<QualityGateCondition> qgConditionsToBeDeleted = new ArrayList<>(qualityGateConditions);
qgConditionsToBeDeleted.removeAll(QUALITY_GATE_CONDITIONS);
qgConditionsToBeDeleted.stream()
qgConditionsToBeDeleted
.forEach(qgc -> qualityGateConditionDao.delete(qgc.toQualityGateDto(builtin.getId()), dbSession));

// Find all conditions that are not present in qualityGateConditions
// Those conditions must be created
List<QualityGateCondition> qgConditionsToBeCreated = new ArrayList<>(QUALITY_GATE_CONDITIONS);
qgConditionsToBeCreated.removeAll(qualityGateConditions);
qgConditionsToBeCreated.stream()
qgConditionsToBeCreated
.forEach(qgc -> qualityGateConditionsUpdater.createCondition(dbSession, builtin, qgc.getMetricKey(), qgc.getOperator(), qgc.getWarningThreshold(),
qgc.getErrorThreshold(), qgc.getPeriod()));
qgc.getErrorThreshold()));

if (!qgConditionsToBeCreated.isEmpty() || !qgConditionsToBeDeleted.isEmpty()) {
LOGGER.info("Built-in quality gate's conditions of [{}] has been updated", BUILTIN_QUALITY_GATE_NAME);
@@ -155,7 +154,6 @@ public class RegisterQualityGates implements Startable {
private static class QualityGateCondition {
private Long id;
private String metricKey;
private Integer period;
private String operator;
private String warningThreshold;
private String errorThreshold;
@@ -165,7 +163,6 @@ public class RegisterQualityGates implements Startable {
.setId(qualityGateConditionDto.getId())
.setMetricKey(mapping.get(qualityGateConditionDto.getMetricId()))
.setOperator(qualityGateConditionDto.getOperator())
.setPeriod(qualityGateConditionDto.getPeriod())
.setErrorThreshold(qualityGateConditionDto.getErrorThreshold())
.setWarningThreshold(qualityGateConditionDto.getWarningThreshold());
}
@@ -189,15 +186,6 @@ public class RegisterQualityGates implements Startable {
return this;
}

public Integer getPeriod() {
return period;
}

public QualityGateCondition setPeriod(Integer period) {
this.period = period;
return this;
}

public String getOperator() {
return operator;
}
@@ -232,7 +220,6 @@ public class RegisterQualityGates implements Startable {
.setId(id)
.setMetricKey(metricKey)
.setOperator(operator)
.setPeriod(period)
.setErrorThreshold(errorThreshold)
.setWarningThreshold(warningThreshold)
.setQualityGateId(qualityGateId);
@@ -249,7 +236,6 @@ public class RegisterQualityGates implements Startable {
}
QualityGateCondition that = (QualityGateCondition) o;
return Objects.equals(metricKey, that.metricKey) &&
Objects.equals(period, that.period) &&
Objects.equals(operator, that.operator) &&
Objects.equals(warningThreshold, that.warningThreshold) &&
Objects.equals(errorThreshold, that.errorThreshold);
@@ -258,7 +244,7 @@ public class RegisterQualityGates implements Startable {
// id does not belongs to hashcode to be able to be compared with builtin
@Override
public int hashCode() {
return Objects.hash(metricKey, period, operator, warningThreshold, errorThreshold);
return Objects.hash(metricKey, operator, warningThreshold, errorThreshold);
}
}
}

+ 1
- 4
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateConditionAction.java View File

@@ -38,7 +38,6 @@ import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ERR
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_ID;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_METRIC;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_OPERATOR;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PERIOD;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_WARNING;
import static org.sonar.server.ws.WsUtils.writeProtobuf;

@@ -81,20 +80,18 @@ public class CreateConditionAction implements QualityGatesWsAction {
String operator = request.mandatoryParam(PARAM_OPERATOR);
String warning = request.param(PARAM_WARNING);
String error = request.param(PARAM_ERROR);
Integer period = request.paramAsInt(PARAM_PERIOD);

try (DbSession dbSession = dbClient.openSession(false)) {
OrganizationDto organization = wsSupport.getOrganization(dbSession, request);
QGateWithOrgDto qualityGate = wsSupport.getByOrganizationAndId(dbSession, organization, gateId);
wsSupport.checkCanEdit(qualityGate);
QualityGateConditionDto condition = qualityGateConditionsUpdater.createCondition(dbSession, qualityGate, metric, operator, emptyToNull(warning), emptyToNull(error), period);
QualityGateConditionDto condition = qualityGateConditionsUpdater.createCondition(dbSession, qualityGate, metric, operator, emptyToNull(warning), emptyToNull(error));
CreateConditionResponse.Builder createConditionResponse = CreateConditionResponse.newBuilder()
.setId(condition.getId())
.setMetric(condition.getMetricKey())
.setOp(condition.getOperator());
setNullable(condition.getWarningThreshold(), createConditionResponse::setWarning);
setNullable(condition.getErrorThreshold(), createConditionResponse::setError);
setNullable(condition.getPeriod(), createConditionResponse::setPeriod);
writeProtobuf(createConditionResponse.build(), request, response);
dbSession.commit();
}

+ 0
- 5
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWs.java View File

@@ -30,7 +30,6 @@ import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.CONTROLLE
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ERROR;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_METRIC;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_OPERATOR;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PERIOD;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_WARNING;

public class QualityGatesWs implements WebService {
@@ -85,10 +84,6 @@ public class QualityGatesWs implements WebService {
.setExampleValue(QualityGateConditionDto.OPERATOR_EQUALS)
.setPossibleValues(QualityGateConditionDto.ALL_OPERATORS);

action.createParam(PARAM_PERIOD)
.setDescription("Condition period. If not set, the absolute value is considered.")
.setPossibleValues("1");

action.createParam(PARAM_WARNING)
.setMaximumLength(CONDITION_MAX_LENGTH)
.setDescription("Condition warning threshold")

+ 0
- 1
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWsParameters.java View File

@@ -40,7 +40,6 @@ public class QualityGatesWsParameters {
public static final String PARAM_NAME = "name";
public static final String PARAM_ERROR = "error";
public static final String PARAM_WARNING = "warning";
public static final String PARAM_PERIOD = "period";
public static final String PARAM_OPERATOR = "op";
public static final String PARAM_METRIC = "metric";
public static final String PARAM_GATE_ID = "gateId";

+ 0
- 1
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java View File

@@ -142,7 +142,6 @@ public class ShowAction implements QualityGatesWsAction {
.setId(condition.getId())
.setMetric(metric.getKey())
.setOp(condition.getOperator());
setNullable(condition.getPeriod(), builder::setPeriod);
setNullable(condition.getErrorThreshold(), builder::setError);
setNullable(condition.getWarningThreshold(), builder::setWarning);
return builder.build();

+ 1
- 4
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/UpdateConditionAction.java View File

@@ -39,7 +39,6 @@ import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ERR
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ID;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_METRIC;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_OPERATOR;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PERIOD;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_WARNING;
import static org.sonar.server.ws.WsUtils.writeProtobuf;

@@ -81,7 +80,6 @@ public class UpdateConditionAction implements QualityGatesWsAction {
String operator = request.mandatoryParam(PARAM_OPERATOR);
String warning = request.param(PARAM_WARNING);
String error = request.param(PARAM_ERROR);
Integer period = request.paramAsInt(PARAM_PERIOD);

try (DbSession dbSession = dbClient.openSession(false)) {
OrganizationDto organization = wsSupport.getOrganization(dbSession, request);
@@ -90,14 +88,13 @@ public class UpdateConditionAction implements QualityGatesWsAction {
checkState(qualityGateDto != null, "Condition '%s' is linked to an unknown quality gate '%s'", id, condition.getQualityGateId());
wsSupport.checkCanEdit(qualityGateDto);
QualityGateConditionDto updatedCondition = qualityGateConditionsUpdater.updateCondition(dbSession, condition, metric, operator,
emptyToNull(warning), emptyToNull(error), period);
emptyToNull(warning), emptyToNull(error));
UpdateConditionResponse.Builder updateConditionResponse = UpdateConditionResponse.newBuilder()
.setId(updatedCondition.getId())
.setMetric(updatedCondition.getMetricKey())
.setOp(updatedCondition.getOperator());
setNullable(updatedCondition.getWarningThreshold(), updateConditionResponse::setWarning);
setNullable(updatedCondition.getErrorThreshold(), updateConditionResponse::setError);
setNullable(updatedCondition.getPeriod(), updateConditionResponse::setPeriod);
writeProtobuf(updateConditionResponse.build(), request, response);
dbSession.commit();
}

+ 0
- 1
server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json View File

@@ -11,7 +11,6 @@
{
"id": 3,
"metric": "critical_violations",
"period": 1,
"op": "LT",
"warning": "0"
}

+ 13
- 11
server/sonar-server/src/test/java/org/sonar/server/measure/live/LiveQualityGateComputerImplTest.java View File

@@ -101,23 +101,20 @@ public class LiveQualityGateComputerImplTest {
MetricDto metric = db.measures().insertMetric();
QGateWithOrgDto gate = db.qualityGates().insertQualityGate(organization);
db.qualityGates().setDefaultQualityGate(organization, gate);
QualityGateConditionDto leakCondition = db.qualityGates().addCondition(gate, metric, c -> c.setPeriod(1));
QualityGateConditionDto absoluteCondition = db.qualityGates().addCondition(gate, metric, c -> c.setPeriod(null));
QualityGateConditionDto condition = db.qualityGates().addCondition(gate, metric);

QualityGate result = underTest.loadQualityGate(db.getSession(), organization, project, branch);

assertThat(result.getId()).isEqualTo("" + gate.getId());
assertThat(result.getConditions())
.extracting(Condition::getMetricKey, Condition::getOperator, c -> c.getErrorThreshold().get(), c -> c.getWarningThreshold().get(), Condition::isOnLeakPeriod)
.extracting(Condition::getMetricKey, Condition::getOperator, c -> c.getErrorThreshold().get(), c -> c.getWarningThreshold().get())
.containsExactlyInAnyOrder(
tuple(metric.getKey(), Condition.Operator.fromDbValue(leakCondition.getOperator()), leakCondition.getErrorThreshold(), leakCondition.getWarningThreshold(), true),
tuple(metric.getKey(), Condition.Operator.fromDbValue(absoluteCondition.getOperator()), absoluteCondition.getErrorThreshold(), absoluteCondition.getWarningThreshold(),
false));
tuple(metric.getKey(), Condition.Operator.fromDbValue(condition.getOperator()), condition.getErrorThreshold(), condition.getWarningThreshold()));
}

@Test
public void getMetricsRelatedTo() {
Condition condition = new Condition("metric1", Condition.Operator.EQUALS, "10", null, false);
Condition condition = new Condition("metric1", Condition.Operator.EQUALS, "10", null);
QualityGate gate = new QualityGate("1", "foo", ImmutableSet.of(condition));

Set<String> result = underTest.getMetricsRelatedTo(gate);
@@ -135,7 +132,7 @@ public class LiveQualityGateComputerImplTest {
MetricDto conditionMetric = newMetricDto();
MetricDto statusMetric = newMetricDto().setKey(CoreMetrics.ALERT_STATUS_KEY);
MetricDto detailsMetric = newMetricDto().setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY);
Condition condition = new Condition(conditionMetric.getKey(), Condition.Operator.GREATER_THAN, "10", null, false);
Condition condition = new Condition(conditionMetric.getKey(), Condition.Operator.GREATER_THAN, "10", null);
QualityGate gate = new QualityGate("1", "foo", ImmutableSet.of(condition));
MeasureMatrix matrix = new MeasureMatrix(singleton(project), asList(conditionMetric, statusMetric, detailsMetric), emptyList());

@@ -159,13 +156,15 @@ public class LiveQualityGateComputerImplTest {
public void refreshGateStatus_provides_measures_to_evaluator() {
ComponentDto project = ComponentTesting.newPublicProjectDto(newOrganizationDto());
MetricDto numericMetric = newMetricDto().setValueType(Metric.ValueType.FLOAT.name());
MetricDto numericNewMetric = newMetricDto().setValueType(Metric.ValueType.FLOAT.name()).setKey("new_metric");
MetricDto stringMetric = newMetricDto().setValueType(Metric.ValueType.STRING.name());
MetricDto statusMetric = newMetricDto().setKey(CoreMetrics.ALERT_STATUS_KEY);
MetricDto detailsMetric = newMetricDto().setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY);
QualityGate gate = new QualityGate("1", "foo", Collections.emptySet());
LiveMeasureDto numericMeasure = new LiveMeasureDto().setMetricId(numericMetric.getId()).setValue(1.23).setVariation(4.56).setComponentUuid(project.uuid());
LiveMeasureDto numericNewMeasure = new LiveMeasureDto().setMetricId(numericNewMetric.getId()).setValue(7.8).setVariation(8.9).setComponentUuid(project.uuid());
LiveMeasureDto stringMeasure = new LiveMeasureDto().setMetricId(stringMetric.getId()).setData("bar").setComponentUuid(project.uuid());
MeasureMatrix matrix = new MeasureMatrix(singleton(project), asList(statusMetric, detailsMetric, numericMetric, stringMetric), asList(numericMeasure, stringMeasure));
MeasureMatrix matrix = new MeasureMatrix(singleton(project), asList(statusMetric, detailsMetric, numericMetric, numericNewMetric, stringMetric), asList(numericMeasure, numericNewMeasure, stringMeasure));

underTest.refreshGateStatus(project, gate, matrix);

@@ -174,14 +173,17 @@ public class LiveQualityGateComputerImplTest {
QualityGateEvaluator.Measure loadedStringMeasure = measures.get(stringMetric.getKey()).get();
assertThat(loadedStringMeasure.getStringValue()).hasValue("bar");
assertThat(loadedStringMeasure.getValue()).isEmpty();
assertThat(loadedStringMeasure.getLeakValue()).isEmpty();
assertThat(loadedStringMeasure.getType()).isEqualTo(Metric.ValueType.STRING);

QualityGateEvaluator.Measure loadedNumericMeasure = measures.get(numericMetric.getKey()).get();
assertThat(loadedNumericMeasure.getStringValue()).isEmpty();
assertThat(loadedNumericMeasure.getValue()).hasValue(1.23);
assertThat(loadedNumericMeasure.getLeakValue()).hasValue(4.56);
assertThat(loadedNumericMeasure.getType()).isEqualTo(Metric.ValueType.FLOAT);

QualityGateEvaluator.Measure loadedNumericNewMeasure = measures.get(numericNewMetric.getKey()).get();
assertThat(loadedNumericNewMeasure.getStringValue()).isEmpty();
assertThat(loadedNumericNewMeasure.getNewMetricValue()).hasValue(8.9);
assertThat(loadedNumericNewMeasure.getType()).isEqualTo(Metric.ValueType.FLOAT);
}

private static class TestQualityGateEvaluator implements QualityGateEvaluator {

+ 39
- 138
server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConditionsUpdaterTest.java View File

@@ -61,23 +61,13 @@ public class QualityGateConditionsUpdaterTest {
private QualityGateConditionsUpdater underTest = new QualityGateConditionsUpdater(db.getDbClient());

@Test
public void create_warning_condition_without_period() {
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());

QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", "90", null, null);

verifyCondition(result, qualityGate, metric, "LT", "90", null, null);
}

@Test
public void create_error_condition_on_leak_period() {
public void create_error_condition() {
MetricDto metric = db.measures().insertMetric(m -> m.setKey("new_coverage").setValueType(INT.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());

QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", null, "80", 1);
QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", null, "80");

verifyCondition(result, qualityGate, metric, "LT", null, "80", 1);
verifyCondition(result, qualityGate, metric, "LT", null, "80");
}

@Test
@@ -89,19 +79,7 @@ public class QualityGateConditionsUpdaterTest {
expectedException.expect(BadRequestException.class);
expectedException.expectMessage(format("Condition on metric '%s' already exists.", metric.getShortName()));

underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", "90", null, null);
}

@Test
public void fail_to_create_condition_when_condition_on_same_metric_and_on_leak_period_already_exist() {
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
db.qualityGates().addCondition(qualityGate, metric, c -> c.setPeriod(1));

expectedException.expect(BadRequestException.class);
expectedException.expectMessage(format("Condition on metric '%s' over leak period already exists.", metric.getShortName()));

underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", "90", null, 1);
underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", "90", null);
}

@Test
@@ -111,7 +89,7 @@ public class QualityGateConditionsUpdaterTest {
expectedException.expect(NotFoundException.class);
expectedException.expectMessage("There is no metric with key=new_coverage");

underTest.createCondition(db.getSession(), qualityGate, "new_coverage", "LT", null, "80", 2);
underTest.createCondition(db.getSession(), qualityGate, "new_coverage", "LT", null, "80");
}

@Test
@@ -123,7 +101,7 @@ public class QualityGateConditionsUpdaterTest {
expectedException.expect(BadRequestException.class);
expectedException.expectMessage(format("Metric '%s' cannot be used to define a condition.", metric.getKey()));

underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", null, "80", null);
underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", null, "80");
}

@Test
@@ -134,29 +112,7 @@ public class QualityGateConditionsUpdaterTest {
expectedException.expect(BadRequestException.class);
expectedException.expectMessage("Operator UNKNOWN is not allowed for metric type PERCENT.");

underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "UNKNOWN", null, "80", 2);
}

@Test
public void fail_to_create_condition_on_missing_period() {
MetricDto metric = db.measures().insertMetric(m -> m.setKey("new_coverage").setValueType(INT.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());

expectedException.expect(BadRequestException.class);
expectedException.expectMessage("A period must be selected for differential metrics.");

underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", null, "90", null);
}

@Test
public void fail_to_create_condition_on_invalid_period() {
MetricDto metric = db.measures().insertMetric(m -> m.setKey("new_coverage").setValueType(INT.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());

expectedException.expect(BadRequestException.class);
expectedException.expectMessage("The only valid quality gate period is 1, the leak period.");

underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", null, "90", 6);
underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "UNKNOWN", null, "80");
}

@Test
@@ -164,20 +120,9 @@ public class QualityGateConditionsUpdaterTest {
MetricDto metric = db.measures().insertMetric(m -> m.setKey(SQALE_RATING_KEY).setValueType(RATING.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());

QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", null, "3", null);
QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", null, "3");

verifyCondition(result, qualityGate, metric, "GT", null, "3", null);
}

@Test
public void fail_to_create_condition_on_rating_metric_on_leak_period() {
MetricDto metric = db.measures().insertMetric(m -> m.setKey(SQALE_RATING_KEY).setValueType(RATING.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());

expectedException.expect(BadRequestException.class);
expectedException.expectMessage(format("The metric '%s' cannot be used on the leak period", metric.getShortName()));

underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", null, "3", 1);
verifyCondition(result, qualityGate, metric, "GT", null, "3");
}

@Test
@@ -188,7 +133,7 @@ public class QualityGateConditionsUpdaterTest {
expectedException.expect(BadRequestException.class);
expectedException.expectMessage("'6' is not a valid rating");

underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "6", null, null);
underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "6", null);
}

@Test
@@ -199,7 +144,7 @@ public class QualityGateConditionsUpdaterTest {
expectedException.expect(BadRequestException.class);
expectedException.expectMessage("'80' is not a valid rating");

underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", null, "80", null);
underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", null, "80");
}

@Test
@@ -210,7 +155,7 @@ public class QualityGateConditionsUpdaterTest {
expectedException.expect(BadRequestException.class);
expectedException.expectMessage("There's no worse rating than E (5)");

underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "5", null, null);
underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "5", null);
}

@Test
@@ -219,9 +164,9 @@ public class QualityGateConditionsUpdaterTest {
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());

QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", value, null, null);
QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", value, null);

verifyCondition(result, qualityGate, metric, "EQ", value, null, null);
verifyCondition(result, qualityGate, metric, "EQ", value, null);
}

@Test
@@ -230,9 +175,9 @@ public class QualityGateConditionsUpdaterTest {
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());

QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", null, value, null);
QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", null, value);

verifyCondition(result, qualityGate, metric, "EQ", null, value, null);
verifyCondition(result, qualityGate, metric, "EQ", null, value);
}

@Test
@@ -244,7 +189,7 @@ public class QualityGateConditionsUpdaterTest {
expectedException.expect(BadRequestException.class);
expectedException.expectMessage(format("Invalid value '%s' for metric '%s'", value, metric.getShortName()));

underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", value, null, null);
underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", value, null);
}

@Test
@@ -256,7 +201,7 @@ public class QualityGateConditionsUpdaterTest {
expectedException.expect(BadRequestException.class);
expectedException.expectMessage(format("Invalid value '%s' for metric '%s'", value, metric.getShortName()));

underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", null, value, null);
underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", null, value);
}

@Test
@@ -264,23 +209,11 @@ public class QualityGateConditionsUpdaterTest {
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80").setPeriod(null));

QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "60", null, 1);

verifyCondition(result, qualityGate, metric, "GT", "60", null, 1);
}

@Test
public void update_condition_over_leak_period() {
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("GT").setWarningThreshold("80").setErrorThreshold(null).setPeriod(1));
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80"));

QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "LT", null, "80", null);
QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "60", null);

verifyCondition(result, qualityGate, metric, "LT", null, "80", null);
verifyCondition(result, qualityGate, metric, "GT", "60", null);
}

@Test
@@ -288,24 +221,11 @@ public class QualityGateConditionsUpdaterTest {
MetricDto metric = db.measures().insertMetric(m -> m.setKey(SQALE_RATING_KEY).setValueType(RATING.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("LT").setWarningThreshold("80").setErrorThreshold(null).setPeriod(1));
c -> c.setOperator("LT").setWarningThreshold("80").setErrorThreshold(null));

QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4", null, null);
QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4", null);

verifyCondition(result, qualityGate, metric, "GT", "4", null, null);
}

@Test
public void fail_to_update_condition_on_rating_metric_on_leak_period() {
MetricDto metric = db.measures().insertMetric(m -> m.setKey(SQALE_RATING_KEY).setValueType(RATING.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("3").setPeriod(null));

expectedException.expect(BadRequestException.class);
expectedException.expectMessage(format("The metric '%s' cannot be used on the leak period", metric.getShortName()));

underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4", null, 1);
verifyCondition(result, qualityGate, metric, "GT", "4", null);
}

@Test
@@ -313,12 +233,12 @@ public class QualityGateConditionsUpdaterTest {
MetricDto metric = db.measures().insertMetric(m -> m.setKey("not_core_rating_metric").setValueType(RATING.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("3").setPeriod(null));
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("3"));

expectedException.expect(BadRequestException.class);
expectedException.expectMessage(format("The metric '%s' cannot be used", metric.getShortName()));

underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4", null, 1);
underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4", null);
}

@Test
@@ -327,28 +247,12 @@ public class QualityGateConditionsUpdaterTest {
MetricDto metric = db.measures().insertMetric(m -> m.setKey(metricKey).setValueType(valueType.name()).setHidden(hidden));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80").setPeriod(null));
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80"));

expectedException.expect(BadRequestException.class);
expectedException.expectMessage(format("Metric '%s' cannot be used to define a condition.", metric.getKey()));

underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "60", null, 1);
}

@Test
public void fail_to_update_condition_when_condition_on_same_metric_already_exist() {
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(INT.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
QualityGateConditionDto conditionNotOnLeakPeriod = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("GT").setWarningThreshold("80").setErrorThreshold(null).setPeriod(null));
QualityGateConditionDto conditionOnLeakPeriod = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("GT").setWarningThreshold("80").setErrorThreshold(null).setPeriod(1));

expectedException.expect(BadRequestException.class);
expectedException.expectMessage(format("Condition on metric '%s' over leak period already exists.", metric.getShortName()));

// Update condition not on leak period to be on leak period => will fail as this condition already exist
underTest.updateCondition(db.getSession(), conditionNotOnLeakPeriod, metric.getKey(), "GT", "80", null, 1);
underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "60", null);
}

@Test
@@ -357,11 +261,11 @@ public class QualityGateConditionsUpdaterTest {
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80").setPeriod(null));
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80"));

QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", value, null, null);
QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", value, null);

verifyCondition(result, qualityGate, metric, "EQ", value, null, null);
verifyCondition(result, qualityGate, metric, "EQ", value, null);
}

@Test
@@ -370,11 +274,11 @@ public class QualityGateConditionsUpdaterTest {
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80").setPeriod(null));
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80"));

QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", null, value, null);
QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", null, value);

verifyCondition(result, qualityGate, metric, "EQ", null, value, null);
verifyCondition(result, qualityGate, metric, "EQ", null, value);
}

@Test
@@ -383,12 +287,12 @@ public class QualityGateConditionsUpdaterTest {
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80").setPeriod(null));
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80"));

expectedException.expect(BadRequestException.class);
expectedException.expectMessage(format("Invalid value '%s' for metric '%s'", value, metric.getShortName()));

underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", value, null, null);
underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", value, null);
}

@Test
@@ -397,12 +301,12 @@ public class QualityGateConditionsUpdaterTest {
MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80").setPeriod(null));
c -> c.setOperator("LT").setWarningThreshold(null).setErrorThreshold("80"));

expectedException.expect(BadRequestException.class);
expectedException.expectMessage(format("Invalid value '%s' for metric '%s'", value, metric.getShortName()));

underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", null, value, null);
underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", null, value);
}

@DataProvider
@@ -438,22 +342,19 @@ public class QualityGateConditionsUpdaterTest {
};
}

private void verifyCondition(QualityGateConditionDto dto, QualityGateDto qualityGate, MetricDto metric, String operator, @Nullable String warning, @Nullable String error,
@Nullable Integer period) {
private void verifyCondition(QualityGateConditionDto dto, QualityGateDto qualityGate, MetricDto metric, String operator, @Nullable String warning, @Nullable String error) {
QualityGateConditionDto reloaded = db.getDbClient().gateConditionDao().selectById(dto.getId(), db.getSession());
assertThat(reloaded.getQualityGateId()).isEqualTo(qualityGate.getId());
assertThat(reloaded.getMetricId()).isEqualTo(metric.getId().longValue());
assertThat(reloaded.getOperator()).isEqualTo(operator);
assertThat(reloaded.getWarningThreshold()).isEqualTo(warning);
assertThat(reloaded.getErrorThreshold()).isEqualTo(error);
assertThat(reloaded.getPeriod()).isEqualTo(period);

assertThat(dto.getQualityGateId()).isEqualTo(qualityGate.getId());
assertThat(dto.getMetricId()).isEqualTo(metric.getId().longValue());
assertThat(dto.getOperator()).isEqualTo(operator);
assertThat(dto.getWarningThreshold()).isEqualTo(warning);
assertThat(dto.getErrorThreshold()).isEqualTo(error);
assertThat(dto.getPeriod()).isEqualTo(period);
}

}

+ 12
- 13
server/sonar-server/src/test/java/org/sonar/server/qualitygate/RegisterQualityGatesTest.java View File

@@ -61,7 +61,6 @@ public class RegisterQualityGatesTest {
@Rule
public LogTester logTester = new LogTester();

private static final int LEAK_PERIOD = 1;
private static final String BUILT_IN_NAME = "Sonar way";

private DbClient dbClient = db.getDbClient();
@@ -108,7 +107,7 @@ public class RegisterQualityGatesTest {
createBuiltInConditions(builtInQualityGate);
// Add another condition
qualityGateConditionsUpdater.createCondition(dbSession, builtInQualityGate,
NEW_SECURITY_REMEDIATION_EFFORT_KEY, OPERATOR_GREATER_THAN, null, "5", LEAK_PERIOD);
NEW_SECURITY_REMEDIATION_EFFORT_KEY, OPERATOR_GREATER_THAN, null, "5");
dbSession.commit();

underTest.start();
@@ -252,28 +251,28 @@ public class RegisterQualityGatesTest {
assertThat(qualityGateDto.isBuiltIn()).isTrue();
assertThat(gateConditionDao.selectForQualityGate(dbSession, qualityGateDto.getId()))
.extracting(QualityGateConditionDto::getMetricId, QualityGateConditionDto::getOperator, QualityGateConditionDto::getWarningThreshold,
QualityGateConditionDto::getErrorThreshold, QualityGateConditionDto::getPeriod)
QualityGateConditionDto::getErrorThreshold)
.containsOnly(
tuple(newReliability.getId().longValue(), OPERATOR_GREATER_THAN, null, "1", 1),
tuple(newSecurity.getId().longValue(), OPERATOR_GREATER_THAN, null, "1", 1),
tuple(newMaintainability.getId().longValue(), OPERATOR_GREATER_THAN, null, "1", 1),
tuple(newCoverage.getId().longValue(), OPERATOR_LESS_THAN, null, "80", 1),
tuple(newDuplication.getId().longValue(), OPERATOR_GREATER_THAN, null, "3", 1));
tuple(newReliability.getId().longValue(), OPERATOR_GREATER_THAN, null, "1"),
tuple(newSecurity.getId().longValue(), OPERATOR_GREATER_THAN, null, "1"),
tuple(newMaintainability.getId().longValue(), OPERATOR_GREATER_THAN, null, "1"),
tuple(newCoverage.getId().longValue(), OPERATOR_LESS_THAN, null, "80"),
tuple(newDuplication.getId().longValue(), OPERATOR_GREATER_THAN, null, "3"));
}

private List<QualityGateConditionDto> createBuiltInConditions(QualityGateDto qg) {
List<QualityGateConditionDto> conditions = new ArrayList<>();

conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg,
NEW_SECURITY_RATING_KEY, OPERATOR_GREATER_THAN, null, "1", LEAK_PERIOD));
NEW_SECURITY_RATING_KEY, OPERATOR_GREATER_THAN, null, "1"));
conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg,
NEW_RELIABILITY_RATING_KEY, OPERATOR_GREATER_THAN, null, "1", LEAK_PERIOD));
NEW_RELIABILITY_RATING_KEY, OPERATOR_GREATER_THAN, null, "1"));
conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg,
NEW_MAINTAINABILITY_RATING_KEY, OPERATOR_GREATER_THAN, null, "1", LEAK_PERIOD));
NEW_MAINTAINABILITY_RATING_KEY, OPERATOR_GREATER_THAN, null, "1"));
conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg,
NEW_COVERAGE_KEY, OPERATOR_LESS_THAN, null, "80", LEAK_PERIOD));
NEW_COVERAGE_KEY, OPERATOR_LESS_THAN, null, "80"));
conditions.add(qualityGateConditionsUpdater.createCondition(dbSession, qg,
NEW_DUPLICATED_LINES_DENSITY_KEY, OPERATOR_GREATER_THAN, null, "3", LEAK_PERIOD));
NEW_DUPLICATED_LINES_DENSITY_KEY, OPERATOR_GREATER_THAN, null, "3"));

return conditions;
}

+ 2
- 2
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CopyActionTest.java View File

@@ -109,8 +109,8 @@ public class CopyActionTest {
assertThat(actual.getUuid()).isNotEqualTo(qualityGate.getUuid());

assertThat(db.getDbClient().gateConditionDao().selectForQualityGate(dbSession, qualityGate.getId()))
.extracting(c-> (int) c.getMetricId(), QualityGateConditionDto::getPeriod, QualityGateConditionDto::getWarningThreshold, QualityGateConditionDto::getErrorThreshold)
.containsExactlyInAnyOrder(tuple(metric.getId(), condition.getPeriod(), condition.getWarningThreshold(), condition.getErrorThreshold()));
.extracting(c-> (int) c.getMetricId(), QualityGateConditionDto::getWarningThreshold, QualityGateConditionDto::getErrorThreshold)
.containsExactlyInAnyOrder(tuple(metric.getId(), condition.getWarningThreshold(), condition.getErrorThreshold()));
}

@Test

+ 2
- 7
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateConditionActionTest.java View File

@@ -50,7 +50,6 @@ import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GAT
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_METRIC;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_OPERATOR;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ORGANIZATION;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PERIOD;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_WARNING;

public class CreateConditionActionTest {
@@ -120,7 +119,6 @@ public class CreateConditionActionTest {
.setParam(PARAM_METRIC, metric.getKey())
.setParam(PARAM_OPERATOR, "LT")
.setParam(PARAM_ERROR, "90")
.setParam(PARAM_PERIOD, "1")
.setParam(PARAM_ORGANIZATION, organization.getKey())
.execute();

@@ -216,7 +214,6 @@ public class CreateConditionActionTest {
.setParam(PARAM_OPERATOR, "LT")
.setParam(PARAM_ERROR, "45")
.setParam(PARAM_WARNING, "90")
.setParam(PARAM_PERIOD, "1")
.setParam(PARAM_ORGANIZATION, organization.getKey())
.executeProtobuf(CreateConditionResponse.class);

@@ -226,7 +223,6 @@ public class CreateConditionActionTest {
assertThat(response.getOp()).isEqualTo("LT");
assertThat(response.getWarning()).isEqualTo("90");
assertThat(response.getError()).isEqualTo("45");
assertThat(response.getPeriod()).isEqualTo(1);
}

@Test
@@ -260,7 +256,6 @@ public class CreateConditionActionTest {
.containsExactlyInAnyOrder(
tuple("gateId", true),
tuple("metric", true),
tuple("period", false),
tuple("op", false),
tuple("warning", false),
tuple("error", false),
@@ -270,8 +265,8 @@ public class CreateConditionActionTest {
private void assertCondition(QualityGateDto qualityGate, MetricDto metric, String operator, @Nullable String warning, @Nullable String error, @Nullable Integer period) {
assertThat(dbClient.gateConditionDao().selectForQualityGate(dbSession, qualityGate.getId()))
.extracting(QualityGateConditionDto::getQualityGateId, QualityGateConditionDto::getMetricId, QualityGateConditionDto::getOperator,
QualityGateConditionDto::getWarningThreshold, QualityGateConditionDto::getErrorThreshold, QualityGateConditionDto::getPeriod)
.containsExactlyInAnyOrder(tuple(qualityGate.getId(), metric.getId().longValue(), operator, warning, error, period));
QualityGateConditionDto::getWarningThreshold, QualityGateConditionDto::getErrorThreshold)
.containsExactlyInAnyOrder(tuple(qualityGate.getId(), metric.getId().longValue(), operator, warning, error));
}

private void logInAsQualityGateAdmin(OrganizationDto organization) {

+ 9
- 8
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java View File

@@ -72,9 +72,10 @@ public class ShowActionTest {
OrganizationDto organization = db.organizations().insert();
QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization);
db.qualityGates().setDefaultQualityGate(organization, qualityGate);
MetricDto metric = db.measures().insertMetric();
QualityGateConditionDto condition1 = db.qualityGates().addCondition(qualityGate, metric, c -> c.setOperator("GT").setPeriod(null));
QualityGateConditionDto condition2 = db.qualityGates().addCondition(qualityGate, metric, c -> c.setOperator("LT").setPeriod(1));
MetricDto metric1 = db.measures().insertMetric();
MetricDto metric2 = db.measures().insertMetric();
QualityGateConditionDto condition1 = db.qualityGates().addCondition(qualityGate, metric1, c -> c.setOperator("GT"));
QualityGateConditionDto condition2 = db.qualityGates().addCondition(qualityGate, metric2, c -> c.setOperator("LT"));

ShowWsResponse response = ws.newRequest()
.setParam("name", qualityGate.getName())
@@ -86,10 +87,10 @@ public class ShowActionTest {
assertThat(response.getIsBuiltIn()).isFalse();
assertThat(response.getConditionsList()).hasSize(2);
assertThat(response.getConditionsList())
.extracting(Condition::getId, Condition::getMetric, Condition::hasPeriod, Condition::getPeriod, Condition::getOp, Condition::getError, Condition::getWarning)
.extracting(Condition::getId, Condition::getMetric, Condition::getOp, Condition::getError, Condition::getWarning)
.containsExactlyInAnyOrder(
tuple(condition1.getId(), metric.getKey(), false, 0, "GT", condition1.getErrorThreshold(), condition1.getWarningThreshold()),
tuple(condition2.getId(), metric.getKey(), true, 1, "LT", condition2.getErrorThreshold(), condition2.getWarningThreshold()));
tuple(condition1.getId(), metric1.getKey(), "GT", condition1.getErrorThreshold(), condition1.getWarningThreshold()),
tuple(condition2.getId(), metric2.getKey(), "LT", condition2.getErrorThreshold(), condition2.getWarningThreshold()));
}

@Test
@@ -397,8 +398,8 @@ public class ShowActionTest {
db.qualityGates().setDefaultQualityGate(organization, qualityGate2);
MetricDto blockerViolationsMetric = db.measures().insertMetric(m -> m.setKey("blocker_violations"));
MetricDto criticalViolationsMetric = db.measures().insertMetric(m -> m.setKey("critical_violations"));
db.qualityGates().addCondition(qualityGate, blockerViolationsMetric, c -> c.setOperator("GT").setPeriod(null).setErrorThreshold("0").setWarningThreshold(null));
db.qualityGates().addCondition(qualityGate, criticalViolationsMetric, c -> c.setOperator("LT").setPeriod(1).setErrorThreshold(null).setWarningThreshold("0"));
db.qualityGates().addCondition(qualityGate, blockerViolationsMetric, c -> c.setOperator("GT").setErrorThreshold("0").setWarningThreshold(null));
db.qualityGates().addCondition(qualityGate, criticalViolationsMetric, c -> c.setOperator("LT").setErrorThreshold(null).setWarningThreshold("0"));

String response = ws.newRequest()
.setParam("name", qualityGate.getName())

+ 13
- 39
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/UpdateConditionActionTest.java View File

@@ -51,7 +51,6 @@ import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ID;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_METRIC;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_OPERATOR;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ORGANIZATION;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PERIOD;
import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_WARNING;

public class UpdateConditionActionTest {
@@ -80,7 +79,7 @@ public class UpdateConditionActionTest {
QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization);
MetricDto metric = insertMetric();
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("GT").setWarningThreshold(null).setErrorThreshold("80").setPeriod(null));
c -> c.setOperator("GT").setWarningThreshold(null).setErrorThreshold("80"));

ws.newRequest()
.setParam(PARAM_ORGANIZATION, organization.getKey())
@@ -90,7 +89,7 @@ public class UpdateConditionActionTest {
.setParam(PARAM_WARNING, "90")
.execute();

assertCondition(qualityGate, metric, "LT", "90", null, null);
assertCondition(qualityGate, metric, "LT", "90", null);
}

@Test
@@ -100,7 +99,7 @@ public class UpdateConditionActionTest {
QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization);
MetricDto metric = insertMetric();
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("GT").setWarningThreshold(null).setErrorThreshold("80").setPeriod(null));
c -> c.setOperator("GT").setWarningThreshold(null).setErrorThreshold("80"));

ws.newRequest()
.setParam(PARAM_ORGANIZATION, organization.getKey())
@@ -110,28 +109,7 @@ public class UpdateConditionActionTest {
.setParam(PARAM_ERROR, "90")
.execute();

assertCondition(qualityGate, metric, "LT", null, "90", null);
}

@Test
public void update_condition_over_leak_period() {
OrganizationDto organization = db.organizations().insert();
userSession.addPermission(ADMINISTER_QUALITY_GATES, organization);
QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization);
MetricDto metric = insertMetric();
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("GT").setWarningThreshold(null).setErrorThreshold("80").setPeriod(null));

ws.newRequest()
.setParam(PARAM_ORGANIZATION, organization.getKey())
.setParam(PARAM_ID, Long.toString(condition.getId()))
.setParam(PARAM_METRIC, metric.getKey())
.setParam(PARAM_OPERATOR, "LT")
.setParam(PARAM_ERROR, "90")
.setParam(PARAM_PERIOD, "1")
.execute();

assertCondition(qualityGate, metric, "LT", null, "90", 1);
assertCondition(qualityGate, metric, "LT", null, "90");
}

@Test
@@ -148,7 +126,7 @@ public class UpdateConditionActionTest {
.setParam(PARAM_WARNING, "90")
.execute();

assertCondition(qualityGate, metric, "LT", "90", null, null);
assertCondition(qualityGate, metric, "LT", "90", null);
}

@Test
@@ -158,7 +136,7 @@ public class UpdateConditionActionTest {
QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization);
MetricDto metric = insertMetric();
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("GT").setWarningThreshold(null).setErrorThreshold("80").setPeriod(null));
c -> c.setOperator("GT").setWarningThreshold(null).setErrorThreshold("80"));

ws.newRequest()
.setParam(PARAM_ORGANIZATION, organization.getKey())
@@ -169,7 +147,7 @@ public class UpdateConditionActionTest {
.setParam(PARAM_ERROR, "")
.execute();

assertCondition(qualityGate, metric, "LT", "90", null, null);
assertCondition(qualityGate, metric, "LT", "90", null);
}

@Test
@@ -179,7 +157,7 @@ public class UpdateConditionActionTest {
QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization);
MetricDto metric = insertMetric();
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("GT").setWarningThreshold(null).setErrorThreshold("80").setPeriod(null));
c -> c.setOperator("GT").setWarningThreshold(null).setErrorThreshold("80"));

ws.newRequest()
.setParam(PARAM_ORGANIZATION, organization.getKey())
@@ -190,7 +168,7 @@ public class UpdateConditionActionTest {
.setParam(PARAM_WARNING, "")
.execute();

assertCondition(qualityGate, metric, "LT", null, "90", null);
assertCondition(qualityGate, metric, "LT", null, "90");
}

@Test
@@ -200,7 +178,7 @@ public class UpdateConditionActionTest {
QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization);
MetricDto metric = insertMetric();
QualityGateConditionDto condition = db.qualityGates().addCondition(qualityGate, metric,
c -> c.setOperator("GT").setWarningThreshold(null).setErrorThreshold("80").setPeriod(null));
c -> c.setOperator("GT").setWarningThreshold(null).setErrorThreshold("80"));

CreateConditionResponse response = ws.newRequest()
.setParam(PARAM_ORGANIZATION, organization.getKey())
@@ -209,7 +187,6 @@ public class UpdateConditionActionTest {
.setParam(PARAM_OPERATOR, "LT")
.setParam(PARAM_WARNING, "90")
.setParam(PARAM_ERROR, "45")
.setParam(PARAM_PERIOD, "1")
.executeProtobuf(CreateConditionResponse.class);

assertThat(response.getId()).isEqualTo(condition.getId());
@@ -217,7 +194,6 @@ public class UpdateConditionActionTest {
assertThat(response.getOp()).isEqualTo("LT");
assertThat(response.getWarning()).isEqualTo("90");
assertThat(response.getError()).isEqualTo("45");
assertThat(response.getPeriod()).isEqualTo(1);
}

@Test
@@ -313,7 +289,6 @@ public class UpdateConditionActionTest {
.containsExactlyInAnyOrder(
tuple("id", true),
tuple("metric", true),
tuple("period", false),
tuple("op", false),
tuple("warning", false),
tuple("error", false),
@@ -321,15 +296,14 @@ public class UpdateConditionActionTest {

}

private void assertCondition(QualityGateDto qualityGate, MetricDto metric, String operator, @Nullable String warning, @Nullable String error, @Nullable Integer period) {
private void assertCondition(QualityGateDto qualityGate, MetricDto metric, String operator, @Nullable String warning, @Nullable String error) {
assertThat(dbClient.gateConditionDao().selectForQualityGate(dbSession, qualityGate.getId()))
.extracting(QualityGateConditionDto::getQualityGateId, QualityGateConditionDto::getMetricId, QualityGateConditionDto::getOperator,
QualityGateConditionDto::getWarningThreshold, QualityGateConditionDto::getErrorThreshold, QualityGateConditionDto::getPeriod)
.containsExactlyInAnyOrder(tuple(qualityGate.getId(), metric.getId().longValue(), operator, warning, error, period));
QualityGateConditionDto::getWarningThreshold, QualityGateConditionDto::getErrorThreshold)
.containsExactlyInAnyOrder(tuple(qualityGate.getId(), metric.getId().longValue(), operator, warning, error));
}

private MetricDto insertMetric() {
return db.measures().insertMetric(m -> m.setValueType(INT.name()).setHidden(false));
}

}

+ 15
- 7
sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/PostProjectAnalysisTaskTester.java View File

@@ -81,7 +81,6 @@ import static java.util.Objects.requireNonNull;
* .setMetricKey("metric key")
* .setOperator(QualityGate.Operator.GREATER_THAN)
* .setErrorThreshold("12")
* .setOnLeakPeriod(true)
* .build(QualityGate.EvaluationStatus.OK, "value"))
* .build())
* .execute();
@@ -516,7 +515,6 @@ public class PostProjectAnalysisTaskTester {
private QualityGate.Operator operator;
private String errorThreshold;
private String warningThreshold;
private boolean onLeakPeriod;

private ConditionBuilder() {
// prevents instantiation outside PostProjectAnalysisTaskTester
@@ -542,8 +540,12 @@ public class PostProjectAnalysisTaskTester {
return this;
}

/**
* @deprecated in 7.6. This method has no longer any effect.
* Conditions "on leak period" were removed. Use "New X" conditions instead.
*/
@Deprecated
public ConditionBuilder setOnLeakPeriod(boolean onLeakPeriod) {
this.onLeakPeriod = onLeakPeriod;
return this;
}

@@ -575,9 +577,13 @@ public class PostProjectAnalysisTaskTester {
return warningThreshold;
}

/**
* @deprecated in 7.6. Conditions "on leak period" were removed. Use "New X" conditions instead.
*/
@Deprecated
@Override
public boolean isOnLeakPeriod() {
return onLeakPeriod;
return false;
}

@Override
@@ -593,7 +599,6 @@ public class PostProjectAnalysisTaskTester {
", operator=" + operator +
", errorThreshold='" + errorThreshold + '\'' +
", warningThreshold='" + warningThreshold + '\'' +
", onLeakPeriod=" + onLeakPeriod +
'}';
}
};
@@ -630,9 +635,13 @@ public class PostProjectAnalysisTaskTester {
return warningThreshold;
}

/**
* @deprecated in 7.6. Conditions "on leak period" were removed. Use "New X" conditions instead.
*/
@Deprecated
@Override
public boolean isOnLeakPeriod() {
return onLeakPeriod;
return false;
}

@Override
@@ -648,7 +657,6 @@ public class PostProjectAnalysisTaskTester {
", operator=" + operator +
", errorThreshold='" + errorThreshold + '\'' +
", warningThreshold='" + warningThreshold + '\'' +
", onLeakPeriod=" + onLeakPeriod +
", value='" + value + '\'' +
'}';
}

+ 4
- 1
sonar-plugin-api/src/main/java/org/sonar/api/ce/posttask/QualityGate.java View File

@@ -100,8 +100,11 @@ public interface QualityGate {
String getWarningThreshold();

/**
* Whether this condition is defined on the leak period or on an absolute value
* Whether this condition is defined on the leak period or on an absolute value.
* @deprecated in 7.6. Implementations should always return false.
* Conditions "on leak period" were removed. Use "New X" conditions instead.
*/
@Deprecated
boolean isOnLeakPeriod();

/**

+ 2
- 25
sonar-plugin-api/src/test/java/org/sonar/api/ce/posttask/ConditionBuilder_PostProjectAnalysisTaskTesterTest.java View File

@@ -130,7 +130,7 @@ public class ConditionBuilder_PostProjectAnalysisTaskTesterTest {
assertThat(underTest.buildNoValue().toString())
.isEqualTo(
"Condition{status=NO_VALUE, metricKey='some metric key', operator=GREATER_THAN, " +
"errorThreshold='some error threshold', warningThreshold='some warning threshold', onLeakPeriod=false}");
"errorThreshold='some error threshold', warningThreshold='some warning threshold'}");
}

@Test
@@ -143,7 +143,6 @@ public class ConditionBuilder_PostProjectAnalysisTaskTesterTest {
assertThat(condition.getOperator()).isEqualTo(SOME_OPERATOR);
assertThat(condition.getErrorThreshold()).isEqualTo(SOME_ERROR_THRESHOLD);
assertThat(condition.getWarningThreshold()).isEqualTo(SOME_WARNING_THRESHOLD);
assertThat(condition.isOnLeakPeriod()).isTrue();
}

@Test
@@ -234,7 +233,7 @@ public class ConditionBuilder_PostProjectAnalysisTaskTesterTest {
assertThat(underTest.build(SOME_STATUS_BUT_NO_VALUE, SOME_VALUE).toString())
.isEqualTo(
"Condition{status=OK, metricKey='some metric key', operator=GREATER_THAN, "
+ "errorThreshold='some error threshold', warningThreshold='some warning threshold', onLeakPeriod=false, value='some value'}");
+ "errorThreshold='some error threshold', warningThreshold='some warning threshold', value='some value'}");
}

@Test
@@ -266,31 +265,9 @@ public class ConditionBuilder_PostProjectAnalysisTaskTesterTest {
assertThat(condition.getOperator()).isEqualTo(SOME_OPERATOR);
assertThat(condition.getErrorThreshold()).isEqualTo(SOME_ERROR_THRESHOLD);
assertThat(condition.getWarningThreshold()).isEqualTo(SOME_WARNING_THRESHOLD);
assertThat(condition.isOnLeakPeriod()).isTrue();
assertThat(condition.getValue()).isEqualTo(SOME_VALUE);
}

@Test
public void isOnLeakPeriod_is_false_by_default() {
initValidBuilder();

assertThat(underTest.buildNoValue().isOnLeakPeriod()).isFalse();
assertThat(underTest.build(SOME_STATUS_BUT_NO_VALUE, SOME_VALUE).isOnLeakPeriod()).isFalse();
}

@Test
public void isOnLeakPeriod_changes_isOnLeakPeriod_returned_value() {
initValidBuilder().setOnLeakPeriod(true);

assertThat(underTest.buildNoValue().isOnLeakPeriod()).isTrue();
assertThat(underTest.build(SOME_STATUS_BUT_NO_VALUE, SOME_VALUE).isOnLeakPeriod()).isTrue();

initValidBuilder().setOnLeakPeriod(false);

assertThat(underTest.buildNoValue().isOnLeakPeriod()).isFalse();
assertThat(underTest.build(SOME_STATUS_BUT_NO_VALUE, SOME_VALUE).isOnLeakPeriod()).isFalse();
}

private PostProjectAnalysisTaskTester.ConditionBuilder initValidBuilder() {
underTest.setMetricKey(SOME_METRIC_KEY).setOperator(SOME_OPERATOR).setErrorThreshold(SOME_ERROR_THRESHOLD).setWarningThreshold(SOME_WARNING_THRESHOLD);
return underTest;

+ 0
- 16
sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygates/CreateConditionRequest.java View File

@@ -36,7 +36,6 @@ public class CreateConditionRequest {
private String metric;
private String op;
private String organization;
private String period;
private String warning;

/**
@@ -108,21 +107,6 @@ public class CreateConditionRequest {
return organization;
}

/**
* Possible values:
* <ul>
* <li>"1"</li>
* </ul>
*/
public CreateConditionRequest setPeriod(String period) {
this.period = period;
return this;
}

public String getPeriod() {
return period;
}

/**
* Example value: "5"
*/

+ 0
- 2
sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygates/QualitygatesService.java View File

@@ -92,7 +92,6 @@ public class QualitygatesService extends BaseService {
.setParam("metric", request.getMetric())
.setParam("op", request.getOp())
.setParam("organization", request.getOrganization())
.setParam("period", request.getPeriod())
.setParam("warning", request.getWarning()),
CreateConditionResponse.parser());
}
@@ -308,7 +307,6 @@ public class QualitygatesService extends BaseService {
.setParam("metric", request.getMetric())
.setParam("op", request.getOp())
.setParam("organization", request.getOrganization())
.setParam("period", request.getPeriod())
.setParam("warning", request.getWarning()),
UpdateConditionResponse.parser());
}

+ 0
- 16
sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygates/UpdateConditionRequest.java View File

@@ -36,7 +36,6 @@ public class UpdateConditionRequest {
private String metric;
private String op;
private String organization;
private String period;
private String warning;

/**
@@ -108,21 +107,6 @@ public class UpdateConditionRequest {
return organization;
}

/**
* Possible values:
* <ul>
* <li>"1"</li>
* </ul>
*/
public UpdateConditionRequest setPeriod(String period) {
this.period = period;
return this;
}

public String getPeriod() {
return period;
}

/**
* Example value: "5"
*/

+ 0
- 3
sonar-ws/src/main/protobuf/ws-qualitygates.proto View File

@@ -105,7 +105,6 @@ message CreateConditionResponse {
optional string op = 3;
optional string warning = 4;
optional string error = 5;
optional int32 period = 6;
}

// POST api/qualitygates/update_condition
@@ -115,7 +114,6 @@ message UpdateConditionResponse {
optional string op = 3;
optional string warning = 4;
optional string error = 5;
optional int32 period = 6;
}

// GET api/qualitygates/show
@@ -129,7 +127,6 @@ message ShowWsResponse {
message Condition {
optional int64 id = 1;
optional string metric = 2;
optional int32 period = 3;
optional string op = 4;
optional string warning = 5;
optional string error = 6;

Loading…
Cancel
Save