]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7152 WS api/qualitygates/project_status search by project id or key
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Fri, 29 Jan 2016 18:13:49 +0000 (19:13 +0100)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Tue, 2 Feb 2016 16:52:34 +0000 (17:52 +0100)
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ProjectStatusAction.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatter.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/ProjectStatusActionTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGateDetailsFormatterTest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/ProjectStatusWsRequest.java
sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesService.java
sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesWsParameters.java [new file with mode: 0644]

index 2ad6a9c451b72ba96edb973e8c09df30e6c4255c..416fb42496bf8ceadab26be16a2744ea2698df92 100644 (file)
@@ -21,30 +21,42 @@ package org.sonar.server.qualitygate.ws;
 
 import com.google.common.base.Function;
 import com.google.common.base.Joiner;
+import com.google.common.base.Optional;
 import com.google.common.collect.Lists;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.server.ws.Request;
 import org.sonar.api.server.ws.Response;
 import org.sonar.api.server.ws.WebService;
+import org.sonar.core.util.Uuids;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.SnapshotDto;
 import org.sonar.db.measure.MeasureDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.component.ComponentFinder.ParamNames;
+import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.user.UserSession;
+import org.sonar.server.ws.KeyExamples;
 import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse;
 import org.sonarqube.ws.client.qualitygate.ProjectStatusWsRequest;
 
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Strings.isNullOrEmpty;
 import static org.sonar.core.permission.GlobalPermissions.SCAN_EXECUTION;
 import static org.sonar.core.permission.GlobalPermissions.SYSTEM_ADMIN;
 import static org.sonar.server.user.AbstractUserSession.insufficientPrivilegesException;
 import static org.sonar.server.ws.WsUtils.checkFound;
+import static org.sonar.server.ws.WsUtils.checkRequest;
 import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ANALYSIS_ID;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_ID;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_KEY;
 
 public class ProjectStatusAction implements QGateWsAction {
   private static final String QG_STATUSES_ONE_LINE = Joiner.on(", ")
@@ -55,30 +67,44 @@ public class ProjectStatusAction implements QGateWsAction {
         return input.toString();
       }
     }));
+  private static final String MSG_ONE_PARAMETER_ONLY = String.format("One (and only one) of the following parameters must be provided '%s', '%s', '%s'",
+    PARAM_ANALYSIS_ID, PARAM_PROJECT_ID, PARAM_PROJECT_KEY);
 
   private final DbClient dbClient;
+  private final ComponentFinder componentFinder;
   private final UserSession userSession;
 
