aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-server
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2019-06-20 17:24:52 +0200
committersonartech <sonartech@sonarsource.com>2019-06-28 08:45:45 +0200
commit071dd097a358d5750b2cc4be0f4216df111eb2d6 (patch)
tree671b2ff8b1b6d7ce38b60cd09b3b0ea5009666d3 /server/sonar-server
parent0d76849de3972733bf0105eda59870cb16560dc5 (diff)
downloadsonarqube-071dd097a358d5750b2cc4be0f4216df111eb2d6.tar.gz
sonarqube-071dd097a358d5750b2cc4be0f4216df111eb2d6.zip
SONAR-12221 Add pagination to api/qualitygates/search
Diffstat (limited to 'server/sonar-server')
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java84
-rw-r--r--server/sonar-server/src/main/resources/org/sonar/server/qualitygate/ws/search-example.json10
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/qualitygate/ws/SearchActionTest.java86
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));
+ }
+
}