]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-10134 Bringing Organization to Search Action
authorGuillaume Jambet <guillaume.jambet@sonarsource.com>
Thu, 7 Dec 2017 15:59:56 +0000 (16:59 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 14 Dec 2017 16:03:35 +0000 (17:03 +0100)
server/sonar-server/src/main/java/org/sonar/server/qualitygate/QgateProjectFinder.java
server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java
server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/example-search.json [deleted file]
server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/search-example.json [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/qualitygate/QgateProjectFinderTest.java
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java [deleted file]
server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SearchActionTest.java [new file with mode: 0644]
sonar-ws/src/main/protobuf/ws-qualitygates.proto

index 4d9e79bd748247c2100f0a64d2914e04274048a8..4f561bd8d5a201ae59a9322365586c18c6ec1245 100644 (file)
@@ -27,6 +27,7 @@ import org.sonar.api.web.UserRole;
 import org.sonar.core.util.stream.MoreCollectors;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
+import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.qualitygate.ProjectQgateAssociation;
 import org.sonar.db.qualitygate.ProjectQgateAssociationDao;
 import org.sonar.db.qualitygate.ProjectQgateAssociationDto;
@@ -52,21 +53,19 @@ public class QgateProjectFinder {
     this.associationDao = dbClient.projectQgateAssociationDao();
   }
 
-  public Association find(ProjectQgateAssociationQuery query) {
-    try (DbSession dbSession = dbClient.openSession(false)) {
-      getQualityGateId(dbSession, query.gateId());
-      List<ProjectQgateAssociationDto> projects = associationDao.selectProjects(dbSession, query);
-      List<ProjectQgateAssociationDto> authorizedProjects = keepAuthorizedProjects(dbSession, projects);
+  public Association find(DbSession dbSession, OrganizationDto organization, ProjectQgateAssociationQuery query) {
+    getQualityGateId(dbSession, organization, query.gateId());
+    List<ProjectQgateAssociationDto> projects = associationDao.selectProjects(dbSession, query);
+    List<ProjectQgateAssociationDto> authorizedProjects = keepAuthorizedProjects(dbSession, projects);
 
-      Paging paging = forPageIndex(query.pageIndex())
-        .withPageSize(query.pageSize())
-        .andTotal(authorizedProjects.size());
-      return new Association(toProjectAssociations(getPaginatedProjects(authorizedProjects, paging)), paging.hasNextPage());
-    }
+    Paging paging = forPageIndex(query.pageIndex())
+      .withPageSize(query.pageSize())
+      .andTotal(authorizedProjects.size());
+    return new Association(toProjectAssociations(getPaginatedProjects(authorizedProjects, paging)), paging.hasNextPage());
   }
 
-  private Long getQualityGateId(DbSession dbSession, String gateId) {
-    return checkFound(qualitygateDao.selectById(dbSession, Long.valueOf(gateId)), "Quality gate '" + gateId + "' does not exists.").getId();
+  private Long getQualityGateId(DbSession dbSession, OrganizationDto organization, String gateId) {
+    return checkFound(qualitygateDao.selectByOrganizationAndId(dbSession, organization, Long.valueOf(gateId)), "Quality gate '" + gateId + "' does not exists.").getId();
   }
 
   private static List<ProjectQgateAssociationDto> getPaginatedProjects(List<ProjectQgateAssociationDto> projects, Paging paging) {
index 285d723bec7aaaba5ac4da9394b4767363295b24..67d4e1b905cb02cac1d42037b92961cb1d4d2c7e 100644 (file)
@@ -23,18 +23,32 @@ import com.google.common.io.Resources;
 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.server.ws.WebService.Param;
-import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.qualitygate.ProjectQgateAssociation;
 import org.sonar.db.qualitygate.ProjectQgateAssociationQuery;
 import org.sonar.server.qualitygate.QgateProjectFinder;
+import org.sonarqube.ws.Qualitygates;
+
+import static org.sonar.api.server.ws.WebService.Param.SELECTED;
+import static org.sonar.db.qualitygate.ProjectQgateAssociationQuery.ANY;
+import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_ID;
+import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PAGE;
+import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PAGE_SIZE;
+import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_QUERY;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
 
 public class SearchAction implements QualityGatesWsAction {
 
+  private final DbClient dbClient;
   private final QgateProjectFinder projectFinder;
+  private final QualityGatesWsSupport wsSupport;
 
-  public SearchAction(QgateProjectFinder projectFinder) {
+  public SearchAction(DbClient dbClient, QgateProjectFinder projectFinder, QualityGatesWsSupport wsSupport) {
+    this.dbClient = dbClient;
     this.projectFinder = projectFinder;
+    this.wsSupport = wsSupport;
   }
 
   @Override
@@ -43,47 +57,60 @@ public class SearchAction implements QualityGatesWsAction {
       .setDescription("Search for projects associated (or not) to a quality gate.<br/>" +
         "Only authorized projects for current user will be returned.")
       .setSince("4.3")
-      .setResponseExample(Resources.getResource(this.getClass(), "example-search.json"))
+      .setResponseExample(Resources.getResource(this.getClass(), "search-example.json"))
       .setHandler(this);
 
-    action.createParam(QualityGatesWsParameters.PARAM_GATE_ID)
+    action.createParam(PARAM_GATE_ID)
       .setDescription("Quality Gate ID")
       .setRequired(true)
       .setExampleValue("1");
 
-    action.createParam(QualityGatesWsParameters.PARAM_QUERY)
+    action.createParam(PARAM_QUERY)
       .setDescription("To search for projects containing this string. If this parameter is set, \"selected\" is set to \"all\".")
       .setExampleValue("abc");
 
     action.addSelectionModeParam();
 
-    action.createParam(QualityGatesWsParameters.PARAM_PAGE)
+    action.createParam(PARAM_PAGE)
       .setDescription("Page number")
       .setDefaultValue("1")
       .setExampleValue("2");
 
-    action.createParam(QualityGatesWsParameters.PARAM_PAGE_SIZE)
+    action.createParam(PARAM_PAGE_SIZE)
       .setDescription("Page size")
       .setExampleValue("10");
+
+    wsSupport.createOrganizationParam(action);
   }
 
   @Override
   public void handle(Request request, Response response) {
-    QgateProjectFinder.Association associations = projectFinder.find(ProjectQgateAssociationQuery.builder()
-      .gateId(request.mandatoryParam(QualityGatesWsParameters.PARAM_GATE_ID))
-      .membership(request.param(QualityGatesWsParameters.PARAM_QUERY) == null ? request.param(Param.SELECTED) : ProjectQgateAssociationQuery.ANY)
-      .projectSearch(request.param(QualityGatesWsParameters.PARAM_QUERY))
-      .pageIndex(request.paramAsInt(QualityGatesWsParameters.PARAM_PAGE))
-      .pageSize(request.paramAsInt(QualityGatesWsParameters.PARAM_PAGE_SIZE))
-      .build());
-    try (JsonWriter writer = response.newJsonWriter()) {
-      writer.beginObject().prop("more", associations.hasMoreResults());
-      writer.name("results").beginArray();
+
+    try (DbSession dbSession = dbClient.openSession(false)) {
+
+      OrganizationDto organization = wsSupport.getOrganization(dbSession, request);
+
+      QgateProjectFinder.Association associations = projectFinder.find(dbSession, organization,
+        ProjectQgateAssociationQuery.builder()
+          .gateId(request.mandatoryParam(PARAM_GATE_ID))
+          .membership(request.param(PARAM_QUERY) == null ? request.param(SELECTED) : ANY)
+          .projectSearch(request.param(PARAM_QUERY))
+          .pageIndex(request.paramAsInt(PARAM_PAGE))
+          .pageSize(request.paramAsInt(PARAM_PAGE_SIZE))
+          .build());
+
+      Qualitygates.SearchResponse.Builder createResponse = Qualitygates.SearchResponse.newBuilder()
+        .setMore(associations.hasMoreResults());
+
       for (ProjectQgateAssociation project : associations.projects()) {
-        writer.beginObject().prop("id", project.id()).prop("name", project.name()).prop(Param.SELECTED, project.isMember()).endObject();
+        createResponse.addResultsBuilder()
+          .setId(project.id())
+          .setName(project.name())
+          .setSelected(project.isMember());
       }
-      writer.endArray().endObject().close();
+
+      writeProtobuf(createResponse.build(), request, response);
+
     }
   }
-
 }
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/example-search.json b/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/example-search.json
deleted file mode 100644 (file)
index 7ad6eed..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "more": true,
-  "results": [
-    {
-      "id": 1,
-      "name": "Simple Java project analyzed with the SonarQube Runner",
-      "selected": true
-    },
-    {
-      "id": 4,
-      "name": "My Project",
-      "selected": true
-    }
-  ]
-}
diff --git a/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/search-example.json b/server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/search-example.json
new file mode 100644 (file)
index 0000000..7ad6eed
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "more": true,
+  "results": [
+    {
+      "id": 1,
+      "name": "Simple Java project analyzed with the SonarQube Runner",
+      "selected": true
+    },
+    {
+      "id": 4,
+      "name": "My Project",
+      "selected": true
+    }
+  ]
+}
index fee90f42ebad13db2cbc0ac39256726d4a5fdac1..2e0e79bafe0164e69fc2c1197eb820769866888e 100644 (file)
@@ -23,19 +23,16 @@ import com.google.common.base.Function;
 import java.util.List;
 import java.util.Map;
 import javax.annotation.Nonnull;
-import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 import org.sonar.api.utils.System2;
-import org.sonar.api.web.UserRole;
 import org.sonar.core.util.Uuids;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
 import org.sonar.db.DbTester;
 import org.sonar.db.component.ComponentDbTester;
 import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentTesting;
 import org.sonar.db.organization.OrganizationDto;
 import org.sonar.db.property.PropertyDto;
 import org.sonar.db.qualitygate.ProjectQgateAssociation;
@@ -48,6 +45,9 @@ import org.sonar.server.tester.UserSessionRule;
 
 import static com.google.common.collect.FluentIterable.from;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.api.web.UserRole.USER;
+import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
+import static org.sonar.db.component.ComponentTesting.newPublicProjectDto;
 import static org.sonar.db.qualitygate.ProjectQgateAssociationQuery.IN;
 import static org.sonar.db.qualitygate.ProjectQgateAssociationQuery.OUT;
 import static org.sonar.db.qualitygate.ProjectQgateAssociationQuery.builder;
@@ -67,19 +67,16 @@ public class QgateProjectFinderTest {
   private DbClient dbClient = dbTester.getDbClient();
   private DbSession dbSession = dbTester.getSession();
   private ComponentDbTester componentDbTester = new ComponentDbTester(dbTester);
-  private QualityGateDto qGate;
   private QgateProjectFinder underTest = new QgateProjectFinder(dbClient, userSession);
 
-  @Before
-  public void setUp() throws Exception {
-    qGate = new QualityGateDto().setName("Default Quality Gate").setUuid(Uuids.createFast());
-    dbClient.qualityGateDao().insert(dbSession, qGate);
-    dbTester.commit();
-  }
-
   @Test
   public void return_empty_association() {
-    Association result = underTest.find(
+    OrganizationDto organization = dbTester.organizations().insert();
+    QualityGateDto qGate = dbTester.qualityGates().insertQualityGate(organization,
+      qualityGateDto -> qualityGateDto.setName("Default Quality Gate").setUuid(Uuids.createFast()));
+    dbTester.commit();
+
+    Association result = underTest.find(dbSession, organization,
       builder()
         .gateId(Long.toString(qGate.getId()))
         .build());
@@ -89,12 +86,17 @@ public class QgateProjectFinderTest {
 
   @Test
   public void return_all_projects() {
-    OrganizationDto org = dbTester.organizations().insert();
-    ComponentDto associatedProject = insertProject(ComponentTesting.newPublicProjectDto(org));
-    ComponentDto unassociatedProject = insertProject(ComponentTesting.newPublicProjectDto(org));
-    associateProjectToQualitGate(associatedProject.getId());
+    OrganizationDto organization = dbTester.organizations().insert();
+    QualityGateDto qGate = dbTester.qualityGates().insertQualityGate(organization,
+      qualityGateDto -> qualityGateDto.setName("Default Quality Gate").setUuid(Uuids.createFast()));
+    dbTester.commit();
+    ComponentDto unassociatedProject = newPublicProjectDto(organization);
+    dbTester.components().insertComponent(unassociatedProject);
+    ComponentDto associatedProject = newPublicProjectDto(organization);
+    dbTester.components().insertComponent(associatedProject);
+    associateProjectToQualitGate(associatedProject, qGate);
 
-    Association result = underTest.find(
+    Association result = underTest.find(dbSession, organization,
       builder()
         .gateId(Long.toString(qGate.getId()))
         .build());
@@ -108,12 +110,18 @@ public class QgateProjectFinderTest {
 
   @Test
   public void return_only_associated_project() {
-    OrganizationDto org = dbTester.organizations().insert();
-    ComponentDto associatedProject = insertProject(ComponentTesting.newPublicProjectDto(org));
-    insertProject(ComponentTesting.newPublicProjectDto(org));
-    associateProjectToQualitGate(associatedProject.getId());
+    OrganizationDto organization = dbTester.organizations().insert();
+    QualityGateDto qGate = dbTester.qualityGates().insertQualityGate(organization,
+      qualityGateDto -> qualityGateDto.setName("Default Quality Gate").setUuid(Uuids.createFast()));
+    dbTester.commit();
+    ComponentDto project1 = newPublicProjectDto(organization);
+    dbTester.components().insertComponent(project1);
+    ComponentDto associatedProject = project1;
+    ComponentDto project = newPublicProjectDto(organization);
+    dbTester.components().insertComponent(project);
+    associateProjectToQualitGate(associatedProject, qGate);
 
-    Association result = underTest.find(
+    Association result = underTest.find(dbSession, organization,
       builder()
         .membership(IN)
         .gateId(Long.toString(qGate.getId()))
@@ -126,12 +134,17 @@ public class QgateProjectFinderTest {
 
   @Test
   public void return_only_unassociated_project() {
-    OrganizationDto org = dbTester.organizations().insert();
-    ComponentDto associatedProject = insertProject(ComponentTesting.newPublicProjectDto(org));
-    ComponentDto unassociatedProject = insertProject(ComponentTesting.newPublicProjectDto(org));
-    associateProjectToQualitGate(associatedProject.getId());
+    OrganizationDto organization = dbTester.organizations().insert();
+    QualityGateDto qGate = dbTester.qualityGates().insertQualityGate(organization,
+      qualityGateDto -> qualityGateDto.setName("Default Quality Gate").setUuid(Uuids.createFast()));
+    dbTester.commit();
+    ComponentDto unAssociatedProject = newPublicProjectDto(organization);
+    dbTester.components().insertComponent(unAssociatedProject);
+    ComponentDto associatedProject = newPublicProjectDto(organization);
+    dbTester.components().insertComponent(associatedProject);
+    associateProjectToQualitGate(associatedProject, qGate);
 
-    Association result = underTest.find(
+    Association result = underTest.find(dbSession, organization,
       builder()
         .membership(OUT)
         .gateId(Long.toString(qGate.getId()))
@@ -139,53 +152,65 @@ public class QgateProjectFinderTest {
 
     Map<Long, ProjectQgateAssociation> projectsById = projectsById(result.projects());
     assertThat(projectsById).hasSize(1);
-    verifyProject(projectsById.get(unassociatedProject.getId()), false, unassociatedProject.name());
+    verifyProject(projectsById.get(unAssociatedProject.getId()), false, unAssociatedProject.name());
   }
 
   @Test
   public void return_only_authorized_projects() {
+    OrganizationDto organization = dbTester.organizations().insert();
+    QualityGateDto qGate = dbTester.qualityGates().insertQualityGate(organization,
+      qualityGateDto -> qualityGateDto.setName("Default Quality Gate").setUuid(Uuids.createFast()));
+    dbTester.commit();
     UserDto user = dbTester.users().insertUser("a_login");
-    OrganizationDto organizationDto = dbTester.organizations().insert();
-    ComponentDto project1 = componentDbTester.insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto));
-    componentDbTester.insertComponent(ComponentTesting.newPrivateProjectDto(organizationDto));
+    ComponentDto project = componentDbTester.insertComponent(newPrivateProjectDto(organization));
+    componentDbTester.insertComponent(newPrivateProjectDto(organization));
 
     // User can only see project 1
-    dbTester.users().insertProjectPermissionOnUser(user, UserRole.USER, project1);
+    dbTester.users().insertProjectPermissionOnUser(user, USER, project);
 
     userSession.logIn(user.getLogin()).setUserId(user.getId());
-    Association result = underTest.find(
+    Association result = underTest.find(dbSession, organization,
       builder()
         .gateId(Long.toString(qGate.getId()))
         .build());
 
-    verifyProjects(result, project1.getId());
+    verifyProjects(result, project.getId());
   }
 
   @Test
   public void do_not_verify_permissions_if_user_is_root() {
-    OrganizationDto org = dbTester.organizations().insert();
-    ComponentDto project = componentDbTester.insertPrivateProject(org);
+    OrganizationDto organization = dbTester.organizations().insert();
+    QualityGateDto qGate = dbTester.qualityGates().insertQualityGate(organization,
+      qualityGateDto -> qualityGateDto.setName("Default Quality Gate").setUuid(Uuids.createFast()));
+    dbTester.commit();
+    ComponentDto project = componentDbTester.insertPrivateProject(organization);
     ProjectQgateAssociationQuery query = builder()
       .gateId(Long.toString(qGate.getId()))
       .build();
 
     userSession.logIn().setNonRoot();
-    verifyProjects(underTest.find(query));
+    verifyProjects(underTest.find(dbSession, organization, query));
 
     userSession.logIn().setRoot();
-    verifyProjects(underTest.find(query), project.getId());
+    verifyProjects(underTest.find(dbSession, organization, query), project.getId());
   }
 
   @Test
   public void test_paging() throws Exception {
-    OrganizationDto org = dbTester.organizations().insert();
-    ComponentDto project1 = insertProject(ComponentTesting.newPublicProjectDto(org).setName("Project 1"));
-    ComponentDto project2 = insertProject(ComponentTesting.newPublicProjectDto(org).setName("Project 2"));
-    ComponentDto project3 = insertProject(ComponentTesting.newPublicProjectDto(org).setName("Project 3"));
-    associateProjectToQualitGate(project1.getId());
+    OrganizationDto organization = dbTester.organizations().insert();
+    QualityGateDto qGate = dbTester.qualityGates().insertQualityGate(organization,
+      qualityGateDto -> qualityGateDto.setName("Default Quality Gate").setUuid(Uuids.createFast()));
+    dbTester.commit();
+    ComponentDto project1 = newPublicProjectDto(organization).setName("Project 1");
+    dbTester.components().insertComponent(project1);
+    associateProjectToQualitGate(project1, qGate);
+    ComponentDto project2 = newPublicProjectDto(organization).setName("Project 2");
+    dbTester.components().insertComponent(project2);
+    ComponentDto project3 = newPublicProjectDto(organization).setName("Project 3");
+    dbTester.components().insertComponent(project3);
 
     // Return partial result on first page
-    verifyPaging(underTest.find(
+    verifyPaging(underTest.find(dbSession, organization,
       builder().gateId(Long.toString(qGate.getId()))
         .pageIndex(1)
         .pageSize(1)
@@ -193,7 +218,7 @@ public class QgateProjectFinderTest {
       true, project1.getId());
 
     // Return partial result on second page
-    verifyPaging(underTest.find(
+    verifyPaging(underTest.find(dbSession, organization,
       builder().gateId(Long.toString(qGate.getId()))
         .pageIndex(2)
         .pageSize(1)
@@ -201,7 +226,7 @@ public class QgateProjectFinderTest {
       true, project2.getId());
 
     // Return partial result on first page
-    verifyPaging(underTest.find(
+    verifyPaging(underTest.find(dbSession, organization,
       builder().gateId(Long.toString(qGate.getId()))
         .pageIndex(1)
         .pageSize(2)
@@ -209,7 +234,7 @@ public class QgateProjectFinderTest {
       true, project1.getId(), project2.getId());
 
     // Return all result on first page
-    verifyPaging(underTest.find(
+    verifyPaging(underTest.find(dbSession, organization,
       builder().gateId(Long.toString(qGate.getId()))
         .pageIndex(1)
         .pageSize(3)
@@ -217,7 +242,7 @@ public class QgateProjectFinderTest {
       false, project1.getId(), project2.getId(), project3.getId());
 
     // Return no result as page index is off limit
-    verifyPaging(underTest.find(
+    verifyPaging(underTest.find(dbSession, organization,
       builder().gateId(Long.toString(qGate.getId()))
         .pageIndex(3)
         .pageSize(3)
@@ -228,7 +253,7 @@ public class QgateProjectFinderTest {
   @Test
   public void fail_on_unknown_quality_gate() {
     expectedException.expect(NotFoundException.class);
-    underTest.find(builder().gateId("123").build());
+    underTest.find(dbSession, dbTester.organizations().insert(), builder().gateId("123").build());
   }
 
   private void verifyProject(ProjectQgateAssociation project, boolean expectedMembership, String expectedName) {
@@ -245,19 +270,14 @@ public class QgateProjectFinderTest {
     assertThat(association.projects()).extracting("id").containsOnly(expectedProjectIds);
   }
 
-  private void associateProjectToQualitGate(long projectId) {
+  private void associateProjectToQualitGate(ComponentDto component, QualityGateDto qualityGate) {
     dbClient.propertiesDao().saveProperty(
       new PropertyDto().setKey(SONAR_QUALITYGATE_PROPERTY)
-        .setResourceId(projectId)
-        .setValue(Long.toString(qGate.getId())));
+        .setResourceId(component.getId())
+        .setValue(Long.toString(qualityGate.getId())));
     dbTester.commit();
   }
 
-  private ComponentDto insertProject(ComponentDto project) {
-    dbTester.components().insertComponent(project);
-    return project;
-  }
-
   private static Map<Long, ProjectQgateAssociation> projectsById(List<ProjectQgateAssociation> projects) {
     return from(projects).uniqueIndex(ProjectToId.INSTANCE);
   }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/QualityGatesWsTest.java
deleted file mode 100644 (file)
index 0a6b037..0000000
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * 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 com.google.common.collect.ImmutableList;
-import java.util.List;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.server.ws.Change;
-import org.sonar.api.server.ws.WebService.Action;
-import org.sonar.api.server.ws.WebService.Controller;
-import org.sonar.db.qualitygate.ProjectQgateAssociation;
-import org.sonar.db.qualitygate.ProjectQgateAssociationQuery;
-import org.sonar.server.qualitygate.QgateProjectFinder;
-import org.sonar.server.qualitygate.QgateProjectFinder.Association;
-import org.sonar.server.qualitygate.QualityGates;
-import org.sonar.server.ws.RemovedWebServiceHandler;
-import org.sonar.server.ws.WsTester;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.tuple;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-// TODO split testcases in action tests
-// TODO restore
-@RunWith(MockitoJUnitRunner.class)
-@Ignore
-public class QualityGatesWsTest {
-
-  @Mock
-  private QualityGates qGates;
-
-  @Mock
-  private QgateProjectFinder projectFinder;
-
-  WsTester tester;
-
-  @Before
-  public void setUp() {
-    tester = new WsTester(new QualityGatesWs(
-      new SearchAction(projectFinder),
-      new CreateAction(null, null, null, null),
-      new SetAsDefaultAction(qGates)));
-  }
-
-  @Test
-  public void define_ws() {
-    Controller controller = tester.controller("api/qualitygates");
-    assertThat(controller).isNotNull();
-    assertThat(controller.path()).isEqualTo("api/qualitygates");
-    assertThat(controller.description()).isNotEmpty();
-    assertThat(controller.actions()).hasSize(6);
-
-    Action setDefault = controller.action("set_as_default");
-    assertThat(setDefault).isNotNull();
-    assertThat(setDefault.handler()).isNotNull();
-    assertThat(setDefault.since()).isEqualTo("4.3");
-    assertThat(setDefault.isPost()).isTrue();
-    assertThat(setDefault.param("id")).isNotNull();
-    assertThat(setDefault.isInternal()).isFalse();
-
-    Action unsetDefault = controller.action("unset_default");
-    assertThat(unsetDefault).isNotNull();
-    assertThat(unsetDefault.handler()).isNotNull();
-    assertThat(unsetDefault.since()).isEqualTo("4.3");
-    assertThat(unsetDefault.deprecatedSince()).isEqualTo("7.0");
-    assertThat(unsetDefault.changelog())
-      .extracting(Change::getVersion, Change::getDescription)
-      .containsOnly(
-        tuple("7.0", "Unset a quality gate is no more authorized"));
-    assertThat(unsetDefault.isPost()).isTrue();
-    assertThat(unsetDefault.handler()).isEqualTo(RemovedWebServiceHandler.INSTANCE);
-    assertThat(unsetDefault.responseExample()).isEqualTo(RemovedWebServiceHandler.INSTANCE.getResponseExample());
-    assertThat(unsetDefault.isInternal()).isFalse();
-  }
-
-  @Test
-  public void search_with_query() throws Exception {
-    long gateId = 12345L;
-    Association assoc = mock(Association.class);
-    when(assoc.hasMoreResults()).thenReturn(true);
-    List<ProjectQgateAssociation> projects = ImmutableList.of(
-      new ProjectQgateAssociation().setId(42L).setName("Project One").setMember(false),
-      new ProjectQgateAssociation().setId(24L).setName("Project Two").setMember(true));
-    when(assoc.projects()).thenReturn(projects);
-    when(projectFinder.find(any(ProjectQgateAssociationQuery.class))).thenReturn(assoc);
-
-    tester.newGetRequest("api/qualitygates", "search")
-      .setParam("gateId", Long.toString(gateId))
-      .setParam("query", "Project")
-      .execute()
-      .assertJson("{\"more\":true,\"results\":["
-        + "{\"id\":42,\"name\":\"Project One\",\"selected\":false},"
-        + "{\"id\":24,\"name\":\"Project Two\",\"selected\":true}"
-        + "]}");
-    ArgumentCaptor<ProjectQgateAssociationQuery> queryCaptor = ArgumentCaptor.forClass(ProjectQgateAssociationQuery.class);
-    verify(projectFinder).find(queryCaptor.capture());
-    ProjectQgateAssociationQuery query = queryCaptor.getValue();
-    assertThat(query.membership()).isEqualTo(ProjectQgateAssociationQuery.ANY);
-  }
-
-  @Test
-  public void search_nominal() throws Exception {
-    long gateId = 12345L;
-    Association assoc = mock(Association.class);
-    when(assoc.hasMoreResults()).thenReturn(true);
-    List<ProjectQgateAssociation> projects = ImmutableList.of(
-      new ProjectQgateAssociation().setId(24L).setName("Project Two").setMember(true));
-    when(assoc.projects()).thenReturn(projects);
-    when(projectFinder.find(any(ProjectQgateAssociationQuery.class))).thenReturn(assoc);
-
-    tester.newGetRequest("api/qualitygates", "search")
-      .setParam("gateId", Long.toString(gateId))
-      .execute()
-      .assertJson("{\"more\":true,\"results\":["
-        + "{\"id\":24,\"name\":\"Project Two\",\"selected\":true}"
-        + "]}");
-    ArgumentCaptor<ProjectQgateAssociationQuery> queryCaptor = ArgumentCaptor.forClass(ProjectQgateAssociationQuery.class);
-    verify(projectFinder).find(queryCaptor.capture());
-    ProjectQgateAssociationQuery query = queryCaptor.getValue();
-    assertThat(query.membership()).isEqualTo(ProjectQgateAssociationQuery.IN);
-  }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SearchActionTest.java
new file mode 100644 (file)
index 0000000..ebc4997
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * 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.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.organization.OrganizationDto;
+import org.sonar.db.property.PropertyDto;
+import org.sonar.db.qualitygate.QualityGateDto;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.organization.TestDefaultOrganizationProvider;
+import org.sonar.server.qualitygate.QgateProjectFinder;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.Qualitygates.SearchResponse;
+
+import static java.lang.String.format;
+import static java.lang.String.valueOf;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.AssertionsForClassTypes.tuple;
+import static org.sonar.api.utils.System2.INSTANCE;
+import static org.sonar.db.permission.OrganizationPermission.ADMINISTER_QUALITY_GATES;
+import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_GATE_ID;
+import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_ORGANIZATION;
+import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PAGE;
+import static org.sonar.server.qualitygate.ws.QualityGatesWsParameters.PARAM_PAGE_SIZE;
+
+public class SearchActionTest {
+
+  @Rule
+  public ExpectedException expectedException = ExpectedException.none();
+
+  @Rule
+  public UserSessionRule userSession = UserSessionRule.standalone();
+
+  @Rule
+  public DbTester db = DbTester.create(INSTANCE);
+
+  private DbClient dbClient = db.getDbClient();
+  private DbSession dbSession = db.getSession();
+  private TestDefaultOrganizationProvider defaultOrganizationProvider = TestDefaultOrganizationProvider.from(db);
+
+  private QgateProjectFinder projectFinder = new QgateProjectFinder(dbClient, userSession);
+  private QualityGatesWsSupport wsSupport = new QualityGatesWsSupport(dbClient, userSession, defaultOrganizationProvider);
+
+  private SearchAction underTest = new SearchAction(dbClient, projectFinder, wsSupport);
+  private WsActionTester ws = new WsActionTester(underTest);
+
+  @Test
+  public void definition() {
+    WebService.Action action = ws.getDef();
+
+    assertThat(action).isNotNull();
+    assertThat(action.isInternal()).isFalse();
+    assertThat(action.isPost()).isFalse();
+    assertThat(action.responseExampleAsString()).isNotEmpty();
+    assertThat(action.params())
+      .extracting(WebService.Param::key, WebService.Param::isRequired)
+      .containsExactlyInAnyOrder(
+        tuple("gateId", true),
+        tuple("query", false),
+        tuple("organization", false),
+        tuple("selected", false),
+        tuple("page", false),
+        tuple("pageSize", false));
+  }
+
+  @Test
+  public void search_projects_of_a_quality_gate_from_an_organization() {
+    OrganizationDto organization = db.organizations().insert();
+    ComponentDto project = db.components().insertPublicProject(organization);
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization);
+    associateProjectToQualityGate(project, qualityGate);
+    userSession.addPermission(ADMINISTER_QUALITY_GATES, organization);
+
+    SearchResponse response = ws.newRequest()
+      .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId()))
+      .setParam(PARAM_ORGANIZATION, valueOf(organization.getKey()))
+      .executeProtobuf(SearchResponse.class);
+
+    assertThat(response).isNotNull();
+    assertThat(response.getMore()).isFalse();
+    assertThat(response.getResultsCount()).isEqualTo(1);
+    assertThat(response.getResults(0).getId()).isEqualTo(project.getId());
+    assertThat(response.getResults(0).getName().substring(4)).isEqualTo(project.getKey().substring(3));
+  }
+
+  @Test
+  public void search_on_default_organization_when_none_is_provided() {
+    OrganizationDto defaultOrganization = db.getDefaultOrganization();
+
+    ComponentDto project = db.components().insertPublicProject(defaultOrganization);
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate(defaultOrganization);
+    associateProjectToQualityGate(project, qualityGate);
+    userSession.addPermission(ADMINISTER_QUALITY_GATES, defaultOrganization);
+
+    SearchResponse response = ws.newRequest()
+      .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId()))
+      .executeProtobuf(SearchResponse.class);
+
+    assertThat(response).isNotNull();
+    assertThat(response.getMore()).isFalse();
+    assertThat(response.getResultsCount()).isEqualTo(1);
+    assertThat(response.getResults(0).getId()).isEqualTo(project.getId());
+    assertThat(response.getResults(0).getName().substring(4)).isEqualTo(project.getKey().substring(3));
+  }
+
+  @Test
+  public void fail_when_quality_gates_does_not_belong_to_organization() {
+    OrganizationDto organization = db.organizations().insert();
+    OrganizationDto otherOrganization = db.organizations().insert();
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate(otherOrganization);
+
+    expectedException.expect(NotFoundException.class);
+    expectedException.expectMessage(format("Quality gate '%s' does not exists.", qualityGate.getId()));
+
+    ws.newRequest()
+      .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId()))
+      .setParam(PARAM_ORGANIZATION, valueOf(organization.getKey()))
+      .executeProtobuf(SearchResponse.class);
+
+  }
+
+  @Test
+  public void more_is_true_when_not_all_project_fit_in_page_size() {
+    OrganizationDto organization = db.organizations().insert();
+    QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization);
+    for (int i = 0; i < 20; i++) {
+      ComponentDto project1 = db.components().insertPublicProject();
+      associateProjectToQualityGate(project1, qualityGate);
+    }
+
+    userSession.addPermission(ADMINISTER_QUALITY_GATES, organization);
+
+    SearchResponse response = ws.newRequest()
+      .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId()))
+      .setParam(PARAM_ORGANIZATION, valueOf(organization.getKey()))
+      .setParam(PARAM_PAGE_SIZE, valueOf(10))
+      .setParam(PARAM_PAGE, valueOf(1))
+      .executeProtobuf(SearchResponse.class);
+
+    assertThat(response).isNotNull();
+    assertThat(response.getMore()).isTrue();
+    assertThat(response.getResultsCount()).isEqualTo(10);
+  }
+
+  private void associateProjectToQualityGate(ComponentDto componentDto, QualityGateDto qualityGateDto) {
+    dbClient.propertiesDao().saveProperty(dbSession, new PropertyDto()
+      .setKey("sonar.qualitygate")
+      .setResourceId(componentDto.getId())
+      .setValue(valueOf(qualityGateDto.getId())));
+    db.commit();
+  }
+}
index 08e1c4570dd4fbc14e582dd047137d0dd4a35229..c9b63db577692f68ef3e4d41e5f73b832c754efe 100644 (file)
@@ -136,6 +136,18 @@ message ShowWsResponse {
   }
 }
 
+// GET api/qualitygates/search
+message SearchResponse {
+  optional bool more = 1;
+  repeated Result results = 2;
+
+  message Result {
+    optional int64 id = 1;
+    optional string name = 2;
+    optional bool selected = 3;
+  }
+}
+
 // GET api/qualitygates/list
 message ListWsResponse {
   repeated QualityGate qualitygates = 1;