]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5182 Add input validation on quality gate conditions
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 29 Mar 2018 15:20:25 +0000 (17:20 +0200)
committerSonarTech <sonartech@sonarsource.com>
Fri, 6 Apr 2018 18:21:51 +0000 (20:21 +0200)
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateConditionsUpdater.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/CreateConditionAction.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/UpdateConditionAction.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateConditionsUpdaterTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/CreateConditionActionTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/UpdateConditionActionTest.java
tests/src/test/java/org/sonarqube/tests/qualityGate/QualityGateTest.java
tests/src/test/java/util/ItUtils.java

index d91c1c837e0922da553489e68a061a2002c8e8dc..0a70ed55ad613438a8dc4c0db0c528e076b9628e 100644 (file)
@@ -38,7 +38,9 @@ import org.sonar.server.computation.task.projectanalysis.qualitymodel.Rating;
 import org.sonar.server.exceptions.NotFoundException;
 
 import static com.google.common.base.Strings.isNullOrEmpty;
+import static java.lang.Double.parseDouble;
 import static java.lang.Integer.parseInt;
+import static java.lang.Long.parseLong;
 import static java.lang.String.format;
 import static java.util.Arrays.stream;
 import static org.sonar.api.measures.Metric.ValueType.RATING;
@@ -115,6 +117,9 @@ public class QualityGateConditionsUpdater {
     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);
     checkRequest(errors.isEmpty(), errors);
   }
@@ -159,6 +164,37 @@ public class QualityGateConditionsUpdater {
       : format("Condition on metric '%s' over leak period already exists.", metric.getShortName()));
   }
 
