aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Brandhof <simon.brandhof@sonarsource.com>2018-02-20 13:49:56 +0100
committerSimon Brandhof <simon.brandhof@sonarsource.com>2018-02-22 09:23:27 +0100
commita0ab2f7b6381bf1325b209a23c5032320f04a512 (patch)
treedd3f26188508f83cf66a7d73de717c7fff5b3559
parenta6983005bce736e7fe20b4a41b5d69e15fdbfb2e (diff)
downloadsonarqube-a0ab2f7b6381bf1325b209a23c5032320f04a512.tar.gz
sonarqube-a0ab2f7b6381bf1325b209a23c5032320f04a512.zip
SONAR-10356 clean message when searching for more than 1000 projects
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java12
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java47
2 files changed, 44 insertions, 15 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java
index 03a235e2c61..e248082b8aa 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/project/ws/SearchAction.java
@@ -30,6 +30,7 @@ import org.sonar.api.server.ws.WebService;
import org.sonar.api.server.ws.WebService.Param;
import org.sonar.api.utils.Paging;
import org.sonar.core.util.stream.MoreCollectors;
+import org.sonar.db.DatabaseUtils;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.component.ComponentDto;
@@ -43,6 +44,7 @@ import org.sonarqube.ws.WsProjects.SearchWsResponse;
import org.sonarqube.ws.client.project.SearchWsRequest;
import static com.google.common.base.Preconditions.checkArgument;
+import static java.lang.String.format;
import static org.sonar.api.resources.Qualifiers.APP;
import static org.sonar.api.resources.Qualifiers.PROJECT;
import static org.sonar.api.resources.Qualifiers.VIEW;
@@ -90,7 +92,9 @@ public class SearchAction implements ProjectsWsAction {
.setResponseExample(getClass().getResource("search-example.json"))
.setHandler(this);
- action.setChangelog(new Change("6.4", "The 'uuid' field is deprecated in the response"));
+ action.setChangelog(
+ new Change("6.4", "The 'uuid' field is deprecated in the response"),
+ new Change("6.7.2", format("Parameters %s and %s accept maximum %d values", PARAM_PROJECTS, PARAM_PROJECT_IDS, DatabaseUtils.PARTITION_SIZE_FOR_ORACLE)));
action.createParam(Param.TEXT_QUERY)
.setDescription("Limit search to: <ul>" +
@@ -130,6 +134,9 @@ public class SearchAction implements ProjectsWsAction {
.createParam(PARAM_PROJECTS)
.setDescription("Comma-separated list of project keys")
.setSince("6.6")
+ // Limitation of ComponentDao#selectByQuery(), max 1000 values are accepted.
+ // Restricting size of HTTP parameter allows to not fail with SQL error
+ .setMaxValuesAllowed(DatabaseUtils.PARTITION_SIZE_FOR_ORACLE)
.setExampleValue(String.join(",", KEY_PROJECT_EXAMPLE_001, KEY_PROJECT_EXAMPLE_002));
action
@@ -138,6 +145,9 @@ public class SearchAction implements ProjectsWsAction {
.setSince("6.6")
// parameter added to match api/projects/bulk_delete parameters
.setDeprecatedSince("6.6")
+ // Limitation of ComponentDao#selectByQuery(), max 1000 values are accepted.
+ // Restricting size of HTTP parameter allows to not fail with SQL error
+ .setMaxValuesAllowed(DatabaseUtils.PARTITION_SIZE_FOR_ORACLE)
.setExampleValue(String.join(",", UUID_EXAMPLE_01, UUID_EXAMPLE_02));
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java
index 9f122fe9feb..f301ae1b772 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java
@@ -20,10 +20,9 @@
package org.sonar.server.project.ws;
import com.google.common.base.Joiner;
-import java.io.IOException;
-import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.assertj.core.api.Assertions;
@@ -97,7 +96,7 @@ public class SearchActionTest {
new SearchAction(db.getDbClient(), userSession, new ProjectsWsSupport(db.getDbClient(), defaultOrganizationProvider, mock(BillingValidationsProxy.class))));
@Test
- public void search_by_key_query_with_partial_match_case_insensitive() throws IOException {
+ public void search_by_key_query_with_partial_match_case_insensitive() {
userSession.addPermission(ADMINISTER, db.getDefaultOrganization());
db.components().insertComponents(
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey("project-_%-key"),
@@ -134,7 +133,7 @@ public class SearchActionTest {
}
@Test
- public void search_projects_when_no_qualifier_set() throws IOException {
+ public void search_projects_when_no_qualifier_set() {
userSession.addPermission(ADMINISTER, db.getDefaultOrganization());
db.components().insertComponents(
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey(PROJECT_KEY_1),
@@ -146,7 +145,7 @@ public class SearchActionTest {
}
@Test
- public void search_projects() throws IOException {
+ public void search_projects() {
userSession.addPermission(ADMINISTER, db.getDefaultOrganization());
ComponentDto project = ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey(PROJECT_KEY_1);
ComponentDto module = newModuleDto(project);
@@ -163,7 +162,7 @@ public class SearchActionTest {
}
@Test
- public void search_views() throws IOException {
+ public void search_views() {
userSession.addPermission(ADMINISTER, db.getDefaultOrganization());
db.components().insertComponents(
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey(PROJECT_KEY_1),
@@ -175,7 +174,7 @@ public class SearchActionTest {
}
@Test
- public void search_projects_and_views() throws IOException {
+ public void search_projects_and_views() {
userSession.addPermission(ADMINISTER, db.getDefaultOrganization());
db.components().insertComponents(
ComponentTesting.newPrivateProjectDto(db.getDefaultOrganization()).setDbKey(PROJECT_KEY_1),
@@ -187,7 +186,7 @@ public class SearchActionTest {
}
@Test
- public void search_on_default_organization_when_no_organization_set() throws IOException {
+ public void search_on_default_organization_when_no_organization_set() {
userSession.addPermission(ADMINISTER, db.getDefaultOrganization());
OrganizationDto otherOrganization = db.organizations().insert();
db.components().insertComponents(
@@ -201,7 +200,7 @@ public class SearchActionTest {
}
@Test
- public void search_for_projects_on_given_organization() throws IOException {
+ public void search_for_projects_on_given_organization() {
OrganizationDto organization1 = db.organizations().insert();
OrganizationDto organization2 = db.organizations().insert();
userSession.addPermission(ADMINISTER, organization1);
@@ -245,7 +244,7 @@ public class SearchActionTest {
}
@Test
- public void result_is_paginated() throws IOException {
+ public void result_is_paginated() {
userSession.addPermission(ADMINISTER, db.getDefaultOrganization());
List<ComponentDto> componentDtoList = new ArrayList<>();
for (int i = 1; i <= 9; i++) {
@@ -305,7 +304,27 @@ public class SearchActionTest {
}
@Test
- public void fail_when_not_system_admin() throws Exception {
+ public void request_throws_IAE_if_more_than_1000_projects() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("'projects' can contains only 1000 values, got 1001");
+
+ call(SearchWsRequest.builder()
+ .setProjects(Collections.nCopies(1_001, "foo"))
+ .build());
+ }
+
+ @Test
+ public void request_throws_IAE_if_more_than_1000_project_ids() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("'projectIds' can contains only 1000 values, got 1001");
+
+ call(SearchWsRequest.builder()
+ .setProjectIds(Collections.nCopies(1_001, "foo"))
+ .build());
+ }
+
+ @Test
+ public void fail_when_not_system_admin() {
userSession.addPermission(ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization());
expectedException.expect(ForbiddenException.class);
@@ -313,14 +332,14 @@ public class SearchActionTest {
}
@Test
- public void fail_on_unknown_organization() throws Exception {
+ public void fail_on_unknown_organization() {
expectedException.expect(NotFoundException.class);
call(SearchWsRequest.builder().setOrganization("unknown").build());
}
@Test
- public void fail_on_invalid_qualifier() throws Exception {
+ public void fail_on_invalid_qualifier() {
userSession.addPermission(ADMINISTER_QUALITY_PROFILES, db.getDefaultOrganization());
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Value of parameter 'qualifiers' (BRC) must be one of: [TRK, VW, APP]");
@@ -387,7 +406,7 @@ public class SearchActionTest {
}
@Test
- public void json_example() throws URISyntaxException, IOException {
+ public void json_example() {
OrganizationDto organization = db.organizations().insertForKey("my-org-1");
userSession.addPermission(ADMINISTER, organization);
ComponentDto publicProject = newPrivateProjectDto(organization, "project-uuid-1").setName("Project Name 1").setDbKey("project-key-1").setPrivate(false);