diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2019-06-20 17:24:52 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2019-06-28 08:45:45 +0200 |
commit | 071dd097a358d5750b2cc4be0f4216df111eb2d6 (patch) | |
tree | 671b2ff8b1b6d7ce38b60cd09b3b0ea5009666d3 /server/sonar-server | |
parent | 0d76849de3972733bf0105eda59870cb16560dc5 (diff) | |
download | sonarqube-071dd097a358d5750b2cc4be0f4216df111eb2d6.tar.gz sonarqube-071dd097a358d5750b2cc4be0f4216df111eb2d6.zip |
SONAR-12221 Add pagination to api/qualitygates/search
Diffstat (limited to 'server/sonar-server')
3 files changed, 98 insertions, 82 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java index fcf81e8142c..743b0e65370 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java @@ -22,6 +22,7 @@ package org.sonar.server.qualitygate.ws; import com.google.common.io.Resources; import java.util.Collection; import java.util.List; +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; @@ -31,13 +32,13 @@ 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.ProjectQgateAssociationDto; import org.sonar.db.qualitygate.ProjectQgateAssociationQuery; import org.sonar.db.qualitygate.QGateWithOrgDto; import org.sonar.server.user.UserSession; import org.sonarqube.ws.Qualitygates; +import static java.util.stream.Collectors.toList; import static org.sonar.api.server.ws.WebService.Param.SELECTED; import static org.sonar.api.utils.Paging.forPageIndex; import static org.sonar.db.qualitygate.ProjectQgateAssociationQuery.ANY; @@ -66,6 +67,10 @@ public class SearchAction implements QualityGatesWsAction { "Only authorized projects for current user will be returned.") .setSince("4.3") .setResponseExample(Resources.getResource(this.getClass(), "search-example.json")) + .setChangelog( + new Change("7.9", "New field 'paging' in response"), + new Change("7.9", "New field 'key' returning the project key in 'results' response"), + new Change("7.9", "Field 'more' is deprecated in the response")) .setHandler(this); action.createParam(PARAM_GATE_ID) @@ -97,45 +102,42 @@ public class SearchAction implements QualityGatesWsAction { OrganizationDto organization = wsSupport.getOrganization(dbSession, request); QGateWithOrgDto qualityGate = wsSupport.getByOrganizationAndId(dbSession, organization, request.mandatoryParamAsLong(PARAM_GATE_ID)); - Association associations = find(dbSession, - ProjectQgateAssociationQuery.builder() - .qualityGate(qualityGate) - .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()) { + + ProjectQgateAssociationQuery projectQgateAssociationQuery = ProjectQgateAssociationQuery.builder() + .qualityGate(qualityGate) + .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(); + List<ProjectQgateAssociationDto> projects = dbClient.projectQgateAssociationDao().selectProjects(dbSession, projectQgateAssociationQuery); + List<ProjectQgateAssociationDto> authorizedProjects = keepAuthorizedProjects(dbSession, projects); + Paging paging = forPageIndex(projectQgateAssociationQuery.pageIndex()) + .withPageSize(projectQgateAssociationQuery.pageSize()) + .andTotal(authorizedProjects.size()); + List<ProjectQgateAssociationDto> paginatedProjects = getPaginatedProjects(authorizedProjects, paging); + + Qualitygates.SearchResponse.Builder createResponse = Qualitygates.SearchResponse.newBuilder().setMore(paging.hasNextPage()); + createResponse.getPagingBuilder() + .setPageIndex(paging.pageIndex()) + .setPageSize(paging.pageSize()) + .setTotal(paging.total()) + .build(); + + for (ProjectQgateAssociationDto project : paginatedProjects) { createResponse.addResultsBuilder() - .setId(project.id()) - .setName(project.name()) - .setSelected(project.isMember()); + .setId(project.getId()) + .setName(project.getName()) + .setKey(project.getKey()) + .setSelected(project.getGateId() != null); } writeProtobuf(createResponse.build(), request, response); } } - private SearchAction.Association find(DbSession dbSession, ProjectQgateAssociationQuery query) { - List<ProjectQgateAssociationDto> projects = dbClient.projectQgateAssociationDao().selectProjects(dbSession, query); - List<ProjectQgateAssociationDto> authorizedProjects = keepAuthorizedProjects(dbSession, projects); - - Paging paging = forPageIndex(query.pageIndex()) - .withPageSize(query.pageSize()) - .andTotal(authorizedProjects.size()); - return new SearchAction.Association(toProjectAssociations(getPaginatedProjects(authorizedProjects, paging)), paging.hasNextPage()); - } - private static List<ProjectQgateAssociationDto> getPaginatedProjects(List<ProjectQgateAssociationDto> projects, Paging paging) { - return projects.stream().skip(paging.offset()).limit(paging.pageSize()).collect(MoreCollectors.toList()); - } - - private static List<ProjectQgateAssociation> toProjectAssociations(List<ProjectQgateAssociationDto> dtos) { - return dtos.stream().map(ProjectQgateAssociationDto::toQgateAssociation).collect(MoreCollectors.toList()); + return projects.stream().skip(paging.offset()).limit(paging.pageSize()).collect(toList()); } private List<ProjectQgateAssociationDto> keepAuthorizedProjects(DbSession dbSession, List<ProjectQgateAssociationDto> projects) { @@ -149,22 +151,4 @@ public class SearchAction implements QualityGatesWsAction { Collection<Long> authorizedProjectIds = dbClient.authorizationDao().keepAuthorizedProjectIds(dbSession, projectIds, userSession.getUserId(), UserRole.USER); return projects.stream().filter(project -> authorizedProjectIds.contains(project.getId())).collect(MoreCollectors.toList()); } - - private static class Association { - private List<ProjectQgateAssociation> projects; - private boolean hasMoreResults; - - private Association(List<ProjectQgateAssociation> projects, boolean hasMoreResults) { - this.projects = projects; - this.hasMoreResults = hasMoreResults; - } - - public List<ProjectQgateAssociation> projects() { - return projects; - } - - public boolean hasMoreResults() { - return hasMoreResults; - } - } } 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 index 7ad6eed5a24..97332a0480b 100644 --- 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 @@ -1,15 +1,21 @@ { - "more": true, + "paging": { + "pageIndex": 1, + "pageSize": 100, + "total": 2 + }, "results": [ { "id": 1, "name": "Simple Java project analyzed with the SonarQube Runner", + "key": "somple-java", "selected": true }, { "id": 4, "name": "My Project", - "selected": true + "key": "my-project", + "selected": false } ] } 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 index 84768e600b8..453ad38190d 100644 --- 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 @@ -70,25 +70,6 @@ public class SearchActionTest { 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); @@ -101,9 +82,8 @@ public class SearchActionTest { .executeProtobuf(SearchResponse.class); assertThat(response.getResultsList()) - .extracting(Result::getId, Result::getName) - .containsExactlyInAnyOrder(tuple(project.getId(), project.name())); - assertThat(response.getMore()).isFalse(); + .extracting(Result::getId, Result::getKey, Result::getName) + .containsExactlyInAnyOrder(tuple(project.getId(), project.getKey(), project.name())); } @Test @@ -120,7 +100,6 @@ public class SearchActionTest { assertThat(response.getResultsList()) .extracting(Result::getId, Result::getName) .containsExactlyInAnyOrder(tuple(project.getId(), project.name())); - assertThat(response.getMore()).isFalse(); } @Test @@ -151,10 +130,10 @@ public class SearchActionTest { .executeProtobuf(SearchResponse.class); assertThat(response.getResultsList()) - .extracting(Result::getName, Result::getSelected) + .extracting(Result::getName, Result::getKey, Result::getSelected) .containsExactlyInAnyOrder( - tuple(associatedProject.name(), true), - tuple(unassociatedProject.name(), false)); + tuple(associatedProject.name(), associatedProject.getKey(), true), + tuple(unassociatedProject.name(), unassociatedProject.getKey(), false)); } @Test @@ -309,25 +288,53 @@ public class SearchActionTest { } @Test - public void more_is_true_when_not_all_project_fit_in_page_size() { + public void test_pagination_on_many_pages() { OrganizationDto organization = db.organizations().insert(); QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization); for (int i = 0; i < 20; i++) { ComponentDto project = db.components().insertPublicProject(organization); db.qualityGates().associateProjectToQualityGate(project, qualityGate); } + userSession.addPermission(ADMINISTER_QUALITY_GATES, organization); + + SearchResponse response = ws.newRequest() + .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) + .setParam(PARAM_ORGANIZATION, organization.getKey()) + .setParam(PARAM_PAGE_SIZE, valueOf(5)) + .setParam(PARAM_PAGE, valueOf(2)) + .executeProtobuf(SearchResponse.class); + assertThat(response) + .extracting(SearchResponse::getMore, + searchResponse -> searchResponse.getPaging().getPageIndex(), + searchResponse -> searchResponse.getPaging().getPageSize(), + searchResponse -> searchResponse.getPaging().getTotal()) + .contains(true, 2, 5, 20); + } + + @Test + public void test_pagination_on_one_page() { + OrganizationDto organization = db.organizations().insert(); + QualityGateDto qualityGate = db.qualityGates().insertQualityGate(organization); + for (int i = 0; i < 20; i++) { + ComponentDto project = db.components().insertPublicProject(organization); + db.qualityGates().associateProjectToQualityGate(project, qualityGate); + } userSession.addPermission(ADMINISTER_QUALITY_GATES, organization); SearchResponse response = ws.newRequest() .setParam(PARAM_GATE_ID, valueOf(qualityGate.getId())) .setParam(PARAM_ORGANIZATION, organization.getKey()) - .setParam(PARAM_PAGE_SIZE, valueOf(10)) + .setParam(PARAM_PAGE_SIZE, valueOf(100)) .setParam(PARAM_PAGE, valueOf(1)) .executeProtobuf(SearchResponse.class); - assertThat(response.getMore()).isTrue(); - assertThat(response.getResultsCount()).isEqualTo(10); + assertThat(response) + .extracting(SearchResponse::getMore, + searchResponse -> searchResponse.getPaging().getPageIndex(), + searchResponse -> searchResponse.getPaging().getPageSize(), + searchResponse -> searchResponse.getPaging().getTotal()) + .contains(false, 1, 100, 20); } @Test @@ -380,4 +387,23 @@ public class SearchActionTest { .executeProtobuf(SearchResponse.class); } + @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)); + } + } |