+  private static void validateThresholdValues(MetricDto metric, @Nullable String value, List<String> errors) {
+    if (value == null) {
+      return;
+    }
+    try {
+      ValueType valueType = ValueType.valueOf(metric.getValueType());
+      switch (valueType) {
+        case BOOL:
+        case INT:
+        case RATING:
+          parseInt(value);
+          return;
+        case MILLISEC:
+        case WORK_DUR:
+          parseLong(value);
+          return;
+        case FLOAT:
+        case PERCENT:
+          parseDouble(value);
+          return;
+        case STRING:
+        case LEVEL:
+          return;
+        default:
+          throw new IllegalArgumentException(format("Unsupported value type %s. Cannot convert condition value", valueType));
+      }
+    } catch (Exception e) {
+      errors.add(format("Invalid value '%s' for metric '%s'", value, metric.getShortName()));
+    }
+  }
+
   private static void checkRatingMetric(MetricDto metric, @Nullable String warningThreshold, @Nullable String errorThreshold, @Nullable Integer period, List<String> errors) {
     if (!metric.getValueType().equals(RATING.name())) {
       return;
index ef9d4d6ee6d0b29761b4665e11470c1a93dea9c1..0b40b6c776ef082898e6e685ebee7e3be66afce1 100644 (file)
@@ -31,6 +31,7 @@ import org.sonar.server.qualitygate.QualityGateConditionsUpdater;
 import org.sonar.server.qualitygate.QualityGateFinder;
 import org.sonarqube.ws.Qualitygates.CreateConditionResponse;
 
+import static com.google.common.base.Strings.emptyToNull;
 import static org.sonar.core.util.Protobuf.setNullable;
 import static org.sonar.server.qualitygate.ws.QualityGatesWs.addConditionParams;
 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.ACTION_CREATE_CONDITION;
@@ -89,7 +90,7 @@ public class CreateConditionAction implements QualityGatesWsAction {
       OrganizationDto organization = wsSupport.getOrganization(dbSession, request);
       QGateWithOrgDto qualityGate = qualityGateFinder.getByOrganizationAndId(dbSession, organization, gateId);
       wsSupport.checkCanEdit(qualityGate);
-      QualityGateConditionDto condition = qualityGateConditionsUpdater.createCondition(dbSession, qualityGate, metric, operator, warning, error, period);
+      QualityGateConditionDto condition = qualityGateConditionsUpdater.createCondition(dbSession, qualityGate, metric, operator, emptyToNull(warning), emptyToNull(error), period);
       CreateConditionResponse.Builder createConditionResponse = CreateConditionResponse.newBuilder()
         .setId(condition.getId())
         .setMetric(condition.getMetricKey())
index d5365ef5423dd8adb9f726ed908edbf44831d1a0..dcdb8b6e29f70504964c054ec2d971eb76cc8466 100644 (file)
@@ -31,6 +31,7 @@ import org.sonar.server.qualitygate.QualityGateConditionsUpdater;
 import org.sonarqube.ws.Qualitygates.UpdateConditionResponse;
 
 import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Strings.emptyToNull;
 import static org.sonar.core.util.Protobuf.setNullable;
 import static org.sonar.server.qualitygate.ws.QualityGatesWs.addConditionParams;
 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.ACTION_UPDATE_CONDITION;
@@ -88,7 +89,7 @@ public class UpdateConditionAction implements QualityGatesWsAction {
       QGateWithOrgDto qualityGateDto = dbClient.qualityGateDao().selectByOrganizationAndId(dbSession, organization, condition.getQualityGateId());
       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, warning, error, period);
+      QualityGateConditionDto updatedCondition = qualityGateConditionsUpdater.updateCondition(dbSession, condition, metric, operator, emptyToNull(warning), emptyToNull(error), period);
       UpdateConditionResponse.Builder updateConditionResponse = UpdateConditionResponse.newBuilder()
         .setId(updatedCondition.getId())
         .setMetric(updatedCondition.getMetricKey())
index 74c4583f7a9505cd51a6781d9681f452e80f5171..22693231eecddea3be333e8f0946b1abdacc618d 100644 (file)
@@ -23,30 +23,31 @@ import com.tngtech.java.junit.dataprovider.DataProvider;
 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
 import com.tngtech.java.junit.dataprovider.UseDataProvider;
 import javax.annotation.Nullable;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
 import org.sonar.api.measures.Metric;
 import org.sonar.api.utils.System2;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.metric.MetricDto;
 import org.sonar.db.qualitygate.QualityGateConditionDto;
-import org.sonar.db.qualitygate.QualityGateDbTester;
 import org.sonar.db.qualitygate.QualityGateDto;
 import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.NotFoundException;
 
+import static java.lang.String.format;
 import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
 import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY;
+import static org.sonar.api.measures.CoreMetrics.SQALE_RATING_KEY;
+import static org.sonar.api.measures.Metric.ValueType.BOOL;
 import static org.sonar.api.measures.Metric.ValueType.DATA;
+import static org.sonar.api.measures.Metric.ValueType.FLOAT;
 import static org.sonar.api.measures.Metric.ValueType.INT;
+import static org.sonar.api.measures.Metric.ValueType.MILLISEC;
+import static org.sonar.api.measures.Metric.ValueType.PERCENT;
 import static org.sonar.api.measures.Metric.ValueType.RATING;
-import static org.sonar.db.metric.MetricTesting.newMetricDto;
-import static org.sonar.server.computation.task.projectanalysis.metric.Metric.MetricType.PERCENT;
+import static org.sonar.api.measures.Metric.ValueType.WORK_DUR;
 
 @RunWith(DataProviderRunner.class)
 public class QualityGateConditionsUpdaterTest {
@@ -57,234 +58,351 @@ public class QualityGateConditionsUpdaterTest {
   @Rule
   public DbTester db = DbTester.create(System2.INSTANCE);
 
-  DbClient dbClient = db.getDbClient();
-  DbSession dbSession = db.getSession();
-  QualityGateDbTester qualityGateDbTester = new QualityGateDbTester(db);
-
-  QualityGateDto qualityGateDto;
-  MetricDto coverageMetricDto = newMetricDto()
-    .setKey("coverage")
-    .setShortName("Coverage")
-    .setValueType(PERCENT.name())
-    .setHidden(false);
-
-  MetricDto ratingMetricDto = newMetricDto()
-    .setKey("reliability_rating")
-    .setShortName("Reliability Rating")
-    .setValueType(RATING.name())
-    .setHidden(false);
-
-  QualityGateConditionsUpdater underTest = new QualityGateConditionsUpdater(dbClient);
-
-  @Before
-  public void setUp() throws Exception {
-    qualityGateDto = qualityGateDbTester.insertQualityGate(db.getDefaultOrganization());
-    dbClient.metricDao().insert(dbSession, coverageMetricDto, ratingMetricDto);
-    dbSession.commit();
-  }
+  private QualityGateConditionsUpdater underTest = new QualityGateConditionsUpdater(db.getDbClient());
 
   @Test
   public void create_warning_condition_without_period() {
-    QualityGateConditionDto result = underTest.createCondition(dbSession, qualityGateDto, "coverage", "LT", "90", null, null);
+    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, coverageMetricDto.getId(), "LT", "90", null, null);
+    verifyCondition(result, qualityGate, metric, "LT", "90", null, null);
   }
 
   @Test
-  public void create_error_condition_with_period() {
-    MetricDto metricDto = dbClient.metricDao().insert(dbSession, newMetricDto()
-      .setKey("new_coverage")
-      .setValueType(INT.name())
-      .setHidden(false));
-    dbSession.commit();
+  public void create_error_condition_on_leak_period() {
+    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(dbSession, qualityGateDto, "new_coverage", "LT", null, "80", 1);
+    QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "LT", null, "80", 1);
 
-    verifyCondition(result, metricDto.getId(), "LT", null, "80", 1);
+    verifyCondition(result, qualityGate, metric, "LT", null, "80", 1);
   }
 
   @Test
   public void fail_to_create_condition_when_condition_on_same_metric_already_exist() {
-    dbClient.gateConditionDao().insert(new QualityGateConditionDto()
-      .setQualityGateId(qualityGateDto.getId())
-      .setMetricId(coverageMetricDto.getId())
-      .setPeriod(null),
-      dbSession);
+    MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false));
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
+    db.qualityGates().addCondition(qualityGate, metric);
 
     expectedException.expect(BadRequestException.class);
-    expectedException.expectMessage("Condition on metric 'Coverage' already exists.");
-    underTest.createCondition(dbSession, qualityGateDto, coverageMetricDto.getKey(), "LT", "90", null, null);
+    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() {
-    dbClient.gateConditionDao().insert(new QualityGateConditionDto()
-      .setQualityGateId(qualityGateDto.getId())
-      .setMetricId(coverageMetricDto.getId())
-      .setPeriod(1),
-      dbSession);
+    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("Condition on metric 'Coverage' over leak period already exists.");
-    underTest.createCondition(dbSession, qualityGateDto, coverageMetricDto.getKey(), "LT", "90", null, 1);
+    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);
   }
 
   @Test
   public void fail_to_create_condition_on_missing_metric() {
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
+
     expectedException.expect(NotFoundException.class);
     expectedException.expectMessage("There is no metric with key=new_coverage");
-    underTest.createCondition(dbSession, qualityGateDto, "new_coverage", "LT", null, "80", 2);
+
+    underTest.createCondition(db.getSession(), qualityGate, "new_coverage", "LT", null, "80", 2);
   }
 
   @Test
   @UseDataProvider("invalid_metrics")
   public void fail_to_create_condition_on_invalid_metric(String metricKey, Metric.ValueType valueType, boolean hidden) {
-    dbClient.metricDao().insert(dbSession, newMetricDto()
-      .setKey(metricKey)
-      .setValueType(valueType.name())
-      .setHidden(hidden));
-    dbSession.commit();
+    MetricDto metric = db.measures().insertMetric(m -> m.setKey(metricKey).setValueType(valueType.name()).setHidden(hidden));
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
 
     expectedException.expect(BadRequestException.class);
-    expectedException.expectMessage("Metric '" + metricKey + "' cannot be used to define a condition.");
-    underTest.createCondition(dbSession, qualityGateDto, metricKey, "EQ", null, "80", null);
+    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);
   }
 
   @Test
   public void fail_to_create_condition_on_not_allowed_operator() {
+    MetricDto metric = db.measures().insertMetric(m -> m.setValueType(PERCENT.name()).setHidden(false));
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
+
     expectedException.expect(BadRequestException.class);
     expectedException.expectMessage("Operator UNKNOWN is not allowed for metric type PERCENT.");
-    underTest.createCondition(dbSession, qualityGateDto, "coverage", "UNKNOWN", null, "80", 2);
+
+    underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "UNKNOWN", null, "80", 2);
   }
 
   @Test
   public void fail_to_create_condition_on_missing_period() {
-    dbClient.metricDao().insert(dbSession, newMetricDto()
-      .setKey("new_coverage")
-      .setValueType(INT.name())
-      .setHidden(false));
-    dbSession.commit();
+    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(dbSession, qualityGateDto, "new_coverage", "EQ", null, "90", null);
+
+    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(dbSession, qualityGateDto, "coverage", "EQ", null, "90", 6);
+
+    underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "EQ", null, "90", 6);
   }
 
   @Test
   public void create_condition_on_rating_metric() {
-    QualityGateConditionDto result = underTest.createCondition(dbSession, qualityGateDto, ratingMetricDto.getKey(), "GT", null, "3", null);
+    MetricDto metric = db.measures().insertMetric(m -> m.setKey(SQALE_RATING_KEY).setValueType(RATING.name()).setHidden(false));
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
 
-    verifyCondition(result, ratingMetricDto.getId(), "GT", null, "3", null);
+    QualityGateConditionDto result = underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", null, "3", null);
+
+    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("The metric 'Reliability Rating' cannot be used on the leak period");
-    underTest.createCondition(dbSession, qualityGateDto, ratingMetricDto.getKey(), "GT", null, "3", 1);
+    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);
   }
 
   @Test
   public void fail_to_create_warning_condition_on_invalid_rating_metric() {
+    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("'6' is not a valid rating");
-    underTest.createCondition(dbSession, qualityGateDto, ratingMetricDto.getKey(), "GT", "6", null, null);
+
+    underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "6", null, null);
   }
 
   @Test
   public void fail_to_create_error_condition_on_invalid_rating_metric() {
+    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("'80' is not a valid rating");
-    underTest.createCondition(dbSession, qualityGateDto, ratingMetricDto.getKey(), "GT", null, "80", null);
+
+    underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", null, "80", null);
   }
 
   @Test
   public void fail_to_create_condition_on_greater_than_E() {
+    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("There's no worse rating than E (5)");
-    underTest.createCondition(dbSession, qualityGateDto, ratingMetricDto.getKey(), "GT", "5", null, null);
+
+    underTest.createCondition(db.getSession(), qualityGate, metric.getKey(), "GT", "5", null, null);
+  }
+
+  @Test
+  @UseDataProvider("valid_values")
+  public void create_warning_condition(Metric.ValueType valueType, String value) {
+    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);
+
+    verifyCondition(result, qualityGate, metric, "EQ", value, null, null);
+  }
+
+  @Test
+  @UseDataProvider("valid_values")
+  public void create_error_condition(Metric.ValueType valueType, String value) {
+    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);
+
+    verifyCondition(result, qualityGate, metric, "EQ", null, value, null);
+  }
+
+  @Test
+  @UseDataProvider("invalid_values")
+  public void fail_to_create_warning_INT_condition_when_value_is_not_an_integer(Metric.ValueType valueType, String value) {
+    MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
+
+    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);
+  }
+
+  @Test
+  @UseDataProvider("invalid_values")
+  public void fail_to_create_error_INT_condition_when_value_is_not_an_integer(Metric.ValueType valueType, String value) {
+    MetricDto metric = db.measures().insertMetric(m -> m.setValueType(valueType.name()).setHidden(false));
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate(db.getDefaultOrganization());
+
+    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);
   }
 
   @Test
   public void update_condition() {
-    QualityGateConditionDto condition = insertCondition(coverageMetricDto.getId(), "LT", null, "80", null);
+    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(dbSession, condition, "coverage", "GT", "60", null, 1);
+    QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "60", null, 1);
 
