diff options
author | Simon Brandhof <simon.brandhof@sonarsource.com> | 2018-02-20 13:49:56 +0100 |
---|---|---|
committer | Simon Brandhof <simon.brandhof@sonarsource.com> | 2018-02-22 09:23:27 +0100 |
commit | a0ab2f7b6381bf1325b209a23c5032320f04a512 (patch) | |
tree | dd3f26188508f83cf66a7d73de717c7fff5b3559 | |
parent | a6983005bce736e7fe20b4a41b5d69e15fdbfb2e (diff) | |
download | sonarqube-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.java | 12 | ||||
-rw-r--r-- | server/sonar-server/src/test/java/org/sonar/server/project/ws/SearchActionTest.java | 47 |
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); |