]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10087 Use protobuf in api/qualitygates/show
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 22 Nov 2017 12:17:02 +0000 (13:17 +0100)
committerEric Hartmann <hartmann.eric@gmail.Com>
Mon, 4 Dec 2017 12:44:55 +0000 (13:44 +0100)
Also take the opportunity to move business from QualityGates to ShowAction

13 files changed:
server/sonar-db-dao/src/test/java/org/sonar/db/qualitygate/QualityGateDbTester.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGateFinder.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QualityGates.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGatesWs.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java
server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/example-show.json [deleted file]
server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGateFinderTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/QualityGatesTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/DeselectActionTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java [new file with mode: 0644]
sonar-ws/src/main/protobuf/ws-qualitygates.proto

index 5b08337d2158acd101058ed4c72a2a5ed17bd36b..38b3ab546de9c40e461fee80cd685b55caca55c2 100644 (file)
@@ -19,6 +19,8 @@
  */
 package org.sonar.db.qualitygate;
 
+import java.util.Arrays;
+import java.util.function.Consumer;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
@@ -72,12 +74,14 @@ public class QualityGateDbTester {
     db.commit();
   }
 
-  public QualityGateConditionDto addCondition(QualityGateDto qualityGate, MetricDto metric) {
+  @SafeVarargs
+  public final QualityGateConditionDto addCondition(QualityGateDto qualityGate, MetricDto metric, Consumer<QualityGateConditionDto>... dtoPopulators) {
     QualityGateConditionDto condition = new QualityGateConditionDto().setQualityGateId(qualityGate.getId())
       .setMetricId(metric.getId())
       .setOperator("GT")
       .setWarningThreshold(randomNumeric(10))
       .setErrorThreshold(randomNumeric(10));
+    Arrays.stream(dtoPopulators).forEach(dtoPopulator -> dtoPopulator.accept(condition));
     dbClient.gateConditionDao().insert(condition, dbSession);
     db.commit();
     return condition;
index 348dd096bd5a6cd021ba26dce852f57a09bd044e..ace49296fe0974ccbe414d5ea01b02d281f81cfc 100644 (file)
@@ -21,14 +21,15 @@ package org.sonar.server.qualitygate;
 
 import java.util.Optional;
 import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.property.PropertyDto;
 import org.sonar.db.qualitygate.QualityGateDto;
-import org.sonar.server.exceptions.NotFoundException;
 
 import static org.apache.commons.lang.StringUtils.isBlank;
 import static org.sonar.server.qualitygate.QualityGates.SONAR_QUALITYGATE_PROPERTY;
+import static org.sonar.server.ws.WsUtils.checkFound;
 
 public class QualityGateFinder {
 
@@ -47,7 +48,7 @@ public class QualityGateFinder {
   public Optional<QualityGateData> getQualityGate(DbSession dbSession, long componentId) {
     Optional<Long> qualityGateId = dbClient.projectQgateAssociationDao().selectQGateIdByComponentId(dbSession, componentId);
     if (qualityGateId.isPresent()) {
-      return Optional.of(new QualityGateData(selectOrFailById(dbSession, qualityGateId.get()), false));
+      return Optional.of(new QualityGateData(getById(dbSession, qualityGateId.get()), false));
     } else {
       QualityGateDto defaultQualityGate = getDefault(dbSession);
       if (defaultQualityGate == null) {
@@ -57,21 +58,27 @@ public class QualityGateFinder {
     }
   }
 
+  public QualityGateDto getById(DbSession dbSession, long qualityGateId) {
+    return checkFound(dbClient.qualityGateDao().selectById(dbSession, qualityGateId), "No quality gate has been found for id %s", qualityGateId);
+  }
+
+  public QualityGateDto getByNameOrId(DbSession dbSession, @Nullable String name, @Nullable Long id) {
+    if (name != null) {
+      return checkFound(dbClient.qualityGateDao().selectByName(dbSession, name), "No quality gate has been found for name %s", name);
+    }
+    if (id != null) {
+      return getById(dbSession, id);
+    }
+    throw new IllegalArgumentException("No parameter has been set to identify a quality gate");
+  }
+
   @CheckForNull
   private QualityGateDto getDefault(DbSession dbSession) {
     Long defaultId = getDefaultId(dbSession);
     if (defaultId == null) {
       return null;
     }
-    return selectOrFailById(dbSession, defaultId);
-  }
-
-  private QualityGateDto selectOrFailById(DbSession dbSession, long qualityGateId) {
-    QualityGateDto qualityGateDto = dbClient.qualityGateDao().selectById(dbSession, qualityGateId);
-    if (qualityGateDto == null) {
-      throw new NotFoundException(String.format("No quality gate has been found for id %s", qualityGateId));
-    }
-    return qualityGateDto;
+    return getById(dbSession, defaultId);
   }
 
   @CheckForNull
@@ -101,4 +108,5 @@ public class QualityGateFinder {
       return isDefault;
     }
   }
+
 }
index add13b7b5c4e6bf41bad2bd08e66d09141df9b54..6a3e809cc112e969533b1d467faa92718da0dfd4 100644 (file)
@@ -26,8 +26,6 @@ import java.util.List;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.apache.commons.lang.StringUtils;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.measures.MetricFinder;
 import org.sonar.api.web.UserRole;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
@@ -47,11 +45,10 @@ import static java.lang.String.format;
 import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
 import static org.sonar.server.util.Validation.CANT_BE_EMPTY_MESSAGE;
 import static org.sonar.server.util.Validation.IS_ALREADY_USED_MESSAGE;
-import static org.sonar.server.ws.WsUtils.checkFound;
 import static org.sonar.server.ws.WsUtils.checkRequest;
 
 /**
- * Methods from this class should be moved to {@link QualityGateUpdater} and to new classes QualityGateFinder / QualityGateConditionsUpdater / etc.
+ * Methods from this class should be moved to {@link QualityGateUpdater} and to classes QualityGateFinder / QualityGateConditionsUpdater / etc.
  * in order to have classes with clearer responsibilities and more easily testable (without having to use too much mocks)
  */
 public class QualityGates {
@@ -61,29 +58,19 @@ public class QualityGates {
   private final DbClient dbClient;
   private final QualityGateDao dao;
   private final QualityGateConditionDao conditionDao;
-  private final MetricFinder metricFinder;
   private final PropertiesDao propertiesDao;
   private final UserSession userSession;
   private final DefaultOrganizationProvider organizationProvider;
 
-  public QualityGates(DbClient dbClient, MetricFinder metricFinder, UserSession userSession, DefaultOrganizationProvider organizationProvider) {
+  public QualityGates(DbClient dbClient, UserSession userSession, DefaultOrganizationProvider organizationProvider) {
     this.dbClient = dbClient;
     this.dao = dbClient.qualityGateDao();
     this.conditionDao = dbClient.gateConditionDao();
-    this.metricFinder = metricFinder;
     this.propertiesDao = dbClient.propertiesDao();
     this.userSession = userSession;
     this.organizationProvider = organizationProvider;
   }
 
-  public QualityGateDto get(Long qGateId) {
-    return getNonNullQgate(qGateId);
-  }
-
-  public QualityGateDto get(String qGateName) {
-    return getNonNullQgate(qGateName);
-  }
-
   public QualityGateDto rename(long idToRename, String name) {
     checkIsQualityGateAdministrator();
     try (DbSession dbSession = dbClient.openSession(false)) {
@@ -161,20 +148,6 @@ public class QualityGates {
     }
   }
 
-  public Collection<QualityGateConditionDto> listConditions(long qGateId) {
-    try (DbSession dbSession = dbClient.openSession(false)) {
-      Collection<QualityGateConditionDto> conditionsForGate = conditionDao.selectForQualityGate(dbSession, qGateId);
-      for (QualityGateConditionDto condition : conditionsForGate) {
-        Metric metric = metricFinder.findById((int) condition.getMetricId());
-        if (metric == null) {
-          throw new IllegalStateException("Could not find metric with id " + condition.getMetricId());
-        }
-        condition.setMetricKey(metric.getKey());
-      }
-      return conditionsForGate;
-    }
-  }
-
   public void dissociateProject(DbSession dbSession, ComponentDto project) {
     checkProjectAdmin(project);
     propertiesDao.deleteProjectProperty(SONAR_QUALITYGATE_PROPERTY, project.getId(), dbSession);
@@ -207,12 +180,6 @@ public class QualityGates {
     return qGate;
   }
 
-  private QualityGateDto getNonNullQgate(String name) {
-    try (DbSession dbSession = dbClient.openSession(false)) {
-      return checkFound(dao.selectByName(dbSession, name), "There is no quality gate with name=%s", name);
-    }
-  }
-
   private void validateQualityGate(DbSession dbSession, @Nullable Long updatingQgateId, @Nullable String name) {
     List<String> errors = new ArrayList<>();
     if (Strings.isNullOrEmpty(name)) {
index df2d83fa411719ec52fec287f241e41a050cf040..7ccb53b0af371fd138f33a51f81db2d54c9e84c7 100644 (file)
@@ -105,22 +105,4 @@ public class QualityGatesWs implements WebService {
       .endObject();
   }
 
-  static JsonWriter writeQualityGateCondition(QualityGateConditionDto condition, JsonWriter writer) {
-    writer.beginObject()
-      .prop(PARAM_ID, condition.getId())
-      .prop(PARAM_METRIC, condition.getMetricKey())
-      .prop(PARAM_OPERATOR, condition.getOperator());
-    if (condition.getWarningThreshold() != null) {
-      writer.prop(PARAM_WARNING, condition.getWarningThreshold());
-    }
-    if (condition.getErrorThreshold() != null) {
-      writer.prop(PARAM_ERROR, condition.getErrorThreshold());
-    }
-    if (condition.getPeriod() != null) {
-      writer.prop(PARAM_PERIOD, condition.getPeriod());
-    }
-    writer.endObject();
-    return writer;
-  }
-
 }
index 8bc6bde9463597dd3c05ab68faa196beb83278b3..d9d9d1efcc1e78826da85c562623662789ed3e85 100644 (file)
@@ -21,25 +21,39 @@ package org.sonar.server.qualitygate.ws;
 
 import com.google.common.io.Resources;
 import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
 import javax.annotation.Nullable;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
-import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.metric.MetricDto;
 import org.sonar.db.qualitygate.QualityGateConditionDto;
 import org.sonar.db.qualitygate.QualityGateDto;
-import org.sonar.server.qualitygate.QualityGates;
+import org.sonar.server.qualitygate.QualityGateFinder;
+import org.sonarqube.ws.Qualitygates.ShowWsResponse;
 
-import static org.sonar.server.ws.WsUtils.checkRequest;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static org.sonar.core.util.Protobuf.setNullable;
+import static org.sonar.core.util.stream.MoreCollectors.toList;
+import static org.sonar.core.util.stream.MoreCollectors.toSet;
+import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex;
 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ID;
 import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_NAME;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
 
 public class ShowAction implements QualityGatesWsAction {
 
-  private final QualityGates qualityGates;
+  private final DbClient dbClient;
+  private final QualityGateFinder qualityGateFinder;
 
-  public ShowAction(QualityGates qualityGates) {
-    this.qualityGates = qualityGates;
+  public ShowAction(DbClient dbClient, QualityGateFinder qualityGateFinder) {
+    this.dbClient = dbClient;
+    this.qualityGateFinder = qualityGateFinder;
   }
 
   @Override
@@ -47,7 +61,7 @@ public class ShowAction implements QualityGatesWsAction {
     WebService.NewAction action = controller.createAction("show")
       .setDescription("Display the details of a quality gate")
       .setSince("4.3")
-      .setResponseExample(Resources.getResource(this.getClass(), "example-show.json"))
+      .setResponseExample(Resources.getResource(this.getClass(), "show-example.json"))
       .setHandler(this);
 
     action.createParam(PARAM_ID)
@@ -61,30 +75,56 @@ public class ShowAction implements QualityGatesWsAction {
 
   @Override
   public void handle(Request request, Response response) {
-    Long qGateId = request.paramAsLong(PARAM_ID);
-    String qGateName = request.param(PARAM_NAME);
-    checkOneOfIdOrNamePresent(qGateId, qGateName);
+    Long id = request.paramAsLong(PARAM_ID);
+    String name = request.param(PARAM_NAME);
+    checkOneOfIdOrNamePresent(id, name);
 
-    QualityGateDto qGate = qGateId == null ? qualityGates.get(qGateName) : qualityGates.get(qGateId);
-    qGateId = qGate.getId();
-
-    try (JsonWriter writer = response.newJsonWriter()) {
-      writer.beginObject()
-        .prop(PARAM_ID, qGate.getId())
-        .prop(PARAM_NAME, qGate.getName());
-      Collection<QualityGateConditionDto> conditions = qualityGates.listConditions(qGateId);
-      if (!conditions.isEmpty()) {
-        writer.name("conditions").beginArray();
-        for (QualityGateConditionDto condition : conditions) {
-          QualityGatesWs.writeQualityGateCondition(condition, writer);
-        }
-        writer.endArray();
-      }
-      writer.endObject().close();
+    try (DbSession dbSession = dbClient.openSession(false)) {
+      QualityGateDto qualityGate = qualityGateFinder.getByNameOrId(dbSession, name, id);
+      Collection<QualityGateConditionDto> conditions = getConditions(dbSession, qualityGate);
+      Map<Integer, MetricDto> metricsById = getMetricsById(dbSession, conditions);
+      writeProtobuf(buildResponse(qualityGate, conditions, metricsById), request, response);
     }
   }
 
+  public Collection<QualityGateConditionDto> getConditions(DbSession dbSession, QualityGateDto qualityGate) {
+    return dbClient.gateConditionDao().selectForQualityGate(dbSession, qualityGate.getId());
+  }
+
+  private Map<Integer, MetricDto> getMetricsById(DbSession dbSession, Collection<QualityGateConditionDto> conditions) {
+    Set<Integer> metricIds = conditions.stream().map(c -> (int) c.getMetricId()).collect(toSet());
+    return dbClient.metricDao().selectByIds(dbSession, metricIds).stream()
+      .filter(MetricDto::isEnabled)
+      .collect(uniqueIndex(MetricDto::getId));
+  }
+
+  private static ShowWsResponse buildResponse(QualityGateDto qualityGate, Collection<QualityGateConditionDto> conditions, Map<Integer, MetricDto> metricsById) {
+    return ShowWsResponse.newBuilder()
+      .setId(qualityGate.getId())
+      .setName(qualityGate.getName())
+      .addAllConditions(conditions.stream()
+        .map(toWsCondition(metricsById))
+        .collect(toList()))
+      .build();
+  }
+
+  private static Function<QualityGateConditionDto, ShowWsResponse.Condition> toWsCondition(Map<Integer, MetricDto> metricsById) {
+    return condition -> {
+      int metricId = (int) condition.getMetricId();
+      MetricDto metric = metricsById.get(metricId);
+      checkState(metric != null, "Could not find metric with id %s", metricId);
+      ShowWsResponse.Condition.Builder builder = ShowWsResponse.Condition.newBuilder()
+        .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();
+    };
+  }
+
   private static void checkOneOfIdOrNamePresent(@Nullable Long qGateId, @Nullable String qGateName) {
-    checkRequest(qGateId == null ^ qGateName == null, "Either '%s' or '%s' must be provided", PARAM_ID, PARAM_NAME);
+    checkArgument(qGateId == null ^ qGateName == null, "Either '%s' or '%s' must be provided", PARAM_ID, PARAM_NAME);
   }
 }
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/example-show.json b/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/example-show.json
deleted file mode 100644 (file)
index 99132a0..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-  "id": 2,
-  "name": "My Quality Gate",
-  "conditions": [
-    {
-      "id": 9,
-      "metric": "blocker_violations",
-      "op": "GT",
-      "error": "0"
-    },
-    {
-      "id": 10,
-      "metric": "critical_violations",
-      "op": "GT",
-      "warning": "0"
-    }
-  ]
-}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json b/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/show-example.json
new file mode 100644 (file)
index 0000000..7bca100
--- /dev/null
@@ -0,0 +1,19 @@
+{
+  "id": 2,
+  "name": "My Quality Gate",
+  "conditions": [
+    {
+      "id": 9,
+      "metric": "blocker_violations",
+      "op": "GT",
+      "error": "0"
+    },
+    {
+      "id": 10,
+      "metric": "critical_violations",
+      "period": 1,
+      "op": "LT",
+      "warning": "0"
+    }
+  ]
+}
index b7754fac0621fb5c253f096d93abd71ef5b8ef8a..4b4026d5fe69d51bc2e79b1350cd87f94fc8d558 100644 (file)
@@ -27,7 +27,6 @@ import org.sonar.api.utils.System2;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentTesting;
 import org.sonar.db.qualitygate.QualityGateDto;
 import org.sonar.server.exceptions.NotFoundException;
 
@@ -39,16 +38,16 @@ public class QualityGateFinderTest {
   public ExpectedException expectedException = ExpectedException.none();
 
   @Rule
-  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+  public DbTester db = DbTester.create(System2.INSTANCE);
 
-  private DbSession dbSession = dbTester.getSession();
+  private DbSession dbSession = db.getSession();
 
-  private QualityGateFinder underTest = new QualityGateFinder(dbTester.getDbClient());
+  private QualityGateFinder underTest = new QualityGateFinder(db.getDbClient());
 
   @Test
   public void return_default_quality_gate_for_project() {
-    ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()));
-    QualityGateDto dbQualityGate = dbTester.qualityGates().createDefaultQualityGate("Sonar way");
+    ComponentDto project = db.components().insertPrivateProject();
+    QualityGateDto dbQualityGate = db.qualityGates().createDefaultQualityGate("Sonar way");
 
     Optional<QualityGateFinder.QualityGateData> result = underTest.getQualityGate(dbSession, project.getId());
 
@@ -59,10 +58,10 @@ public class QualityGateFinderTest {
 
   @Test
   public void return_project_quality_gate_over_default() {
-    ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert()));
-    dbTester.qualityGates().createDefaultQualityGate("Sonar way");
-    QualityGateDto dbQualityGate = dbTester.qualityGates().insertQualityGate("My team QG");
-    dbTester.qualityGates().associateProjectToQualityGate(project, dbQualityGate);
+    ComponentDto project = db.components().insertPrivateProject();
+    db.qualityGates().createDefaultQualityGate("Sonar way");
+    QualityGateDto dbQualityGate = db.qualityGates().insertQualityGate("My team QG");
+    db.qualityGates().associateProjectToQualityGate(project, dbQualityGate);
 
     Optional<QualityGateFinder.QualityGateData> result = underTest.getQualityGate(dbSession, project.getId());
 
@@ -73,7 +72,7 @@ public class QualityGateFinderTest {
 
   @Test
   public void return_nothing_when_no_default_qgate_and_no_qgate_defined_for_project() {
-    ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()));
+    ComponentDto project = db.components().insertPrivateProject();
 
     Optional<QualityGateFinder.QualityGateData> result = underTest.getQualityGate(dbSession, project.getId());
 
@@ -82,9 +81,9 @@ public class QualityGateFinderTest {
 
   @Test
   public void fail_when_default_qgate_defined_in_properties_does_not_exists() throws Exception {
-    ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert()));
-    QualityGateDto dbQualityGate = dbTester.qualityGates().createDefaultQualityGate("Sonar way");
-    dbTester.getDbClient().qualityGateDao().delete(dbQualityGate, dbSession);
+    ComponentDto project = db.components().insertPrivateProject();
+    QualityGateDto dbQualityGate = db.qualityGates().createDefaultQualityGate("Sonar way");
+    db.getDbClient().qualityGateDao().delete(dbQualityGate, dbSession);
 
     expectedException.expect(NotFoundException.class);
     underTest.getQualityGate(dbSession, project.getId());
@@ -92,12 +91,44 @@ public class QualityGateFinderTest {
 
   @Test
   public void fail_when_project_qgate_defined_in_properties_does_not_exists() throws Exception {
-    ComponentDto project = dbTester.components().insertComponent(ComponentTesting.newPrivateProjectDto(dbTester.getDefaultOrganization()));
-    QualityGateDto dbQualityGate = dbTester.qualityGates().insertQualityGate("My team QG");
-    dbTester.qualityGates().associateProjectToQualityGate(project, dbQualityGate);
-    dbTester.getDbClient().qualityGateDao().delete(dbQualityGate, dbSession);
+    ComponentDto project = db.components().insertPrivateProject();
+    QualityGateDto dbQualityGate = db.qualityGates().insertQualityGate("My team QG");
+    db.qualityGates().associateProjectToQualityGate(project, dbQualityGate);
+    db.getDbClient().qualityGateDao().delete(dbQualityGate, dbSession);
 
     expectedException.expect(NotFoundException.class);
     underTest.getQualityGate(dbSession, project.getId());
   }
+
+  @Test
+  public void get_by_name_or_id() {
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
+
+    assertThat(underTest.getByNameOrId(db.getSession(), qualityGate.getName(), null)).isNotNull();
+    assertThat(underTest.getByNameOrId(db.getSession(), null, qualityGate.getId())).isNotNull();
+  }
+
+  @Test
+  public void fail_get_by_name_or_id_when_name_matches_nothing() {
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("No quality gate has been found for name UNKNOWN");
+
+    underTest.getByNameOrId(db.getSession(), "UNKNOWN", null);
+  }
+
+  @Test
+  public void fail_get_by_name_or_id_when_id_matches_nothing() {
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("No quality gate has been found for id 123");
+
+    underTest.getByNameOrId(db.getSession(), null, 123L);
+  }
+
+  @Test
+  public void fail_get_by_name_or_id_when_parameters_are_null() {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("No parameter has been set to identify a quality gate");
+
+    underTest.getByNameOrId(db.getSession(), null, null);
+  }
 }
index f8e9168dfe5ef0f4e68830a3abc17ad8ec22f89a..a2946607e9a133619eba4e02ba177470d95b79f2 100644 (file)
@@ -22,7 +22,6 @@ package org.sonar.server.qualitygate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Lists;
 import java.util.Collection;
-import java.util.Iterator;
 import java.util.List;
 import org.junit.Before;
 import org.junit.Rule;
@@ -30,10 +29,6 @@ import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.measures.Metric;
-import org.sonar.api.measures.Metric.ValueType;
-import org.sonar.api.measures.MetricFinder;
 import org.sonar.core.util.Uuids;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
@@ -80,7 +75,6 @@ public class QualityGatesTest {
   private QualityGateConditionDao conditionDao = mock(QualityGateConditionDao.class);
   private PropertiesDao propertiesDao = mock(PropertiesDao.class);
   private ComponentDao componentDao = mock(ComponentDao.class);
-  private MetricFinder metricFinder = mock(MetricFinder.class);
   private QualityGates underTest;
 
   @Before
@@ -94,7 +88,7 @@ public class QualityGatesTest {
     when(componentDao.selectOrFailById(eq(dbSession), anyLong())).thenReturn(
       newPrivateProjectDto(OrganizationTesting.newOrganizationDto(), PROJECT_UUID).setId(1L).setDbKey(PROJECT_KEY));
 
-    underTest = new QualityGates(dbClient, metricFinder, userSession, organizationProvider);
+    underTest = new QualityGates(dbClient, userSession, organizationProvider);
 
     userSession.logIn().addPermission(OrganizationPermission.ADMINISTER_QUALITY_GATES, organizationProvider.get().getUuid());
   }
@@ -106,31 +100,6 @@ public class QualityGatesTest {
     assertThat(underTest.list()).isEqualTo(allQgates);
   }
 
-  @Test
-  public void should_get_qgate_by_id() {
-    long id = QUALITY_GATE_ID;
-    final String name = "Golden";
-    QualityGateDto existing = new QualityGateDto().setId(id).setName(name);
-    when(dao.selectById(dbSession, id)).thenReturn(existing);
-    assertThat(underTest.get(id)).isEqualTo(existing);
-    verify(dao).selectById(dbSession, id);
-  }
-
-  @Test
-  public void should_get_qgate_by_name() {
-    long id = QUALITY_GATE_ID;
-    final String name = "Golden";
-    QualityGateDto existing = new QualityGateDto().setId(id).setName(name);
-    when(dao.selectByName(dbSession, name)).thenReturn(existing);
-    assertThat(underTest.get(name)).isEqualTo(existing);
-    verify(dao).selectByName(dbSession, name);
-  }
-
-  @Test(expected = NotFoundException.class)
-  public void should_fail_to_find_qgate_by_name() {
-    underTest.get("Does not exist");
-  }
-
   @Test
   public void should_rename_qgate() {
     long id = QUALITY_GATE_ID;
@@ -246,45 +215,6 @@ public class QualityGatesTest {
     assertThat(underTest.getDefault()).isNull();
   }
 
-  @Test
-  public void should_list_conditions() {
-    long qGateId = QUALITY_GATE_ID;
-    long metric1Id = 1L;
-    String metric1Key = "polop";
-    long metric2Id = 2L;
-    String metric2Key = "palap";
-    QualityGateConditionDto cond1 = new QualityGateConditionDto().setMetricId(metric1Id);
-    QualityGateConditionDto cond2 = new QualityGateConditionDto().setMetricId(metric2Id);
-    Collection<QualityGateConditionDto> conditions = ImmutableList.of(cond1, cond2);
-    when(conditionDao.selectForQualityGate(dbSession, qGateId)).thenReturn(conditions);
-    Metric metric1 = mock(Metric.class);
-    when(metric1.getKey()).thenReturn(metric1Key);
-    when(metricFinder.findById((int) metric1Id)).thenReturn(metric1);
-    Metric metric2 = mock(Metric.class);
-    when(metric2.getKey()).thenReturn(metric2Key);
-    when(metricFinder.findById((int) metric2Id)).thenReturn(metric2);
-    assertThat(underTest.listConditions(qGateId)).isEqualTo(conditions);
-    Iterator<QualityGateConditionDto> iterator = conditions.iterator();
-    assertThat(iterator.next().getMetricKey()).isEqualTo(metric1Key);
-    assertThat(iterator.next().getMetricKey()).isEqualTo(metric2Key);
-  }
-
-  @Test(expected = IllegalStateException.class)
-  public void should_do_a_sanity_check_when_listing_conditions() {
-    long qGateId = QUALITY_GATE_ID;
-    long metric1Id = 1L;
-    String metric1Key = "polop";
-    long metric2Id = 2L;
-    QualityGateConditionDto cond1 = new QualityGateConditionDto().setMetricId(metric1Id);
-    QualityGateConditionDto cond2 = new QualityGateConditionDto().setMetricId(metric2Id);
-    Collection<QualityGateConditionDto> conditions = ImmutableList.of(cond1, cond2);
-    when(conditionDao.selectForQualityGate(dbSession, qGateId)).thenReturn(conditions);
-    Metric metric1 = mock(Metric.class);
-    when(metric1.getKey()).thenReturn(metric1Key);
-    when(metricFinder.findById((int) metric1Id)).thenReturn(metric1);
-    underTest.listConditions(qGateId);
-  }
-
   @Test
   public void should_copy_qgate() {
     String name = "Atlantis";
@@ -310,21 +240,4 @@ public class QualityGatesTest {
     verify(conditionDao, times(conditions.size())).insert(any(QualityGateConditionDto.class), eq(dbSession));
   }
 
-  @Test
-  public void should_list_gate_metrics() {
-    Metric dataMetric = mock(Metric.class);
-    when(dataMetric.isDataType()).thenReturn(true);
-    Metric hiddenMetric = mock(Metric.class);
-    when(hiddenMetric.isHidden()).thenReturn(true);
-    Metric nullHiddenMetric = mock(Metric.class);
-    when(nullHiddenMetric.isHidden()).thenReturn(null);
-    Metric alertMetric = CoreMetrics.ALERT_STATUS;
-    Metric ratingMetric = mock(Metric.class);
-    when(ratingMetric.getType()).thenReturn(ValueType.RATING);
-    Metric classicMetric = mock(Metric.class);
-    when(classicMetric.getType()).thenReturn(ValueType.BOOL);
-    when(metricFinder.findAll()).thenReturn(ImmutableList.of(
-      dataMetric, hiddenMetric, nullHiddenMetric, alertMetric, ratingMetric, classicMetric));
-  }
-
 }
index fa9639d1afe6a40975ad705e81e51ca10e080422..5904f1aff495c117a1e58410acdd40a12e8c4ec4 100644 (file)
@@ -23,7 +23,6 @@ import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.sonar.api.measures.MetricFinder;
 import org.sonar.api.server.ws.Change;
 import org.sonar.api.server.ws.WebService;
 import org.sonar.api.utils.System2;
@@ -47,7 +46,6 @@ import org.sonar.server.ws.WsActionTester;
 import static java.lang.String.format;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.tuple;
-import static org.mockito.Mockito.mock;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_PROFILES;
 import static org.sonar.server.qualitygate.QualityGates.SONAR_QUALITYGATE_PROPERTY;
 
@@ -63,7 +61,7 @@ public class DeselectActionTest {
   private DbClient dbClient = db.getDbClient();
   private DbSession dbSession = db.getSession();
   private TestDefaultOrganizationProvider organizationProvider = TestDefaultOrganizationProvider.from(db);
-  private QualityGates qualityGates = new QualityGates(dbClient, mock(MetricFinder.class), userSession, organizationProvider);
+  private QualityGates qualityGates = new QualityGates(dbClient, userSession, organizationProvider);
   private WsActionTester ws;
   private ComponentDto project;
   private QualityGateDto gate;
@@ -87,8 +85,7 @@ public class DeselectActionTest {
     assertThat(def.isPost()).isTrue();
     assertThat(def.since()).isEqualTo("4.3");
     assertThat(def.changelog()).extracting(Change::getVersion, Change::getDescription).containsExactly(
-      tuple("6.6", "The parameter 'gateId' was removed")
-    );
+      tuple("6.6", "The parameter 'gateId' was removed"));
 
     assertThat(def.params()).extracting(WebService.Param::key)
       .containsExactlyInAnyOrder("projectId", "projectKey");
index 0996909c23372a7329151cade4b0dabf8e590196..9b2de4b6e55e0314b5cb04ccd5fa2b4fa0e33f03 100644 (file)
@@ -33,7 +33,6 @@ import org.sonar.api.server.ws.WebService.Controller;
 import org.sonar.db.DbClient;
 import org.sonar.db.qualitygate.ProjectQgateAssociation;
 import org.sonar.db.qualitygate.ProjectQgateAssociationQuery;
-import org.sonar.db.qualitygate.QualityGateConditionDto;
 import org.sonar.db.qualitygate.QualityGateDto;
 import org.sonar.server.component.ComponentFinder;
 import org.sonar.server.exceptions.BadRequestException;
@@ -70,7 +69,6 @@ public class QualityGatesWsTest {
 
     tester = new WsTester(new QualityGatesWs(
       new ListAction(qGates),
-      new ShowAction(qGates),
       new SearchAction(projectFinder),
       new CreateAction(null, null, null, null),
       new CopyAction(qGates),
@@ -90,7 +88,7 @@ public class QualityGatesWsTest {
     assertThat(controller).isNotNull();
     assertThat(controller.path()).isEqualTo("api/qualitygates");
     assertThat(controller.description()).isNotEmpty();
-    assertThat(controller.actions()).hasSize(15);
+    assertThat(controller.actions()).hasSize(14);
 
     Action list = controller.action("list");
     assertThat(list).isNotNull();
@@ -99,14 +97,6 @@ public class QualityGatesWsTest {
     assertThat(list.isPost()).isFalse();
     assertThat(list.isInternal()).isFalse();
 
-    Action show = controller.action("show");
-    assertThat(show).isNotNull();
-    assertThat(show.handler()).isNotNull();
-    assertThat(show.since()).isEqualTo("4.3");
-    assertThat(show.isPost()).isFalse();
-    assertThat(show.param("id")).isNotNull();
-    assertThat(show.isInternal()).isFalse();
-
     Action create = controller.action("create");
     assertThat(create).isNotNull();
     assertThat(create.handler()).isNotNull();
@@ -258,53 +248,6 @@ public class QualityGatesWsTest {
       "{\"qualitygates\":[{\"id\":42,\"name\":\"Golden\"},{\"id\":43,\"name\":\"Star\"},{\"id\":666,\"name\":\"Ninth\"}],\"default\":42}");
   }
 
-  @Test
-  public void show_empty() throws Exception {
-    long gateId = 12345L;
-    when(qGates.get(gateId)).thenReturn(new QualityGateDto().setId(gateId).setName("Golden"));
-    tester.newGetRequest("api/qualitygates", "show").setParam("id", Long.toString(gateId)).execute().assertJson(
-      "{\"id\":12345,\"name\":\"Golden\"}");
-  }
-
-  @Test
-  public void show_by_id_nominal() throws Exception {
-    long gateId = 12345L;
-    when(qGates.get(gateId)).thenReturn(new QualityGateDto().setId(gateId).setName("Golden"));
-    when(qGates.listConditions(gateId)).thenReturn(ImmutableList.of(
-      new QualityGateConditionDto().setId(1L).setMetricKey("ncloc").setOperator("GT").setErrorThreshold("10000"),
-      new QualityGateConditionDto().setId(2L).setMetricKey("new_coverage").setOperator("LT").setWarningThreshold("90").setPeriod(3)));
-    tester.newGetRequest("api/qualitygates", "show").setParam("id", Long.toString(gateId)).execute().assertJson(
-      "{\"id\":12345,\"name\":\"Golden\",\"conditions\":["
-        + "{\"id\":1,\"metric\":\"ncloc\",\"op\":\"GT\",\"error\":\"10000\"},"
-        + "{\"id\":2,\"metric\":\"new_coverage\",\"op\":\"LT\",\"warning\":\"90\",\"period\":3}"
-        + "]}");
-  }
-
-  @Test
-  public void show_by_name_nominal() throws Exception {
-    long qGateId = 12345L;
-    String gateName = "Golden";
-    when(qGates.get(gateName)).thenReturn(new QualityGateDto().setId(qGateId).setName(gateName));
-    when(qGates.listConditions(qGateId)).thenReturn(ImmutableList.of(
-      new QualityGateConditionDto().setId(1L).setMetricKey("ncloc").setOperator("GT").setErrorThreshold("10000"),
-      new QualityGateConditionDto().setId(2L).setMetricKey("new_coverage").setOperator("LT").setWarningThreshold("90").setPeriod(3)));
-    tester.newGetRequest("api/qualitygates", "show").setParam("name", gateName).execute().assertJson(
-      "{\"id\":12345,\"name\":\"Golden\",\"conditions\":["
-        + "{\"id\":1,\"metric\":\"ncloc\",\"op\":\"GT\",\"error\":\"10000\"},"
-        + "{\"id\":2,\"metric\":\"new_coverage\",\"op\":\"LT\",\"warning\":\"90\",\"period\":3}"
-        + "]}");
-  }
-
-  @Test(expected = BadRequestException.class)
-  public void show_without_parameters() throws Exception {
-    tester.newGetRequest("api/qualitygates", "show").execute();
-  }
-
-  @Test(expected = BadRequestException.class)
-  public void show_with_both_parameters() throws Exception {
-    tester.newGetRequest("api/qualitygates", "show").setParam("id", "12345").setParam("name", "Polop").execute();
-  }
-
   @Test
   public void search_with_query() throws Exception {
     long gateId = 12345L;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ShowActionTest.java
new file mode 100644 (file)
index 0000000..3be7de2
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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.ws;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.db.metric.MetricDto;
+import org.sonar.db.qualitygate.QualityGateConditionDto;
+import org.sonar.db.qualitygate.QualityGateDto;
+import org.sonar.server.qualitygate.QualityGateFinder;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.Qualitygates.ShowWsResponse;
+import org.sonarqube.ws.Qualitygates.ShowWsResponse.Condition;
+
+import static java.lang.String.format;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.AssertionsForClassTypes.tuple;
+import static org.sonar.test.JsonAssert.assertJson;
+
+public class ShowActionTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+  @Rule
+  public DbTester db = DbTester.create(System2.INSTANCE);
+
+  private WsActionTester ws = new WsActionTester(new ShowAction(db.getDbClient(), new QualityGateFinder(db.getDbClient())));
+
+  @Test
+  public void verify_definition() {
+    WebService.Action action = ws.getDef();
+    assertThat(action.since()).isEqualTo("4.3");
+    assertThat(action.changelog()).isEmpty();
+    assertThat(action.params())
+      .extracting(Param::key, Param::isRequired)
+      .containsExactlyInAnyOrder(tuple("id", false), tuple("name", false));
+  }
+
+  @Test
+  public void json_example() {
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate("My Quality Gate");
+    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"));
+
+    String response = ws.newRequest()
+      .setParam("name", qualityGate.getName())
+      .execute()
+      .getInput();
+
+    assertJson(response).ignoreFields("id")
+      .isSimilarTo(getClass().getResource("show-example.json"));
+  }
+
+  @Test
+  public void show() {
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
+    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));
+
+    ShowWsResponse response = ws.newRequest().setParam("name", qualityGate.getName())
+      .executeProtobuf(ShowWsResponse.class);
+
+    assertThat(response.getId()).isEqualTo(qualityGate.getId());
+    assertThat(response.getName()).isEqualTo(qualityGate.getName());
+    assertThat(response.getConditionsList()).hasSize(2);
+    assertThat(response.getConditionsList())
+      .extracting(Condition::getId, Condition::getMetric, Condition::hasPeriod, Condition::getPeriod, 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()));
+  }
+
+  @Test
+  public void show_by_id() {
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
+
+    ShowWsResponse response = ws.newRequest().setParam("id", qualityGate.getId().toString())
+      .executeProtobuf(ShowWsResponse.class);
+
+    assertThat(response.getId()).isEqualTo(qualityGate.getId());
+    assertThat(response.getName()).isEqualTo(qualityGate.getName());
+  }
+
+  @Test
+  public void no_condition() {
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
+
+    ShowWsResponse response = ws.newRequest().setParam("name", qualityGate.getName())
+      .executeProtobuf(ShowWsResponse.class);
+
+    assertThat(response.getId()).isEqualTo(qualityGate.getId());
+    assertThat(response.getName()).isEqualTo(qualityGate.getName());
+    assertThat(response.getConditionsList()).isEmpty();
+  }
+
+  @Test
+  public void fail_when_no_name_or_id() {
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Either 'id' or 'name' must be provided");
+
+    ws.newRequest().execute();
+  }
+
+  @Test
+  public void fail_when_both_name_or_id() {
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
+
+    expectedException.expect(IllegalArgumentException.class);
+    expectedException.expectMessage("Either 'id' or 'name' must be provided");
+
+    ws.newRequest()
+      .setParam("name", qualityGate.getName())
+      .setParam("id", qualityGate.getId().toString())
+      .execute();
+  }
+
+  @Test
+  public void fail_when_condition_is_on_disabled_metric() {
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate();
+    MetricDto metric = db.measures().insertMetric();
+    db.qualityGates().addCondition(qualityGate, metric);
+    db.getDbClient().metricDao().disableCustomByKey(db.getSession(), metric.getKey());
+    db.commit();
+
+    expectedException.expect(IllegalStateException.class);
+    expectedException.expectMessage(format("Could not find metric with id %s", metric.getId()));
+
+    ws.newRequest()
+      .setParam("name", qualityGate.getName())
+      .execute();
+  }
+}
index 7a40a0bf2ce1a838efdeba905a62157b5365060d..ef51ba14a3964e2ebcd2ced07b3c8bd84b85ae14 100644 (file)
@@ -118,5 +118,21 @@ message UpdateConditionResponse {
   optional int32 period = 6;
 }
 
+// GET api/qualitygates/show
+message ShowWsResponse {
+  optional int64 id = 1;
+  optional string name = 2;
+  repeated Condition conditions = 3;
+
+  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;
+  }
+}
+