-    verifyCondition(result, coverageMetricDto.getId(), "GT", "60", null, 1);
+    verifyCondition(result, qualityGate, metric, "GT", "60", null, 1);
   }
 
   @Test
   public void update_condition_over_leak_period() {
-    QualityGateConditionDto condition = insertCondition(coverageMetricDto.getId(), "GT", "80", null, 1);
+    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));
 
-    QualityGateConditionDto result = underTest.updateCondition(dbSession, condition, "coverage", "LT", null, "80", null);
+    QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "LT", null, "80", null);
 
-    verifyCondition(result, coverageMetricDto.getId(), "LT", null, "80", null);
+    verifyCondition(result, qualityGate, metric, "LT", null, "80", null);
   }
 
   @Test
   public void update_condition_on_rating_metric() {
-    QualityGateConditionDto condition = insertCondition(ratingMetricDto.getId(), "LT", null, "3", null);
+    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));
 
-    QualityGateConditionDto result = underTest.updateCondition(dbSession, condition, ratingMetricDto.getKey(), "GT", "4", null, null);
+    QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4", null, null);
 
-    verifyCondition(result, ratingMetricDto.getId(), "GT", "4", null, null);
+    verifyCondition(result, qualityGate, metric, "GT", "4", null, null);
   }
 
   @Test
   public void fail_to_update_condition_on_rating_metric_on_leak_period() {
-    QualityGateConditionDto condition = insertCondition(ratingMetricDto.getId(), "LT", null, "3", null);
+    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("The metric 'Reliability Rating' cannot be used on the leak period");
-    underTest.updateCondition(dbSession, condition, ratingMetricDto.getKey(), "GT", "4", null, 1);
+    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);
   }
 
   @Test
   public void fail_to_update_condition_on_rating_metric_on_not_core_rating_metric() {
-    MetricDto metricDto = dbClient.metricDao().insert(dbSession, newMetricDto().setKey("rating_metric")
-      .setShortName("Not core rating")
-      .setValueType(RATING.name()).setHidden(false));
-    QualityGateConditionDto condition = insertCondition(metricDto.getId(), "LT", null, "3", null);
-    dbSession.commit();
+    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));
 
     expectedException.expect(BadRequestException.class);
-    expectedException.expectMessage("The metric 'Not core rating' cannot be used");
-    underTest.updateCondition(dbSession, condition, metricDto.getKey(), "GT", "4", null, 1);
+    expectedException.expectMessage(format("The metric '%s' cannot be used", metric.getShortName()));
+
+    underTest.updateCondition(db.getSession(), condition, metric.getKey(), "GT", "4", null, 1);
   }
 
   @Test
   @UseDataProvider("invalid_metrics")
   public void fail_to_update_condition_on_invalid_metric(String metricKey, Metric.ValueType valueType, boolean hidden) {
-    MetricDto metricDto = dbClient.metricDao().insert(dbSession, newMetricDto()
-      .setKey(metricKey)
-      .setValueType(valueType.name())
-      .setHidden(hidden));
-    QualityGateConditionDto condition = insertCondition(metricDto.getId(), "LT", null, "80", null);
-    dbSession.commit();
+    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));
 
     expectedException.expect(BadRequestException.class);