-  public ProjectStatusAction(DbClient dbClient, UserSession userSession) {
+  public ProjectStatusAction(DbClient dbClient, ComponentFinder componentFinder, UserSession userSession) {
     this.dbClient = dbClient;
+    this.componentFinder = componentFinder;
     this.userSession = userSession;
   }
 
   @Override
   public void define(WebService.NewController controller) {
     WebService.NewAction action = controller.createAction("project_status")
-      .setDescription(String.format("Quality gate status for a given Compute Engine task. <br />" +
-        "The different statuses returned are: %s. The %s status is returned when there is no Quality Gate associated with the analysis.<br />" +
-        "Returns a http code 404 if the analysis associated with the task is not found or does not exist.<br />" +
+      .setDescription(String.format("Get the quality gate status of a project or a Compute Engine task.<br />" +
+        MSG_ONE_PARAMETER_ONLY + "<br />" +
+        "The different statuses returned are: %s. The %s status is returned when there is no quality gate associated with the analysis.<br />" +
+        "Returns an HTTP code 404 if the analysis associated with the task is not found or does not exist.<br />" +
         "Requires 'Administer System' or 'Execute Analysis' permission.", QG_STATUSES_ONE_LINE, ProjectStatusWsResponse.Status.NONE))
       .setResponseExample(getClass().getResource("project_status-example.json"))
       .setSince("5.3")
       .setHandler(this);
 
-    action.createParam("analysisId")
+    action.createParam(PARAM_ANALYSIS_ID)
       .setDescription("Analysis id")
-      .setRequired(true)
       .setExampleValue("2963");
+
+    action.createParam(PARAM_PROJECT_ID)
+      .setSince("5.4")
+      .setDescription("Project id")
+      .setExampleValue(Uuids.UUID_EXAMPLE_01);
+
+    action.createParam(PARAM_PROJECT_KEY)
+      .setSince("5.4")
+      .setDescription("Project key")
+      .setExampleValue(KeyExamples.KEY_PROJECT_EXAMPLE_001);
   }
 
   @Override
@@ -90,20 +116,42 @@ public class ProjectStatusAction implements QGateWsAction {
   private ProjectStatusWsResponse doHandle(ProjectStatusWsRequest request) {
     DbSession dbSession = dbClient.openSession(false);
     try {
-      String snapshotId = request.getAnalysisId();
-      SnapshotDto snapshotDto = getSnapshot(dbSession, snapshotId);
-      ComponentDto projectDto = dbClient.componentDao().selectOrFailById(dbSession, snapshotDto.getComponentId());
-      checkPermission(projectDto.uuid());
-      String measureData = getQualityGateDetailsMeasureData(dbSession, snapshotDto);
+      ProjectAndSnapshot projectAndSnapshot = getProjectAndSnapshot(dbSession, request);
+      checkPermission(projectAndSnapshot.project.uuid());
+      Optional<String> measureData = getQualityGateDetailsMeasureData(dbSession, projectAndSnapshot.snapshotDto);
 
       return ProjectStatusWsResponse.newBuilder()
-        .setProjectStatus(new QualityGateDetailsFormatter(measureData, snapshotDto).format())
+        .setProjectStatus(new QualityGateDetailsFormatter(measureData, projectAndSnapshot.snapshotDto).format())
         .build();
     } finally {
       dbClient.closeSession(dbSession);
     }
   }
 
+  private ProjectAndSnapshot getProjectAndSnapshot(DbSession dbSession, ProjectStatusWsRequest request) {
+    String snapshotId = request.getAnalysisId();
+    if (!isNullOrEmpty(request.getAnalysisId())) {
+      return getSnapshotThenProject(dbSession, snapshotId);
+    } else if (!isNullOrEmpty(request.getProjectId()) ^ !isNullOrEmpty(request.getProjectKey())) {
+      return getProjectThenSnapshot(dbSession, request);
+    }
+
+    throw new BadRequestException(MSG_ONE_PARAMETER_ONLY);
+  }
+
+  private ProjectAndSnapshot getProjectThenSnapshot(DbSession dbSession, ProjectStatusWsRequest request) {
+    ComponentDto projectDto = componentFinder.getByUuidOrKey(dbSession, request.getProjectId(), request.getProjectKey(), ParamNames.PROJECT_ID_AND_KEY);
+    SnapshotDto snapshotDto = dbClient.snapshotDao().selectLastSnapshotByComponentId(dbSession, projectDto.getId());
+    checkState(snapshotDto != null, "Last analysis of project '%s' not found", projectDto.getKey());
+    return new ProjectAndSnapshot(projectDto, snapshotDto);
+  }
+
+  private ProjectAndSnapshot getSnapshotThenProject(DbSession dbSession, String snapshotId) {
+    SnapshotDto snapshotDto = getSnapshot(dbSession, snapshotId);
+    ComponentDto projectDto = dbClient.componentDao().selectOrFailById(dbSession, snapshotDto.getComponentId());
+    return new ProjectAndSnapshot(projectDto, snapshotDto);
+  }
+
   private SnapshotDto getSnapshot(DbSession dbSession, String snapshotIdFromRequest) {
     Long snapshotId = null;
     try {
@@ -120,19 +168,30 @@ public class ProjectStatusAction implements QGateWsAction {
     return checkFound(snapshotDto, "Analysis with id '%s' is not found", snapshotIdFromRequest);
   }
 
-  @CheckForNull
-  private String getQualityGateDetailsMeasureData(DbSession dbSession, SnapshotDto snapshotDto) {
-    List<MeasureDto> measures = dbClient.measureDao().selectBySnapshotIdAndMetricKeys(snapshotDto.getId(),
+  private Optional<String> getQualityGateDetailsMeasureData(DbSession dbSession, Optional<SnapshotDto> snapshotDto) {
+    if (!snapshotDto.isPresent()) {
+      return Optional.absent();
+    }
+
+    List<MeasureDto> measures = dbClient.measureDao().selectBySnapshotIdAndMetricKeys(snapshotDto.get().getId(),
       Collections.singleton(CoreMetrics.QUALITY_GATE_DETAILS_KEY), dbSession);
 
     return measures.isEmpty()
-      ? null
-      : measures.get(0).getData();
+      ? Optional.<String>absent()
+      : Optional.fromNullable(measures.get(0).getData());
   }
 
   private static ProjectStatusWsRequest toProjectStatusWsRequest(Request request) {
-    return new ProjectStatusWsRequest()
-      .setAnalysisId(request.mandatoryParam("analysisId"));
+    ProjectStatusWsRequest projectStatusWsRequest = new ProjectStatusWsRequest()
+      .setAnalysisId(request.param(PARAM_ANALYSIS_ID))
+      .setProjectId(request.param(PARAM_PROJECT_ID))
+      .setProjectKey(request.param(PARAM_PROJECT_KEY));
+    checkRequest(
+      !isNullOrEmpty(projectStatusWsRequest.getAnalysisId())
+        ^ !isNullOrEmpty(projectStatusWsRequest.getProjectId())
+        ^ !isNullOrEmpty(projectStatusWsRequest.getProjectKey()),
+      MSG_ONE_PARAMETER_ONLY);
+    return projectStatusWsRequest;
   }
 
   private void checkPermission(String projectUuid) {
@@ -141,4 +200,14 @@ public class ProjectStatusAction implements QGateWsAction {
       throw insufficientPrivilegesException();
     }
   }
+
+  private static class ProjectAndSnapshot {
+    private final ComponentDto project;
+    private final Optional<SnapshotDto> snapshotDto;
+
+    private ProjectAndSnapshot(ComponentDto project, @Nullable SnapshotDto snapshotDto) {
+      this.project = project;
+      this.snapshotDto = Optional.fromNullable(snapshotDto);
+    }
+  }
 }
index 9ed8f3c1313139eb9ded8643bbbfd9424feb0704..21888dbb6fdad60903a5bc630eef4c30b2d726d0 100644 (file)
  */
 package org.sonar.server.qualitygate.ws;
 
+import com.google.common.base.Optional;
 import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
-import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 import org.sonar.db.component.SnapshotDto;
 import org.sonarqube.ws.WsQualityGates.ProjectStatusWsResponse;
@@ -32,24 +32,23 @@ import static com.google.common.base.Strings.isNullOrEmpty;
 import static org.sonar.api.utils.DateUtils.formatDateTime;
 
 public class QualityGateDetailsFormatter {
-  @CheckForNull
-  private final String measureData;
-  private final SnapshotDto snapshot;
+  private final Optional<String> optionalMeasureData;
+  private final Optional<SnapshotDto> optionalSnapshot;
   private final ProjectStatusWsResponse.ProjectStatus.Builder projectStatusBuilder;
 
-  public QualityGateDetailsFormatter(@Nullable String measureData, SnapshotDto snapshot) {
-    this.measureData = measureData;
-    this.snapshot = snapshot;
+  public QualityGateDetailsFormatter(Optional<String> measureData, Optional<SnapshotDto> snapshot) {
+    this.optionalMeasureData = measureData;
+    this.optionalSnapshot = snapshot;
     this.projectStatusBuilder = ProjectStatusWsResponse.ProjectStatus.newBuilder();
   }
 
   public ProjectStatusWsResponse.ProjectStatus format() {
-    if (isNullOrEmpty(measureData)) {
+    if (!optionalMeasureData.isPresent()) {
       return newResponseWithoutQualityGateDetails();
     }
 
     JsonParser parser = new JsonParser();
-    JsonObject json = parser.parse(measureData).getAsJsonObject();
+    JsonObject json = parser.parse(optionalMeasureData.get()).getAsJsonObject();
 
     ProjectStatusWsResponse.Status qualityGateStatus = measureLevelToQualityGateStatus(json.get("level").getAsString());
     projectStatusBuilder.setStatus(qualityGateStatus);
@@ -61,11 +60,16 @@ public class QualityGateDetailsFormatter {
   }
 
   private void formatPeriods() {
+    if (!optionalSnapshot.isPresent()) {
+      return;
+    }
+
     ProjectStatusWsResponse.Period.Builder periodBuilder = ProjectStatusWsResponse.Period.newBuilder();
     for (int i = 1; i <= 5; i++) {
       periodBuilder.clear();
       boolean doesPeriodExist = false;
 
+      SnapshotDto snapshot = this.optionalSnapshot.get();
       if (!isNullOrEmpty(snapshot.getPeriodMode(i))) {
         doesPeriodExist = true;
         periodBuilder.setIndex(i);
@@ -97,44 +101,66 @@ public class QualityGateDetailsFormatter {
   private void formatCondition(JsonObject jsonCondition) {
     ProjectStatusWsResponse.Condition.Builder conditionBuilder = ProjectStatusWsResponse.Condition.newBuilder();
 
-    JsonElement measureLevel = jsonCondition.get("level");
-    if (measureLevel != null && !isNullOrEmpty(measureLevel.getAsString())) {
-      conditionBuilder.setStatus(measureLevelToQualityGateStatus(measureLevel.getAsString()));
+    formatConditionLevel(conditionBuilder, jsonCondition);
+    formatConditionMetric(conditionBuilder, jsonCondition);
+    formatConditionOperation(conditionBuilder, jsonCondition);
+    formatConditionPeriod(conditionBuilder, jsonCondition);
+    formatConditionWarningThreshold(conditionBuilder, jsonCondition);
+    formatConditionErrorThreshold(conditionBuilder, jsonCondition);
+    formatConditionActual(conditionBuilder, jsonCondition);
+
+    projectStatusBuilder.addConditions(conditionBuilder);
+  }
+
+  private static void formatConditionActual(ProjectStatusWsResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
+    JsonElement actual = jsonCondition.get("actual");
+    if (actual != null && !isNullOrEmpty(actual.getAsString())) {
+      conditionBuilder.setActualValue(actual.getAsString());
     }
+  }
 
-    JsonElement metric = jsonCondition.get("metric");
-    if (metric != null && !isNullOrEmpty(metric.getAsString())) {
-      conditionBuilder.setMetricKey(metric.getAsString());
+  private static void formatConditionErrorThreshold(ProjectStatusWsResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
+    JsonElement error = jsonCondition.get("error");
+    if (error != null && !isNullOrEmpty(error.getAsString())) {
+      conditionBuilder.setErrorThreshold(error.getAsString());
     }
+  }
 
-    JsonElement op = jsonCondition.get("op");
-    if (op != null && !isNullOrEmpty(op.getAsString())) {
-      String stringOp = op.getAsString();
-      ProjectStatusWsResponse.Comparator comparator = measureOpToQualityGateComparator(stringOp);
-      conditionBuilder.setComparator(comparator);
+  private static void formatConditionWarningThreshold(ProjectStatusWsResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
+    JsonElement warning = jsonCondition.get("warning");
+    if (warning != null && !isNullOrEmpty(warning.getAsString())) {
+      conditionBuilder.setWarningThreshold(warning.getAsString());
     }
+  }
 
+  private static void formatConditionPeriod(ProjectStatusWsResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
     JsonElement periodIndex = jsonCondition.get("period");
     if (periodIndex != null && !isNullOrEmpty(periodIndex.getAsString())) {
       conditionBuilder.setPeriodIndex(periodIndex.getAsInt());
     }
+  }
 
-    JsonElement warning = jsonCondition.get("warning");
-    if (warning != null && !isNullOrEmpty(warning.getAsString())) {
-      conditionBuilder.setWarningThreshold(warning.getAsString());
+  private static void formatConditionOperation(ProjectStatusWsResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
+    JsonElement op = jsonCondition.get("op");
+    if (op != null && !isNullOrEmpty(op.getAsString())) {
+      String stringOp = op.getAsString();
+      ProjectStatusWsResponse.Comparator comparator = measureOpToQualityGateComparator(stringOp);
+      conditionBuilder.setComparator(comparator);
     }
+  }
 
-    JsonElement error = jsonCondition.get("error");
-    if (error != null && !isNullOrEmpty(error.getAsString())) {
-      conditionBuilder.setErrorThreshold(error.getAsString());
+  private static void formatConditionMetric(ProjectStatusWsResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
+    JsonElement metric = jsonCondition.get("metric");
+    if (metric != null && !isNullOrEmpty(metric.getAsString())) {
+      conditionBuilder.setMetricKey(metric.getAsString());
     }
+  }
 
-    JsonElement actual = jsonCondition.get("actual");
-    if (actual != null && !isNullOrEmpty(actual.getAsString())) {
-      conditionBuilder.setActualValue(actual.getAsString());
+  private static void formatConditionLevel(ProjectStatusWsResponse.Condition.Builder conditionBuilder, JsonObject jsonCondition) {
+    JsonElement measureLevel = jsonCondition.get("level");
+    if (measureLevel != null && !isNullOrEmpty(measureLevel.getAsString())) {
+      conditionBuilder.setStatus(measureLevelToQualityGateStatus(measureLevel.getAsString()));
     }
-
-    projectStatusBuilder.addConditions(conditionBuilder);
   }
 
   private static ProjectStatusWsResponse.Status measureLevelToQualityGateStatus(String measureLevel) {
index f50387016d0e9714bbfec714e76c2a7219377a52..093d1c6749ca7d72f9f3f3455948e6e24210a7ac 100644 (file)
@@ -34,8 +34,9 @@ import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDto;
 import org.sonar.db.component.SnapshotDto;
-import org.sonar.db.measure.MeasureDto;
 import org.sonar.db.metric.MetricDto;
+import org.sonar.server.component.ComponentFinder;
+import org.sonar.server.exceptions.BadRequestException;
 import org.sonar.server.exceptions.ForbiddenException;
 import org.sonar.server.exceptions.NotFoundException;
 import org.sonar.server.tester.UserSessionRule;
@@ -54,6 +55,9 @@ import static org.sonar.db.component.SnapshotTesting.newSnapshotForProject;
 import static org.sonar.db.measure.MeasureTesting.newMeasureDto;
 import static org.sonar.db.metric.MetricTesting.newMetricDto;
 import static org.sonar.test.JsonAssert.assertJson;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ANALYSIS_ID;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_ID;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_KEY;
 
 @Category(DbTests.class)
 public class ProjectStatusActionTest {
@@ -74,7 +78,7 @@ public class ProjectStatusActionTest {
     dbClient = db.getDbClient();
     dbSession = db.getSession();
 
-    ws = new WsActionTester(new ProjectStatusAction(dbClient, userSession));
+    ws = new WsActionTester(new ProjectStatusAction(dbClient, new ComponentFinder(dbClient), userSession));
   }
 
   @Test
@@ -108,61 +112,79 @@ public class ProjectStatusActionTest {
   }
 
   @Test
-  public void fail_if_no_snapshot_id_found() {
-    userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN);
-
-    expectedException.expect(NotFoundException.class);
-    expectedException.expectMessage("Analysis with id 'task-uuid' is not found");
-
-    newRequest(ANALYSIS_ID);
-  }
-
-  @Test
-  public void return_undefined_status_if_measure_is_not_found() {
+  public void return_status_by_project_id() throws IOException {
     userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN);
 
     ComponentDto project = newProjectDto("project-uuid");
     dbClient.componentDao().insert(dbSession, project);
-    SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newSnapshotForProject(project));
+    SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newSnapshotForProject(project)
+      .setPeriodMode(1, "last_period")
+      .setPeriodDate(1, 956789123456L)
+      .setPeriodMode(2, "last_version")
+      .setPeriodParam(2, "2015-12-07")
+      .setPeriodDate(2, 956789123987L)
+      .setPeriodMode(3, "last_analysis")
+      .setPeriodMode(5, "last_30_days")
+      .setPeriodParam(5, "2015-11-07"));
+    MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
+      .setEnabled(true)
+      .setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY));
+    dbClient.measureDao().insert(dbSession,
+      newMeasureDto(metric, snapshot.getId())
+        .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
     dbSession.commit();
 
-    ProjectStatusWsResponse result = newRequest(snapshot.getId().toString());
+    String response = ws.newRequest()
+      .setParam(PARAM_PROJECT_ID, "project-uuid")
+      .execute().getInput();
 
-    assertThat(result.getProjectStatus().getStatus()).isEqualTo(Status.NONE);
-    assertThat(result.getProjectStatus().getConditionsCount()).isEqualTo(0);
+    assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
   }
 
   @Test
-  public void return_undefined_status_if_measure_data_is_not_well_formatted() {
-    userSession.login("john").setGlobalPermissions(SCAN_EXECUTION);
+  public void return_status_by_project_key() throws IOException {
+    userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN);
 
-    ComponentDto project = newProjectDto("project-uuid");
+    ComponentDto project = newProjectDto("project-uuid")
+      .setKey("project-key");
     dbClient.componentDao().insert(dbSession, project);
-    SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newSnapshotForProject(project));
+    SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newSnapshotForProject(project)
+      .setPeriodMode(1, "last_period")
+      .setPeriodDate(1, 956789123456L)
+      .setPeriodMode(2, "last_version")
+      .setPeriodParam(2, "2015-12-07")
+      .setPeriodDate(2, 956789123987L)
+      .setPeriodMode(3, "last_analysis")
+      .setPeriodMode(5, "last_30_days")
+      .setPeriodParam(5, "2015-11-07"));
     MetricDto metric = dbClient.metricDao().insert(dbSession, newMetricDto()
       .setEnabled(true)
       .setKey(CoreMetrics.QUALITY_GATE_DETAILS_KEY));
-    MeasureDto measure = newMeasureDto(metric, snapshot.getId()).setData("");
-    dbClient.measureDao().insert(dbSession, measure);
+    dbClient.measureDao().insert(dbSession,
+      newMeasureDto(metric, snapshot.getId())
+        .setData(IOUtils.toString(getClass().getResource("ProjectStatusActionTest/measure_data.json"))));
     dbSession.commit();
 
-    ProjectStatusWsResponse result = newRequest(String.valueOf(snapshot.getId()));
+    String response = ws.newRequest()
+      .setParam(PARAM_PROJECT_KEY, "project-key")
+      .execute().getInput();
 
-    assertThat(result.getProjectStatus().getStatus()).isEqualTo(Status.NONE);
-    assertThat(result.getProjectStatus().getConditionsCount()).isEqualTo(0);
+    assertJson(response).isSimilarTo(getClass().getResource("project_status-example.json"));
   }
 
   @Test
-  public void fail_if_insufficient_privileges() {
-    userSession.login("john").setGlobalPermissions(PREVIEW_EXECUTION);
+  public void return_undefined_status_if_measure_is_not_found() {
+    userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN);
 
     ComponentDto project = newProjectDto("project-uuid");
     dbClient.componentDao().insert(dbSession, project);
     SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newSnapshotForProject(project));
     dbSession.commit();
 
-    expectedException.expect(ForbiddenException.class);
-    newRequest(snapshot.getId().toString());
+    ProjectStatusWsResponse result = newRequest(snapshot.getId().toString());
+
+    assertThat(result.getProjectStatus().getStatus()).isEqualTo(Status.NONE);
+    assertThat(result.getProjectStatus().getConditionsCount()).isEqualTo(0);
   }
 
   @Test
@@ -201,6 +223,48 @@ public class ProjectStatusActionTest {
     newRequest(snapshot.getId().toString());
   }
 
+  @Test
+  public void fail_if_no_snapshot_id_found() {
+    userSession.login("john").setGlobalPermissions(SYSTEM_ADMIN);
+
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage("Analysis with id 'task-uuid' is not found");
+
+    newRequest(ANALYSIS_ID);
+  }
+
+  @Test
+  public void fail_if_insufficient_privileges() {
+    userSession.login("john").setGlobalPermissions(PREVIEW_EXECUTION);
+
+    ComponentDto project = newProjectDto("project-uuid");
+    dbClient.componentDao().insert(dbSession, project);
+    SnapshotDto snapshot = dbClient.snapshotDao().insert(dbSession, newSnapshotForProject(project));
+    dbSession.commit();
+
+    expectedException.expect(ForbiddenException.class);
+    newRequest(snapshot.getId().toString());
+  }
+
+  @Test
+  public void fail_if_project_id_and_ce_task_id_provided() {
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("One (and only one) of the following parameters must be provided 'analysisId', 'projectId', 'projectKey'");
+
+    ws.newRequest()
+      .setParam(PARAM_ANALYSIS_ID, "analysis-id")
+      .setParam(PARAM_PROJECT_ID, "project-uuid")
+      .execute().getInput();
+  }
+
+  @Test
+  public void fail_if_no_parameter_provided() {
+    expectedException.expect(BadRequestException.class);
+    expectedException.expectMessage("One (and only one) of the following parameters must be provided 'analysisId', 'projectId', 'projectKey'");
+
+    ws.newRequest().execute().getInput();
+  }
+
   private ProjectStatusWsResponse newRequest(String taskId) {
     try {
       return ProjectStatusWsResponse.parseFrom(
index b421b5df5322978980241af77073093deb450381..19355575e30fe2c93b69090c9ecc745a8ec1c4b7 100644 (file)
  */
 package org.sonar.server.qualitygate.ws;
 
+import com.google.common.base.Optional;
 import java.io.IOException;
 import java.util.List;
+import javax.annotation.Nullable;
 import org.apache.commons.io.IOUtils;
 import org.junit.Rule;
 import org.junit.Test;
@@ -49,7 +51,7 @@ public class QualityGateDetailsFormatterTest {
       .setPeriodMode(3, "last_analysis")
       .setPeriodMode(5, "last_30_days")
       .setPeriodParam(5, "2015-11-07");
-    underTest = new QualityGateDetailsFormatter(measureData, snapshot);
+    underTest = newQualityGateDetailsFormatter(measureData, snapshot);
 
     ProjectStatus result = underTest.format();
 
@@ -82,22 +84,10 @@ public class QualityGateDetailsFormatterTest {
     assertThat(periods).extracting("index").containsExactly(1, 2, 3, 5);
     assertThat(periods).extracting("mode").containsExactly("last_period", "last_version", "last_analysis", "last_30_days");
     assertThat(periods).extracting("parameter").containsExactly("", "2015-12-07", "", "2015-11-07");
-    System.out.println(System.currentTimeMillis());
     assertThat(periods.get(0).getDate()).startsWith("2015-12-07T");
     assertThat(periods.get(1).getDate()).startsWith("2015-12-06T");
   }
 
-  @Test
-  public void undefined_quality_gate_when_ill_formatted_measure_data() {
-    underTest = new QualityGateDetailsFormatter("", new SnapshotDto());
-
-    ProjectStatus result = underTest.format();
-
-    assertThat(result.getStatus()).isEqualTo(ProjectStatusWsResponse.Status.NONE);
-    assertThat(result.getPeriodsCount()).isEqualTo(0);
-    assertThat(result.getConditionsCount()).isEqualTo(0);
-  }
-
   @Test
   public void fail_when_measure_level_is_unknown() {
     String measureData = "{\n" +
@@ -114,7 +104,7 @@ public class QualityGateDetailsFormatterTest {
       "    }\n" +
       "  ]\n" +
       "}";
-    underTest = new QualityGateDetailsFormatter(measureData, new SnapshotDto());
+    underTest = newQualityGateDetailsFormatter(measureData, new SnapshotDto());
     expectedException.expect(IllegalStateException.class);
     expectedException.expectMessage("Unknown quality gate status 'UNKNOWN'");
 
@@ -137,10 +127,14 @@ public class QualityGateDetailsFormatterTest {
       "    }\n" +
       "  ]\n" +
       "}";
-    underTest = new QualityGateDetailsFormatter(measureData, new SnapshotDto());
+    underTest = newQualityGateDetailsFormatter(measureData, new SnapshotDto());
     expectedException.expect(IllegalStateException.class);
     expectedException.expectMessage("Unknown quality gate comparator 'UNKNOWN'");
 
     underTest.format();
   }
+
+  private static QualityGateDetailsFormatter newQualityGateDetailsFormatter(@Nullable String measureData, @Nullable SnapshotDto snapshotDto) {
+    return new QualityGateDetailsFormatter(Optional.fromNullable(measureData), Optional.fromNullable(snapshotDto));
+  }
 }
index e5bf09d8e3cc128319452a0aac8a040be5dc597b..328efa5bb5826c37d8604223e71a3e9fb6f9935b 100644 (file)
  */
 package org.sonarqube.ws.client.qualitygate;
 
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
 public class ProjectStatusWsRequest {
-  private String taskId;
+  private String analysisId;
+  private String projectId;
+  private String projectKey;
 
+  @CheckForNull
   public String getAnalysisId() {
-    return taskId;
+    return analysisId;
+  }
+
+  public ProjectStatusWsRequest setAnalysisId(@Nullable String analysisId) {
+    this.analysisId = analysisId;
+    return this;
+  }
+
+  @CheckForNull
+  public String getProjectId() {
+    return projectId;
+  }
+
+  public ProjectStatusWsRequest setProjectId(@Nullable String projectId) {
+    this.projectId = projectId;
+    return this;
+  }
+
+  @CheckForNull
+  public String getProjectKey() {
+    return projectKey;
   }
 
-  public ProjectStatusWsRequest setAnalysisId(String taskId) {
-    this.taskId = taskId;
+  public ProjectStatusWsRequest setProjectKey(@Nullable String projectKey) {
+    this.projectKey = projectKey;
     return this;
   }
 }
index 6142b9aa1673ebe816cd7e5e20192d59d8026fa3..bd00874f57a6ba11be01f767b17c5a198880f891 100644 (file)
@@ -24,6 +24,10 @@ import org.sonarqube.ws.client.BaseService;
 import org.sonarqube.ws.client.GetRequest;
 import org.sonarqube.ws.client.WsConnector;
 
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_ANALYSIS_ID;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_ID;
+import static org.sonarqube.ws.client.qualitygate.QualityGatesWsParameters.PARAM_PROJECT_KEY;
+
 public class QualityGatesService extends BaseService {
 
   public QualityGatesService(WsConnector wsConnector) {
@@ -32,7 +36,9 @@ public class QualityGatesService extends BaseService {
 
   public ProjectStatusWsResponse projectStatus(ProjectStatusWsRequest request) {
     return call(new GetRequest(path("project_status"))
-      .setParam("analysisId", request.getAnalysisId()),
+      .setParam(PARAM_ANALYSIS_ID, request.getAnalysisId())
+      .setParam(PARAM_PROJECT_ID, request.getProjectId())
+      .setParam(PARAM_PROJECT_KEY, request.getProjectKey()),
       ProjectStatusWsResponse.parser());
   }
 }
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesWsParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/qualitygate/QualityGatesWsParameters.java
new file mode 100644 (file)
index 0000000..5ba885b
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact 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.sonarqube.ws.client.qualitygate;
+
+public class QualityGatesWsParameters {
+  public static final String PARAM_ANALYSIS_ID = "analysisId";
+  public static final String PARAM_PROJECT_ID = "projectId";
+  public static final String PARAM_PROJECT_KEY = "projectKey";
+
+  private QualityGatesWsParameters() {
+    // prevent instantiation
+  }
+
+}