]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9016 Use 'Paging' in api/user_groups/search WS
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Mon, 3 Apr 2017 13:52:25 +0000 (15:52 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 13 Apr 2017 09:51:55 +0000 (11:51 +0200)
server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/SearchAction.java
server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/SearchActionTest.java
server/sonar-web/src/main/js/apps/groups/groups.js
sonar-ws/src/main/protobuf/ws-user_groups.proto

index 695300fa2d8e0d09cbe7d26c8bbb639a9f4094d7..15f70e04fe51508e98376f05f2112b8d696a4fbc 100644 (file)
@@ -24,12 +24,13 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import org.sonar.api.server.ws.Change;
 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.NewController;
 import org.sonar.api.server.ws.WebService.Param;
-import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.api.utils.Paging;
 import org.sonar.core.util.stream.MoreCollectors;
 import org.sonar.db.DbClient;
 import org.sonar.db.DbSession;
@@ -39,13 +40,17 @@ import org.sonar.server.es.SearchOptions;
 import org.sonar.server.user.UserSession;
 
 import static org.apache.commons.lang.StringUtils.defaultIfBlank;
+import static org.sonar.api.utils.Paging.forPageIndex;
+import static org.sonar.core.util.Protobuf.setNullable;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
 import static org.sonar.server.es.SearchOptions.MAX_LIMIT;
 import static org.sonar.server.usergroups.ws.GroupWsSupport.PARAM_ORGANIZATION_KEY;
+import static org.sonar.server.ws.WsUtils.writeProtobuf;
+import static org.sonarqube.ws.WsUserGroups.Group;
+import static org.sonarqube.ws.WsUserGroups.SearchWsResponse;
 
 public class SearchAction implements UserGroupsWsAction {
 
-  private static final String FIELD_ID = "id";
   private static final String FIELD_NAME = "name";
   private static final String FIELD_DESCRIPTION = "description";
   private static final String FIELD_MEMBERS_COUNT = "membersCount";
@@ -71,7 +76,8 @@ public class SearchAction implements UserGroupsWsAction {
       .setSince("5.2")
       .addFieldsParam(ALL_FIELDS)
       .addPagingParams(100, MAX_LIMIT)
-      .addSearchQuery("sonar-users", "names");
+      .addSearchQuery("sonar-users", "names")
+      .setChangelog(new Change("6.4", "Paging response fields moved to a Paging object"));
 
     action.createParam(PARAM_ORGANIZATION_KEY)
       .setDescription("Key of organization. If not set then groups are searched in default organization.")
@@ -95,32 +101,12 @@ public class SearchAction implements UserGroupsWsAction {
       userSession.checkLoggedIn().checkPermission(ADMINISTER, organization);
 
       int limit = dbClient.groupDao().countByQuery(dbSession, organization.getUuid(), query);
+      Paging paging = forPageIndex(page).withPageSize(pageSize).andTotal(limit);
       List<GroupDto> groups = dbClient.groupDao().selectByQuery(dbSession, organization.getUuid(), query, options.getOffset(), pageSize);
       List<Integer> groupIds = groups.stream().map(GroupDto::getId).collect(MoreCollectors.toList(groups.size()));
       Map<String, Integer> userCountByGroup = dbClient.groupMembershipDao().countUsersByGroups(dbSession, groupIds);
-
-      JsonWriter json = response.newJsonWriter().beginObject();
-      options.writeJson(json, limit);
-      writeGroups(json, groups, userCountByGroup, fields);
-      json.endObject().close();
-    }
-  }
-
-  private static void writeGroups(JsonWriter json, List<GroupDto> groups, Map<String, Integer> userCountByGroup, Set<String> fields) {
-    json.name("groups").beginArray();
-    for (GroupDto group : groups) {
-      writeGroup(json, group, userCountByGroup.get(group.getName()), fields);
+      writeProtobuf(buildResponse(groups, userCountByGroup, fields, paging), request, response);
     }
-    json.endArray();
-  }
-
-  private static void writeGroup(JsonWriter json, GroupDto group, Integer memberCount, Set<String> fields) {
-    json.beginObject()
-      .prop(FIELD_ID, group.getId().toString())
-      .prop(FIELD_NAME, fields.contains(FIELD_NAME) ? group.getName() : null)
-      .prop(FIELD_DESCRIPTION, fields.contains(FIELD_DESCRIPTION) ? group.getDescription() : null)
-      .prop(FIELD_MEMBERS_COUNT, fields.contains(FIELD_MEMBERS_COUNT) ? memberCount : null)
-      .endObject();
   }
 
   private static Set<String> neededFields(Request request) {
@@ -133,4 +119,30 @@ public class SearchAction implements UserGroupsWsAction {
     }
     return fields;
   }
+
+  private static SearchWsResponse buildResponse(List<GroupDto> groups, Map<String, Integer> userCountByGroup, Set<String> fields, Paging paging) {
+    SearchWsResponse.Builder responseBuilder = SearchWsResponse.newBuilder();
+    groups.forEach(group -> responseBuilder.addGroups(toWsGroup(group, userCountByGroup.get(group.getName()), fields)));
+    responseBuilder.getPagingBuilder()
+      .setPageIndex(paging.pageIndex())
+      .setPageSize(paging.pageSize())
+      .setTotal(paging.total())
+      .build();
+    return responseBuilder.build();
+  }
+
+  private static Group toWsGroup(GroupDto group, Integer memberCount, Set<String> fields) {
+    Group.Builder groupBuilder = Group.newBuilder().setId(group.getId());
+    if (fields.contains(FIELD_NAME)) {
+      groupBuilder.setName(group.getName());
+    }
+    if (fields.contains(FIELD_DESCRIPTION)) {
+      setNullable(group.getDescription(), groupBuilder::setDescription);
+    }
+    if (fields.contains(FIELD_MEMBERS_COUNT)) {
+      groupBuilder.setMembersCount(memberCount);
+    }
+    return groupBuilder.build();
+  }
+
 }
index b5b5acf73bf5a23f84ca5b74153a2eb0f65387c3..169661b3f9fe7f53f6bdfb30f7566f013e426984 100644 (file)
  */
 package org.sonar.server.usergroups.ws;
 
+import com.google.common.base.Throwables;
+import java.io.IOException;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.sonar.api.server.ws.WebService.Param;
 import org.sonar.api.utils.System2;
 import org.sonar.db.DbTester;
 import org.sonar.db.organization.OrganizationDto;
@@ -33,12 +34,20 @@ import org.sonar.server.organization.TestDefaultOrganizationProvider;
 import org.sonar.server.tester.UserSessionRule;
 import org.sonar.server.ws.TestRequest;
 import org.sonar.server.ws.WsActionTester;
+import org.sonarqube.ws.Common.Paging;
+import org.sonarqube.ws.MediaTypes;
 
 import static org.apache.commons.lang.StringUtils.capitalize;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.tuple;
+import static org.sonar.api.server.ws.WebService.Param.FIELDS;
+import static org.sonar.api.server.ws.WebService.Param.PAGE;
+import static org.sonar.api.server.ws.WebService.Param.PAGE_SIZE;
+import static org.sonar.api.server.ws.WebService.Param.TEXT_QUERY;
 import static org.sonar.db.permission.OrganizationPermission.ADMINISTER;
 import static org.sonar.db.user.GroupTesting.newGroupDto;
-import static org.sonar.test.JsonAssert.assertJson;
+import static org.sonarqube.ws.WsUserGroups.Group;
+import static org.sonarqube.ws.WsUserGroups.SearchWsResponse;
 
 public class SearchActionTest {
 
@@ -57,14 +66,10 @@ public class SearchActionTest {
   public void search_empty() throws Exception {
     loginAsDefaultOrgAdmin();
 
-    String result = newRequest().execute().getInput();
+    SearchWsResponse response = call(ws.newRequest());
 
-    assertJson(result).isSimilarTo("{\n" +
-      "  \"p\": 1,\n" +
-      "  \"ps\": 100,\n" +
-      "  \"total\": 0,\n" +
-      "  \"groups\": []\n" +
-      "}");
+    assertThat(response.getGroupsList()).isEmpty();
+    assertThat(response.getPaging().getTotal()).isZero();
   }
 
   @Test
@@ -76,17 +81,14 @@ public class SearchActionTest {
     insertGroup(db.getDefaultOrganization(), "customer3", 0);
     loginAsDefaultOrgAdmin();
 
-    String result = newRequest().execute().getInput();
-
-    assertJson(result).isSimilarTo("{\n" +
-      "  \"groups\": [\n" +
-      "    {\"name\": \"admins\", \"description\": \"Admins\", \"membersCount\": 0},\n" +
-      "    {\"name\": \"customer1\", \"description\": \"Customer1\", \"membersCount\": 0},\n" +
-      "    {\"name\": \"customer2\", \"description\": \"Customer2\", \"membersCount\": 0},\n" +
-      "    {\"name\": \"customer3\", \"description\": \"Customer3\", \"membersCount\": 0},\n" +
-      "    {\"name\": \"users\", \"description\": \"Users\", \"membersCount\": 0}\n" +
-      "  ]\n" +
-      "}");
+    SearchWsResponse response = call(ws.newRequest());
+
+    assertThat(response.getGroupsList()).extracting(Group::getName, Group::getDescription, Group::getMembersCount).containsOnly(
+      tuple("admins", "Admins", 0),
+      tuple("customer1", "Customer1", 0),
+      tuple("customer2", "Customer2", 0),
+      tuple("customer3", "Customer3", 0),
+      tuple("users", "Users", 0));
   }
 
   @Test
@@ -98,17 +100,14 @@ public class SearchActionTest {
     insertGroup(db.getDefaultOrganization(), "customer3", 0);
     loginAsDefaultOrgAdmin();
 
-    String result = newRequest().execute().getInput();
-
-    assertJson(result).isSimilarTo("{\n" +
-      "  \"groups\": [\n" +
-      "    {\"name\": \"admins\", \"description\": \"Admins\", \"membersCount\": 1},\n" +
-      "    {\"name\": \"customer1\", \"description\": \"Customer1\", \"membersCount\": 0},\n" +
-      "    {\"name\": \"customer2\", \"description\": \"Customer2\", \"membersCount\": 4},\n" +
-      "    {\"name\": \"customer3\", \"description\": \"Customer3\", \"membersCount\": 0},\n" +
-      "    {\"name\": \"users\", \"description\": \"Users\", \"membersCount\": 5}\n" +
-      "  ]\n" +
-      "}\n");
+    SearchWsResponse response = call(ws.newRequest());
+
+    assertThat(response.getGroupsList()).extracting(Group::getName, Group::getDescription, Group::getMembersCount).containsOnly(
+      tuple("admins", "Admins", 1),
+      tuple("customer1", "Customer1", 0),
+      tuple("customer2", "Customer2", 4),
+      tuple("customer3", "Customer3", 0),
+      tuple("users", "Users", 5));
   }
 
   @Test
@@ -120,15 +119,12 @@ public class SearchActionTest {
     insertGroup(db.getDefaultOrganization(), "customer%_%/3", 0);
     loginAsDefaultOrgAdmin();
 
-    String result = newRequest().setParam(Param.TEXT_QUERY, "tomer%_%/").execute().getInput();
+    SearchWsResponse response = call(ws.newRequest().setParam(TEXT_QUERY, "tomer%_%/"));
 
-    assertJson(result).ignoreFields("id").isSimilarTo("{\n" +
-      "  \"groups\": [\n" +
-      "    {\"name\": \"customer%_%/1\", \"description\": \"Customer%_%/1\", \"membersCount\": 0},\n" +
-      "    {\"name\": \"customer%_%/2\", \"description\": \"Customer%_%/2\", \"membersCount\": 0},\n" +
-      "    {\"name\": \"customer%_%/3\", \"description\": \"Customer%_%/3\", \"membersCount\": 0}\n" +
-      "  ]\n" +
-      "}\n");
+    assertThat(response.getGroupsList()).extracting(Group::getName, Group::getDescription, Group::getMembersCount).containsOnly(
+      tuple("customer%_%/1", "Customer%_%/1", 0),
+      tuple("customer%_%/2", "Customer%_%/2", 0),
+      tuple("customer%_%/3", "Customer%_%/3", 0));
   }
 
   @Test
@@ -140,31 +136,22 @@ public class SearchActionTest {
     insertGroup(db.getDefaultOrganization(), "customer3", 0);
     loginAsDefaultOrgAdmin();
 
-    assertJson(newRequest().setParam(Param.PAGE_SIZE, "3").execute().getInput()).isSimilarTo("{\n" +
-      "  \"p\": 1,\n" +
-      "  \"ps\": 3,\n" +
-      "  \"total\": 5,\n" +
-      "  \"groups\": [\n" +
-      "    {\"name\": \"admins\", \"description\": \"Admins\", \"membersCount\": 0},\n" +
-      "    {\"name\": \"customer1\", \"description\": \"Customer1\", \"membersCount\": 0},\n" +
-      "    {\"name\": \"customer2\", \"description\": \"Customer2\", \"membersCount\": 0}\n" +
-      "  ]\n" +
-      "}\n");
-    assertJson(newRequest().setParam(Param.PAGE_SIZE, "3").setParam(Param.PAGE, "2").execute().getInput()).isSimilarTo("{\n" +
-      "  \"p\": 2,\n" +
-      "  \"ps\": 3,\n" +
-      "  \"total\": 5,\n" +
-      "  \"groups\": [\n" +
-      "    {\"name\": \"customer3\", \"description\": \"Customer3\", \"membersCount\": 0},\n" +
-      "    {\"name\": \"users\", \"description\": \"Users\", \"membersCount\": 0}\n" +
-      "  ]\n" +
-      "}\n");
-    assertJson(newRequest().setParam(Param.PAGE_SIZE, "3").setParam(Param.PAGE, "3").execute().getInput()).isSimilarTo("{\n" +
-      "  \"p\": 3,\n" +
-      "  \"ps\": 3,\n" +
-      "  \"total\": 5,\n" +
-      "  \"groups\": []\n" +
-      "}\n");
+    SearchWsResponse response = call(ws.newRequest().setParam(PAGE_SIZE, "3"));
+    assertThat(response.getPaging()).extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal).containsOnly(1, 3, 5);
+    assertThat(response.getGroupsList()).extracting(Group::getName, Group::getDescription, Group::getMembersCount).containsOnly(
+      tuple("admins", "Admins", 0),
+      tuple("customer1", "Customer1", 0),
+      tuple("customer2", "Customer2", 0));
+
+    response = call(ws.newRequest().setParam(PAGE_SIZE, "3").setParam(PAGE, "2"));
+    assertThat(response.getPaging()).extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal).containsOnly(2, 3, 5);
+    assertThat(response.getGroupsList()).extracting(Group::getName, Group::getDescription, Group::getMembersCount).containsOnly(
+      tuple("customer3", "Customer3", 0),
+      tuple("users", "Users", 0));
+
+    response = call(ws.newRequest().setParam(PAGE_SIZE, "3").setParam(PAGE, "3"));
+    assertThat(response.getPaging()).extracting(Paging::getPageIndex, Paging::getPageSize, Paging::getTotal).containsOnly(3, 3, 5);
+    assertThat(response.getGroupsList()).isEmpty();
   }
 
   @Test
@@ -172,35 +159,16 @@ public class SearchActionTest {
     insertGroup(db.getDefaultOrganization(), "sonar-users", 0);
     loginAsDefaultOrgAdmin();
 
-    assertThat(newRequest().execute().getInput())
-      .contains("id")
-      .contains("name")
-      .contains("description")
-      .contains("membersCount");
-
-    assertThat(newRequest().setParam(Param.FIELDS, "").execute().getInput())
-      .contains("id")
-      .contains("name")
-      .contains("description")
-      .contains("membersCount");
-
-    assertThat(newRequest().setParam(Param.FIELDS, "name").execute().getInput())
-      .contains("id")
-      .contains("name")
-      .doesNotContain("description")
-      .doesNotContain("membersCount");
-
-    assertThat(newRequest().setParam(Param.FIELDS, "description").execute().getInput())
-      .contains("id")
-      .doesNotContain("name")
-      .contains("description")
-      .doesNotContain("membersCount");
-
-    assertThat(newRequest().setParam(Param.FIELDS, "membersCount").execute().getInput())
-      .contains("id")
-      .doesNotContain("name")
-      .doesNotContain("description")
-      .contains("membersCount");
+    assertThat(call(ws.newRequest()).getGroupsList()).extracting(Group::hasId, Group::hasName, Group::hasDescription, Group::hasMembersCount)
+      .containsOnly(tuple(true, true, true, true));
+    assertThat(call(ws.newRequest().setParam(FIELDS, "")).getGroupsList()).extracting(Group::hasId, Group::hasName, Group::hasDescription, Group::hasMembersCount)
+      .containsOnly(tuple(true, true, true, true));
+    assertThat(call(ws.newRequest().setParam(FIELDS, "name")).getGroupsList()).extracting(Group::hasId, Group::hasName, Group::hasDescription, Group::hasMembersCount)
+      .containsOnly(tuple(true, true, false, false));
+    assertThat(call(ws.newRequest().setParam(FIELDS, "description")).getGroupsList()).extracting(Group::hasId, Group::hasName, Group::hasDescription, Group::hasMembersCount)
+      .containsOnly(tuple(true, false, true, false));
+    assertThat(call(ws.newRequest().setParam(FIELDS, "membersCount")).getGroupsList()).extracting(Group::hasId, Group::hasName, Group::hasDescription, Group::hasMembersCount)
+      .containsOnly(tuple(true, false, false, true));
   }
 
   @Test
@@ -212,9 +180,9 @@ public class SearchActionTest {
     loginAsDefaultOrgAdmin();
     userSession.addPermission(ADMINISTER, org);
 
-    String result = newRequest().setParam("organization", org.getKey()).execute().getInput();
+    SearchWsResponse response = call(ws.newRequest().setParam("organization", org.getKey()));
 
-    assertJson(result).isSimilarTo("{\"groups\":[{\"id\":\"" + group.getId() + "\",\"name\":\"users\"}]}\n");
+    assertThat(response.getGroupsList()).extracting(Group::getId, Group::getName).containsOnly(tuple(group.getId().longValue(), "users"));
   }
 
   @Test
@@ -222,11 +190,16 @@ public class SearchActionTest {
     userSession.anonymous();
 
     expectedException.expect(UnauthorizedException.class);
-    newRequest().execute();
+    call(ws.newRequest());
   }
 
-  private TestRequest newRequest() {
-    return ws.newRequest();
+  private SearchWsResponse call(TestRequest request) {
+    request.setMediaType(MediaTypes.PROTOBUF);
+    try {
+      return SearchWsResponse.parseFrom(request.execute().getInputStream());
+    } catch (IOException e) {
+      throw Throwables.propagate(e);
+    }
   }
 
   private void insertGroup(OrganizationDto org, String name, int numberOfMembers) {
index e21b53ec6af64cd89274d5ffc25508c630543963..8cfd82d3512d047826aed75a421d85a0cd294e41 100644 (file)
@@ -32,9 +32,9 @@ export default Backbone.Collection.extend({
   },
 
   parse(r) {
-    this.total = +r.total;
-    this.p = +r.p;
-    this.ps = +r.ps;
+    this.total = +r.paging.total;
+    this.p = +r.paging.pageIndex;
+    this.ps = +r.paging.pageSize;
     return r.groups;
   },
 
index cd57e802bc31431285d2ddc6e55fa7398d80a191..d9fc797f4840b4c3e416aa820542a9fbd5166674 100644 (file)
@@ -20,6 +20,8 @@ syntax = "proto2";
 
 package sonarqube.ws.usergroup;
 
+import "ws-commons.proto";
+
 option java_package = "org.sonarqube.ws";
 option java_outer_classname = "WsUserGroups";
 option optimize_for = SPEED;
@@ -36,7 +38,8 @@ message UpdateWsResponse {
 
 // WS api/user_groups/search
 message SearchWsResponse {
-  repeated Group groups = 1;
+  optional sonarqube.ws.commons.Paging paging = 1;
+  repeated Group groups = 2;
 }
 
 message Group {