-    expectedException.expectMessage("Metric '" + metricKey + "' cannot be used to define a condition.");
-    underTest.updateCondition(dbSession, condition, metricDto.getKey(), "GT", "60", null, 1);
+    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() {
-    QualityGateConditionDto conditionNotOnLeakPeriod = insertCondition(coverageMetricDto.getId(), "GT", "80", null, null);
-    QualityGateConditionDto conditionOnLeakPeriod = insertCondition(coverageMetricDto.getId(), "GT", "80", null, 1);
+    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("Condition on metric 'Coverage' over leak period already exists.");
+    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(dbSession, conditionNotOnLeakPeriod, coverageMetricDto.getKey(), "GT", "80", null, 1);
+    underTest.updateCondition(db.getSession(), conditionNotOnLeakPeriod, metric.getKey(), "GT", "80", null, 1);
+  }
+
+  @Test
+  @UseDataProvider("valid_values")
+  public void update_warning_condition(Metric.ValueType valueType, String value) {
+    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));
+
+    QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", value, null, null);
+
+    verifyCondition(result, qualityGate, metric, "EQ", value, null, null);
+  }
+
+  @Test
+  @UseDataProvider("valid_values")
+  public void update_error_condition(Metric.ValueType valueType, String value) {
+    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));
+
+    QualityGateConditionDto result = underTest.updateCondition(db.getSession(), condition, metric.getKey(), "EQ", null, value, null);
+
+    verifyCondition(result, qualityGate, metric, "EQ", null, value, null);
+  }
+
+  @Test
+  @UseDataProvider("invalid_values")
+  public void fail_to_update_warning_INT_condition_when_value_is_not_an_integer(Metric.ValueType valueType, String value) {
+    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));
+
+    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);
+  }
+
+  @Test
+  @UseDataProvider("invalid_values")
+  public void fail_to_update_error_INT_condition_when_value_is_not_an_integer(Metric.ValueType valueType, String value) {
+    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));
+
+    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);
   }
 
   @DataProvider
@@ -296,30 +414,42 @@ public class QualityGateConditionsUpdaterTest {
     };
   }
 
-  private QualityGateConditionDto insertCondition(long metricId, String operator, @Nullable String warning, @Nullable String error,
+  @DataProvider
+  public static Object[][] valid_values() {
+    return new Object[][] {
+      {INT, "10"},
+      {BOOL, "1"},
+      {MILLISEC, "1000"},
+      {WORK_DUR, "1000"},
+      {FLOAT, "5.12"},
+      {PERCENT, "10.30"},
+    };
+  }
+
+  @DataProvider
+  public static Object[][] invalid_values() {
+    return new Object[][] {
+      {INT, "ABCD"},
+      {BOOL, "ABCD"},
+      {MILLISEC, "ABCD"},
+      {WORK_DUR, "ABCD"},
+      {FLOAT, "ABCD"},
+      {PERCENT, "ABCD"},
+    };
+  }
+
+  private void verifyCondition(QualityGateConditionDto dto, QualityGateDto qualityGate, MetricDto metric, String operator, @Nullable String warning, @Nullable String error,
     @Nullable Integer period) {
-    QualityGateConditionDto qualityGateConditionDto = new QualityGateConditionDto().setQualityGateId(qualityGateDto.getId())
-      .setMetricId(metricId)
-      .setOperator(operator)
-      .setWarningThreshold(warning)
-      .setErrorThreshold(error)
-      .setPeriod(period);
-    dbClient.gateConditionDao().insert(qualityGateConditionDto, dbSession);
-    dbSession.commit();
-    return qualityGateConditionDto;
-  }
-
-  private void verifyCondition(QualityGateConditionDto dto, int metricId, String operator, @Nullable String warning, @Nullable String error, @Nullable Integer period) {
-    QualityGateConditionDto reloaded = dbClient.gateConditionDao().selectById(dto.getId(), dbSession);
-    assertThat(reloaded.getQualityGateId()).isEqualTo(qualityGateDto.getId());
-    assertThat(reloaded.getMetricId()).isEqualTo(metricId);
+    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(qualityGateDto.getId());
-    assertThat(dto.getMetricId()).isEqualTo(metricId);
+    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);
index f4f885a070af5e1e1cc03ff8ef358a64d6870494..01f3bc60e203f340431b2d8e50c2170306363781 100644 (file)
@@ -147,6 +147,44 @@ public class CreateConditionActionTest {
     assertCondition(qualityGate, metric, "LT", "90", null, null);
   }
 
+  @Test
+  public void create_warning_condition_with_empty_string_on_error() {
+    OrganizationDto organization = db.organizations().insert();
+    logInAsQualityGateAdmin(organization);
+    QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization);
+    MetricDto metric = insertMetric();
+
+    ws.newRequest()
+      .setParam(PARAM_GATE_ID, qualityGate.getId().toString())
+      .setParam(PARAM_METRIC, metric.getKey())
+      .setParam(PARAM_OPERATOR, "LT")
+      .setParam(PARAM_WARNING, "90")
+      .setParam(PARAM_ERROR, "")
+      .setParam(PARAM_ORGANIZATION, organization.getKey())
+      .execute();
+
+    assertCondition(qualityGate, metric, "LT", "90", null, null);
+  }
+
+  @Test
+  public void create_error_condition_with_empty_string_on_warning() {
+    OrganizationDto organization = db.organizations().insert();
+    logInAsQualityGateAdmin(organization);
+    QGateWithOrgDto qualityGate = db.qualityGates().insertQualityGate(organization);
+    MetricDto metric = insertMetric();
+
+    ws.newRequest()
+      .setParam(PARAM_GATE_ID, qualityGate.getId().toString())
+      .setParam(PARAM_METRIC, metric.getKey())
+      .setParam(PARAM_OPERATOR, "LT")
+      .setParam(PARAM_WARNING, "")
+      .setParam(PARAM_ERROR, "90")
+      .setParam(PARAM_ORGANIZATION, organization.getKey())
+      .execute();
+
+    assertCondition(qualityGate, metric, "LT", null, "90", null);
+  }
+
   @Test
   public void fail_to_update_built_in_quality_gate() {
     OrganizationDto organization = db.organizations().insert();
index 5b783fc01291b61792ba7e3380b1675478d915bf..f01d7f6ac9165e77b756c4f96f2f1b6a9c5b82ec 100644 (file)
@@ -151,6 +151,48 @@ public class UpdateConditionActionTest {
     assertCondition(qualityGate, metric, "LT", "90", null, null);
   }
 
+  @Test
+  public void update_warning_condition_with_empty_string_on_error() {
+    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_WARNING, "90")
+      .setParam(PARAM_ERROR, "")
+      .execute();
+
+    assertCondition(qualityGate, metric, "LT", "90", null, null);
+  }
+
+  @Test
+  public void update_error_condition_with_empty_string_on_warning() {
+    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_WARNING, "")
+      .execute();
+
+    assertCondition(qualityGate, metric, "LT", null, "90", null);
+  }
+
   @Test
   public void test_response() {
     OrganizationDto organization = db.organizations().insert();
index 7160ac819d88dfbca84c83c10bba82ab208b5aa4..05f7871f36484bfd5ca3078ef1cd1213992bbdd4 100644 (file)
@@ -19,6 +19,7 @@
  */
 package org.sonarqube.tests.qualityGate;
 
+import com.google.common.collect.ImmutableList;
 import com.google.gson.Gson;
 import com.sonar.orchestrator.Orchestrator;
 import com.sonar.orchestrator.build.BuildResult;
@@ -34,49 +35,45 @@ import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
 import org.apache.commons.io.Charsets;
 import org.apache.commons.io.FileUtils;
-import org.junit.After;
-import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
-import org.sonar.wsclient.qualitygate.NewCondition;
-import org.sonar.wsclient.qualitygate.QualityGate;
-import org.sonar.wsclient.qualitygate.QualityGateClient;
+import org.sonarqube.qa.util.QGateTester;
 import org.sonarqube.qa.util.Tester;
-import org.sonarqube.qa.util.TesterSession;
-import org.sonarqube.ws.Ce;
 import org.sonarqube.ws.Measures.Measure;
-import org.sonarqube.ws.MediaTypes;
-import org.sonarqube.ws.Organizations.Organization;
 import org.sonarqube.ws.Projects.CreateWsResponse.Project;
 import org.sonarqube.ws.Qualitygates;
 import org.sonarqube.ws.Qualitygates.CreateResponse;
+import org.sonarqube.ws.Qualitygates.ListWsResponse.QualityGate;
 import org.sonarqube.ws.Qualitygates.ProjectStatusResponse;
 import org.sonarqube.ws.Users;
-import org.sonarqube.ws.client.GetRequest;
-import org.sonarqube.ws.client.PostRequest;
-import org.sonarqube.ws.client.WsResponse;
+import org.sonarqube.ws.client.ce.TaskRequest;
+import org.sonarqube.ws.client.metrics.CreateRequest;
+import org.sonarqube.ws.client.metrics.DeleteRequest;
 import org.sonarqube.ws.client.permissions.AddUserRequest;
 import org.sonarqube.ws.client.qualitygates.CreateConditionRequest;
+import org.sonarqube.ws.client.qualitygates.DeleteConditionRequest;
+import org.sonarqube.ws.client.qualitygates.DestroyRequest;
+import org.sonarqube.ws.client.qualitygates.ListRequest;
 import org.sonarqube.ws.client.qualitygates.ProjectStatusRequest;
-import org.sonarqube.ws.client.qualitygates.QualitygatesService;
 import org.sonarqube.ws.client.qualitygates.SelectRequest;
+import org.sonarqube.ws.client.qualitygates.SetAsDefaultRequest;
 import org.sonarqube.ws.client.qualitygates.UpdateConditionRequest;
 
+import static java.lang.String.format;
 import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.groups.Tuple.tuple;
 import static org.sonarqube.ws.Qualitygates.ProjectStatusResponse.Status.ERROR;
 import static util.ItUtils.concat;
+import static util.ItUtils.expectHttpError;
 import static util.ItUtils.extractCeTaskId;
 import static util.ItUtils.getMeasure;
-import static util.ItUtils.newProjectKey;
 import static util.ItUtils.projectDir;
 
 public class QualityGateTest {
 
   private static final String TASK_STATUS_SUCCESS = "SUCCESS";
-  private static final String QG_STATUS_NO_QG = "null";
   private static final String QG_STATUS_OK = "OK";
   private static final String QG_STATUS_ERROR = "ERROR";
   private static final String QG_STATUS_WARN = "WARN";
@@ -85,114 +82,101 @@ public class QualityGateTest {
   public static Orchestrator orchestrator = QualityGateSuite.ORCHESTRATOR;
 
   @Rule
-  public Tester tester = new Tester(orchestrator)
-    // all the tests of QualityGateSuite must disable organizations
-    .disableOrganizations();
-
-  private QualityGate defaultGate;
-
-  @Before
-  public void setUp() {
-    defaultGate = qgClient().list().defaultGate();
-  }
-
-  @After
-  public void tearDown() {
-    if (defaultGate != null) {
-      qgClient().setDefault(defaultGate.id());
-    }
-  }
+  public Tester tester = new Tester(orchestrator).disableOrganizations();
 
   @Test
   public void status_ok_if_empty_gate() throws Exception {
-    Qualitygates.CreateResponse empty = tester.qGates().generate();
-    qgClient().setDefault(empty.getId());
-
-    String projectKey = newProjectKey();
-    BuildResult buildResult = executeAnalysis(projectKey);
+    Project project = tester.projects().provision();
+    Qualitygates.CreateResponse qualityGate = tester.qGates().generate();
+    tester.qGates().associateProject(qualityGate, project);
+    BuildResult buildResult = executeAnalysis(project.getKey());
 
-    verifyQGStatusInPostTask(buildResult, projectKey, TASK_STATUS_SUCCESS, QG_STATUS_OK);
+    verifyQGStatusInPostTask(buildResult, project.getKey(), TASK_STATUS_SUCCESS, QG_STATUS_OK);
 
-    assertThat(getGateStatusMeasure(projectKey).getValue()).isEqualTo("OK");
+    assertThat(getGateStatusMeasure(project.getKey()).getValue()).isEqualTo("OK");
   }
 
   @Test
   public void test_status_ok() throws IOException {
-    Qualitygates.CreateResponse simple = tester.qGates().generate();
-    qgClient().setDefault(simple.getId());
-    qgClient().createCondition(NewCondition.create(simple.getId()).metricKey("ncloc").operator("GT").warningThreshold("40"));
-
-    String projectKey = newProjectKey();
-    BuildResult buildResult = executeAnalysis(projectKey);
+    Project project = tester.projects().provision();
+    Qualitygates.CreateResponse qualityGate = tester.qGates().generate();
+    tester.qGates().associateProject(qualityGate, project);
+    tester.qGates().service().createCondition(new CreateConditionRequest().setGateId(Long.toString(qualityGate.getId())).setMetric("ncloc").setOp("GT").setWarning("40"));
+    BuildResult buildResult = executeAnalysis(project.getKey());
 
-    verifyQGStatusInPostTask(buildResult, projectKey, TASK_STATUS_SUCCESS, QG_STATUS_OK);
+    verifyQGStatusInPostTask(buildResult, project.getKey(), TASK_STATUS_SUCCESS, QG_STATUS_OK);
 
-    assertThat(getGateStatusMeasure(projectKey).getValue()).isEqualTo("OK");
+    assertThat(getGateStatusMeasure(project.getKey()).getValue()).isEqualTo("OK");
   }
 
   @Test
   public void test_status_warning() throws IOException {
-    Qualitygates.CreateResponse simple = tester.qGates().generate();
-    qgClient().setDefault(simple.getId());
-    qgClient().createCondition(NewCondition.create(simple.getId()).metricKey("ncloc").operator("GT").warningThreshold("10"));
-
-    String projectKey = newProjectKey();
-    BuildResult buildResult = executeAnalysis(projectKey);
+    Project project = tester.projects().provision();
+    Qualitygates.CreateResponse qualityGate = tester.qGates().generate();
+    tester.qGates().associateProject(qualityGate, project);
+    tester.qGates().service().createCondition(new CreateConditionRequest().setGateId(Long.toString(qualityGate.getId())).setMetric("ncloc").setOp("GT").setWarning("10"));
+    BuildResult buildResult = executeAnalysis(project.getKey());
 
-    verifyQGStatusInPostTask(buildResult, projectKey, TASK_STATUS_SUCCESS, QG_STATUS_WARN);
+    verifyQGStatusInPostTask(buildResult, project.getKey(), TASK_STATUS_SUCCESS, QG_STATUS_WARN);
 
-    assertThat(getGateStatusMeasure(projectKey).getValue()).isEqualTo("WARN");
+    assertThat(getGateStatusMeasure(project.getKey()).getValue()).isEqualTo("WARN");
   }
 
   @Test
   public void test_status_error() throws IOException {
-    Qualitygates.CreateResponse simple = tester.qGates().generate();
-    qgClient().setDefault(simple.getId());
-    qgClient().createCondition(NewCondition.create(simple.getId()).metricKey("ncloc").operator("GT").errorThreshold("10"));
-
-    String projectKey = newProjectKey();
-    BuildResult buildResult = executeAnalysis(projectKey);
+    Project project = tester.projects().provision();
+    Qualitygates.CreateResponse qualityGate = tester.qGates().generate();
+    tester.qGates().associateProject(qualityGate, project);
+    tester.qGates().service().createCondition(new CreateConditionRequest().setGateId(Long.toString(qualityGate.getId())).setMetric("ncloc").setOp("GT").setError("10"));
+    BuildResult buildResult = executeAnalysis(project.getKey());
 
-    verifyQGStatusInPostTask(buildResult, projectKey, TASK_STATUS_SUCCESS, QG_STATUS_ERROR);
+    verifyQGStatusInPostTask(buildResult, project.getKey(), TASK_STATUS_SUCCESS, QG_STATUS_ERROR);
 
-    assertThat(getGateStatusMeasure(projectKey).getValue()).isEqualTo("ERROR");
+    assertThat(getGateStatusMeasure(project.getKey()).getValue()).isEqualTo("ERROR");
   }
 
   @Test
   public void use_server_settings_instead_of_default_gate() throws IOException {
-    Qualitygates.CreateResponse alert = tester.qGates().generate();
-    qgClient().createCondition(NewCondition.create(alert.getId()).metricKey("ncloc").operator("GT").warningThreshold("10"));
-    Qualitygates.CreateResponse error = tester.qGates().generate();
-    qgClient().createCondition(NewCondition.create(error.getId()).metricKey("ncloc").operator("GT").errorThreshold("10"));
-
-    qgClient().setDefault(alert.getId());
-    String projectKey = newProjectKey();
-    orchestrator.getServer().provisionProject(projectKey, projectKey);
-    associateQualityGateToProject(error.getId(), projectKey);
+    QualityGate existingDefaultQualityGate = tester.qGates().service().list(new ListRequest()).getQualitygatesList()
+      .stream()
+      .filter(QualityGate::getIsDefault)
+      .findFirst()
+      .orElseThrow(() -> new IllegalStateException("No default quality gate found"));
+    try {
+      Qualitygates.CreateResponse defaultQualityGate = tester.qGates().generate();
+      tester.qGates().service().createCondition(new CreateConditionRequest().setGateId(Long.toString(defaultQualityGate.getId())).setMetric("ncloc").setOp("GT").setWarning("10"));
+      tester.qGates().service().setAsDefault(new SetAsDefaultRequest().setId(Long.toString(defaultQualityGate.getId())));
 
-    BuildResult buildResult = executeAnalysis(projectKey);
+      Project project = tester.projects().provision();
+      Qualitygates.CreateResponse qualityGate = tester.qGates().generate();
+      tester.qGates().service().createCondition(new CreateConditionRequest().setGateId(Long.toString(qualityGate.getId())).setMetric("ncloc").setOp("GT").setError("10"));
+      tester.qGates().associateProject(qualityGate, project);
 
-    verifyQGStatusInPostTask(buildResult, projectKey, TASK_STATUS_SUCCESS, QG_STATUS_ERROR);
+      BuildResult buildResult = executeAnalysis(project.getKey());
 
-    assertThat(getGateStatusMeasure(projectKey).getValue()).isEqualTo("ERROR");
+      verifyQGStatusInPostTask(buildResult, project.getKey(), TASK_STATUS_SUCCESS, QG_STATUS_ERROR);
+      assertThat(getGateStatusMeasure(project.getKey()).getValue()).isEqualTo("ERROR");
+    } finally {
+      tester.qGates().service().setAsDefault(new SetAsDefaultRequest().setId(Long.toString(existingDefaultQualityGate.getId())));
+    }
   }
 
   @Test
   public void conditions_on_multiple_metric_types() throws IOException {
-    Qualitygates.CreateResponse allTypes = tester.qGates().generate();
-    qgClient().createCondition(NewCondition.create(allTypes.getId()).metricKey("ncloc").operator("GT").warningThreshold("10"));
-    qgClient().createCondition(NewCondition.create(allTypes.getId()).metricKey("duplicated_lines_density").operator("GT").warningThreshold("20"));
-    qgClient().setDefault(allTypes.getId());
-
-    String projectKey = newProjectKey();
-    BuildResult buildResult = executeAnalysis(projectKey, "sonar.cpd.xoo.minimumLines", "2", "sonar.cpd.xoo.minimumTokens", "5");
+    Project project = tester.projects().provision();
+    Qualitygates.CreateResponse qualityGate = tester.qGates().generate();
+    tester.qGates().associateProject(qualityGate, project);
+    tester.qGates().service().createCondition(new CreateConditionRequest().setGateId(Long.toString(qualityGate.getId())).setMetric("ncloc").setOp("GT").setWarning("10"));
+    tester.qGates().service()
+      .createCondition(new CreateConditionRequest().setGateId(Long.toString(qualityGate.getId())).setMetric("duplicated_lines_density").setOp("GT").setWarning("20"));
+    BuildResult buildResult = executeAnalysis(project.getKey(), "sonar.cpd.xoo.minimumLines", "2", "sonar.cpd.xoo.minimumTokens", "5");
 
-    verifyQGStatusInPostTask(buildResult, projectKey, TASK_STATUS_SUCCESS, QG_STATUS_WARN);
+    verifyQGStatusInPostTask(buildResult, project.getKey(), TASK_STATUS_SUCCESS, QG_STATUS_WARN);
 
-    Measure alertStatus = getGateStatusMeasure(projectKey);
+    Measure alertStatus = getGateStatusMeasure(project.getKey());
     assertThat(alertStatus.getValue()).isEqualTo("WARN");
 
-    String qualityGateDetailJson = getMeasure(orchestrator, projectKey, "quality_gate_details").getValue();
+    String qualityGateDetailJson = getMeasure(orchestrator, project.getKey(), "quality_gate_details").getValue();
     assertThat(QualityGateDetails.parse(qualityGateDetailJson).getConditions())
       .extracting(QualityGateDetails.Conditions::getMetric, QualityGateDetails.Conditions::getOp, QualityGateDetails.Conditions::getWarning)
       .contains(tuple("ncloc", "GT", "10"), tuple("duplicated_lines_density", "GT", "20"));
@@ -200,19 +184,18 @@ public class QualityGateTest {
 
   @Test
   public void ad_hoc_build_break_strategy() throws IOException {
-    Qualitygates.CreateResponse simple = tester.qGates().generate();
-    qgClient().setDefault(simple.getId());
-    qgClient().createCondition(NewCondition.create(simple.getId()).metricKey("ncloc").operator("GT").errorThreshold("7"));
-
-    String projectKey = newProjectKey();
-    BuildResult buildResult = executeAnalysis(projectKey);
+    Project project = tester.projects().provision();
+    Qualitygates.CreateResponse qualityGate = tester.qGates().generate();
+    tester.qGates().associateProject(qualityGate, project);
+    tester.qGates().service().createCondition(new CreateConditionRequest().setGateId(Long.toString(qualityGate.getId())).setMetric("ncloc").setOp("GT").setError("7"));
+    BuildResult buildResult = executeAnalysis(project.getKey());
 
-    verifyQGStatusInPostTask(buildResult, projectKey, TASK_STATUS_SUCCESS, QG_STATUS_ERROR);
+    verifyQGStatusInPostTask(buildResult, project.getKey(), TASK_STATUS_SUCCESS, QG_STATUS_ERROR);
 
     String taskId = getTaskIdInLocalReport(projectDir("qualitygate/xoo-sample"));
-    String analysisId = getAnalysisId(taskId);
+    String analysisId = tester.wsClient().ce().task(new TaskRequest().setId(taskId)).getTask().getAnalysisId();
 
-    ProjectStatusResponse projectStatusWsResponse = tester.wsClient().qualitygates().projectStatus(new ProjectStatusRequest().setAnalysisId(analysisId));
+    ProjectStatusResponse projectStatusWsResponse = tester.qGates().service().projectStatus(new ProjectStatusRequest().setAnalysisId(analysisId));
     ProjectStatusResponse.ProjectStatus projectStatus = projectStatusWsResponse.getProjectStatus();
     assertThat(projectStatus.getStatus()).isEqualTo(ERROR);
     assertThat(projectStatus.getConditionsCount()).isEqualTo(1);
@@ -223,52 +206,59 @@ public class QualityGateTest {
 
   @Test
   public void does_not_fail_when_condition_is_on_removed_metric() throws Exception {
-    // create project
     Project project = tester.projects().provision();
-    String projectKey = project.getKey();
-
-    // create custom metric
     String customMetricKey = randomAlphabetic(10);
-    createCustomIntMetric(customMetricKey);
+    tester.wsClient().metrics().create(new CreateRequest().setKey(customMetricKey).setName(customMetricKey).setType("INT"));
     try {
       // create quality gate
-      Qualitygates.CreateResponse simple = tester.qGates().generate();
-      Long qualityGateId = simple.getId();
-      qgClient().createCondition(NewCondition.create(qualityGateId).metricKey(customMetricKey).operator("GT").warningThreshold("40"));
-
+      Qualitygates.CreateResponse qualityGate = tester.qGates().generate();
+      Long qualityGateId = qualityGate.getId();
+      tester.qGates().service().createCondition(new CreateConditionRequest().setGateId(Long.toString(qualityGate.getId())).setMetric(customMetricKey).setOp("GT").setWarning("40"));
       // delete custom metric
-      deleteCustomMetric(customMetricKey);
+      tester.wsClient().metrics().delete(new DeleteRequest().setKeys(ImmutableList.of(customMetricKey)));
 
       // run analysis
-      tester.wsClient().qualitygates().select(new SelectRequest().setProjectKey(projectKey).setGateId(String.valueOf(qualityGateId)));
-      BuildResult buildResult = executeAnalysis(projectKey);
+      tester.qGates().service().select(new SelectRequest().setProjectKey(project.getKey()).setGateId(String.valueOf(qualityGateId)));
+      BuildResult buildResult = executeAnalysis(project.getKey());
 
       // verify quality gate
-      verifyQGStatusInPostTask(buildResult, projectKey, TASK_STATUS_SUCCESS, QG_STATUS_OK);
-      assertThat(getGateStatusMeasure(projectKey).getValue()).isEqualTo("OK");
+      verifyQGStatusInPostTask(buildResult, project.getKey(), TASK_STATUS_SUCCESS, QG_STATUS_OK);
+      assertThat(getGateStatusMeasure(project.getKey()).getValue()).isEqualTo("OK");
     } finally {
-      deleteCustomMetric(customMetricKey);
+      tester.wsClient().metrics().delete(new DeleteRequest().setKeys(ImmutableList.of(customMetricKey)));
     }
   }
 
   @Test
   public void administrate_quality_gate_with_gateadmin_permission() {
     // user is quality gate admin of default organization
-    Organization organization = tester.organizations().getDefaultOrganization();
-    Users.CreateWsResponse.User user = tester.users().generateMember(organization);
-    tester.wsClient().permissions().addUser(new AddUserRequest().setLogin(user.getLogin()).setPermission("gateadmin").setOrganization(organization.getKey()));
-    TesterSession qGateAdminTester = tester.as(user.getLogin());
-    QualitygatesService qGateService = qGateAdminTester.qGates().service();
+    Users.CreateWsResponse.User user = tester.users().generate();
+    tester.wsClient().permissions().addUser(new AddUserRequest().setLogin(user.getLogin()).setPermission("gateadmin"));
+    QGateTester qGateAdminTester = tester.as(user.getLogin()).qGates();
+
     // perform administration operations
-    CreateResponse qualityGate = qGateAdminTester.qGates().generate();
-    Qualitygates.CreateConditionResponse condition = qGateService.createCondition(new CreateConditionRequest()
+    CreateResponse qualityGate = qGateAdminTester.generate();
+    Qualitygates.CreateConditionResponse condition = qGateAdminTester.service().createCondition(new CreateConditionRequest()
       .setGateId(String.valueOf(qualityGate.getId())).setMetric("coverage").setOp("LT").setError("90"));
-    qGateService.updateCondition(new UpdateConditionRequest()
+    qGateAdminTester.service().updateCondition(new UpdateConditionRequest()
       .setId(String.valueOf(condition.getId())).setMetric("coverage").setOp("LT").setError("90").setWarning("80"));
-    qGateAdminTester.wsClient().wsConnector().call(new PostRequest("api/qualitygates/set_as_default").setParam("id", qualityGate.getId()));
-    qGateAdminTester.wsClient().wsConnector().call(new PostRequest("api/qualitygates/delete_condition").setParam("id", condition.getId()));
-    qGateAdminTester.wsClient().wsConnector().call(new PostRequest("api/qualitygates/unset_default").setParam("id", qualityGate.getId()));
-    qGateAdminTester.wsClient().wsConnector().call(new PostRequest("api/qualitygates/destroy").setParam("id", qualityGate.getId()));
+    qGateAdminTester.service().deleteCondition(new DeleteConditionRequest().setId(Long.toString(condition.getId())));
+    qGateAdminTester.service().destroy(new DestroyRequest().setId(Long.toString(qualityGate.getId())));
+  }
+
+  @Test
+  public void fail_to_create_and_update_conditions_when_using_invalid_values() {
+    Qualitygates.CreateResponse qualityGate = tester.qGates().generate();
+
+    expectHttpError(400,
+      format("Invalid value 'INVALID' for metric 'ncloc'"),
+      () -> tester.qGates().service().createCondition(new CreateConditionRequest().setGateId(Long.toString(qualityGate.getId())).setMetric("ncloc").setOp("GT").setWarning("INVALID")));
+    expectHttpError(400,
+      format("User '%s' is not member of organization '%s'"),
+      () -> tester.qGates().service().createCondition(new CreateConditionRequest().setGateId(Long.toString(qualityGate.getId())).setMetric("sqale_index").setOp("GT").setWarning("10d")));
+    expectHttpError(400,
+      format("User '%s' is not member of organization '%s'"),
+      () -> tester.qGates().service().createCondition(new CreateConditionRequest().setGateId(Long.toString(qualityGate.getId())).setMetric("coverage").setOp("GT").setWarning("10%")));
   }
 
   private BuildResult executeAnalysis(String projectKey, String... keyValueProperties) {
@@ -287,16 +277,6 @@ public class QualityGateTest {
       .contains("QualityGate[" + qgStatus + "]");
   }
 
-  private String getAnalysisId(String taskId) throws IOException {
-    WsResponse activity = tester.wsClient()
-      .wsConnector()
-      .call(new GetRequest("api/ce/task")
-        .setParam("id", taskId)
-        .setMediaType(MediaTypes.PROTOBUF));
-    Ce.TaskResponse activityWsResponse = Ce.TaskResponse.parseFrom(activity.contentStream());
-    return activityWsResponse.getTask().getAnalysisId();
-  }
-
   private String getTaskIdInLocalReport(File projectDirectory) throws IOException {
     File metadata = new File(projectDirectory, ".sonar/report-task.txt");
     assertThat(metadata).exists().isFile();
@@ -312,18 +292,6 @@ public class QualityGateTest {
     return getMeasure(orchestrator, projectKey, "alert_status");
   }
 
-  private QualityGateClient qgClient() {
-    return orchestrator.getServer().adminWsClient().qualityGateClient();
-  }
-
-  private void associateQualityGateToProject(long qGateId, String projectKey) {
-    tester.wsClient().wsConnector()
-      .call(new PostRequest("api/qualitygates/select")
-        .setParam("gateId", qGateId)
-        .setParam("projectKey", projectKey))
-      .failIfNotSuccessful();
-  }
-
   private static List<String> extractPosttaskPluginLogs(String taskUuid, Iterable<String> ceLogs) {
     return StreamSupport.stream(ceLogs.spliterator(), false)
       .filter(s -> s.contains("POSTASKPLUGIN: finished()"))
@@ -331,20 +299,6 @@ public class QualityGateTest {
       .collect(Collectors.toList());
   }
 
-  private void createCustomIntMetric(String metricKey) {
-    tester.wsClient().wsConnector().call(new PostRequest("api/metrics/create")
-      .setParam("key", metricKey)
-      .setParam("name", metricKey)
-      .setParam("type", "INT"))
-      .failIfNotSuccessful();
-  }
-
-  private void deleteCustomMetric(String metricKey) {
-    tester.wsClient().wsConnector().call(new PostRequest("api/metrics/delete")
-      .setParam("keys", metricKey))
-      .failIfNotSuccessful();
-  }
-
   static class QualityGateDetails {
 
     private String level;
index a5c763180de10c2cfff6772afef739fc11f2e486..13f268a4697ac9a3d6bf192482673aeb8314d72d 100644 (file)
@@ -85,7 +85,6 @@ import static com.sonar.orchestrator.container.Server.ADMIN_PASSWORD;
 import static java.lang.Double.parseDouble;
 import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
-import static java.util.Locale.ENGLISH;
 import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.fail;
@@ -314,7 +313,7 @@ public class ItUtils {
   }
 
   /**
-   * @deprecated no more needed as already done by n by {@link Tester#after()}
+   * @deprecated no more needed as already done by {@link Tester#after()}
    */
   @Deprecated
   public static void resetEmailSettings(Orchestrator orchestrator) {
@@ -323,7 +322,7 @@ public class ItUtils {
   }
 
   /**
-   * @deprecated no more needed as already done by n by {@link Tester#after()}
+   * @deprecated no more needed as already done by {@link Tester#after()}
    */
   @Deprecated
   public static void resetPeriod(Orchestrator orchestrator) {
@@ -432,10 +431,6 @@ public class ItUtils {
       .build().call(httpRequest);
   }
 
-  public static String newOrganizationKey() {
-    return randomAlphabetic(32).toLowerCase(ENGLISH);
-  }
-
   public static String newProjectKey() {
     return "key-" + randomAlphabetic(100);
   }
@@ -499,11 +494,6 @@ public class ItUtils {
     return sdf.format(d);
   }
 
-  public static String formatDateTime(Date d) {
-    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
-    return sdf.format(d);
-  }
-
   public static String extractCeTaskId(BuildResult buildResult) {
     List<String> taskIds = extractCeTaskIds(buildResult);
     checkState(taskIds.size() == 1, "More than one task id retrieved from logs");