From a6983005bce736e7fe20b4a41b5d69e15fdbfb2e Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Tue, 20 Feb 2018 13:49:17 +0100 Subject: [PATCH] SONAR-10356 clean message when bulk deleting more than 1000 projects --- .../server/project/ws/BulkDeleteAction.java | 22 ++++++++-- .../project/ws/BulkDeleteActionTest.java | 41 ++++++++++++++----- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java index ec129767b14..785a69f8c62 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java @@ -19,6 +19,10 @@ */ package org.sonar.server.project.ws; +import java.util.List; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +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; @@ -33,6 +37,7 @@ import org.sonar.server.project.Visibility; import org.sonar.server.user.UserSession; import org.sonarqube.ws.client.project.SearchWsRequest; +import static java.lang.Math.min; import static org.sonar.api.resources.Qualifiers.APP; import static org.sonar.api.resources.Qualifiers.PROJECT; import static org.sonar.api.resources.Qualifiers.VIEW; @@ -74,7 +79,8 @@ public class BulkDeleteAction implements ProjectsWsAction { .setDescription("Delete one or several projects.
" + "Requires 'Administer System' permission.") .setSince("5.2") - .setHandler(this); + .setHandler(this) + .setChangelog(new Change("6.7.2", "Only the 1'000 first items in project filters are taken into account")); support.addOrganizationParam(action); @@ -86,7 +92,7 @@ public class BulkDeleteAction implements ProjectsWsAction { action .createParam(PARAM_PROJECT_IDS) - .setDescription("Comma-separated list of project ids") + .setDescription("Comma-separated list of project ids. Only the 1'000 first ids are used. Others are silently ignored.") .setDeprecatedKey("ids", "6.4") .setDeprecatedSince("6.4") .setExampleValue(String.join(",", UUID_EXAMPLE_01, UUID_EXAMPLE_02)); @@ -148,8 +154,16 @@ public class BulkDeleteAction implements ProjectsWsAction { .setVisibility(request.param(PARAM_VISIBILITY)) .setAnalyzedBefore(request.param(PARAM_ANALYZED_BEFORE)) .setOnProvisionedOnly(request.mandatoryParamAsBoolean(PARAM_ON_PROVISIONED_ONLY)) - .setProjects(request.paramAsStrings(PARAM_PROJECTS)) - .setProjectIds(request.paramAsStrings(PARAM_PROJECT_IDS)) + .setProjects(restrictTo1000Values(request.paramAsStrings(PARAM_PROJECTS))) + .setProjectIds(restrictTo1000Values(request.paramAsStrings(PARAM_PROJECT_IDS))) .build(); } + + @CheckForNull + private static List restrictTo1000Values(@Nullable List values) { + if (values == null) { + return null; + } + return values.subList(0, min(values.size(), 1_000)); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java index 79f3806677d..7f14b392fde 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java @@ -19,10 +19,11 @@ */ package org.sonar.server.project.ws; -import java.io.IOException; import java.net.HttpURLConnection; import java.util.Date; +import java.util.List; import java.util.stream.IntStream; +import org.apache.commons.lang.StringUtils; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -31,6 +32,7 @@ import org.mockito.ArgumentCaptor; import org.sonar.api.resources.Qualifiers; import org.sonar.api.server.ws.WebService.Param; import org.sonar.api.utils.System2; +import org.sonar.core.util.stream.MoreCollectors; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; @@ -86,7 +88,7 @@ public class BulkDeleteActionTest { } @Test - public void delete_projects_in_default_organization_if_no_org_provided() throws Exception { + public void delete_projects_in_default_organization_if_no_org_provided() { userSession.logIn().setRoot(); OrganizationDto defaultOrganization = db.getDefaultOrganization(); ComponentDto toDeleteInOrg1 = db.components().insertPrivateProject(org1); @@ -103,7 +105,7 @@ public class BulkDeleteActionTest { } @Test - public void delete_projects_by_keys() throws Exception { + public void delete_projects_by_keys() { userSession.logIn().setRoot(); ComponentDto toDeleteInOrg1 = db.components().insertPrivateProject(org1); ComponentDto toDeleteInOrg2 = db.components().insertPrivateProject(org1); @@ -118,7 +120,7 @@ public class BulkDeleteActionTest { } @Test - public void projects_that_dont_exist_are_ignored_and_dont_break_bulk_deletion() throws Exception { + public void projects_that_dont_exist_are_ignored_and_dont_break_bulk_deletion() { userSession.logIn().setRoot(); ComponentDto toDelete1 = db.components().insertPrivateProject(org1); ComponentDto toDelete2 = db.components().insertPrivateProject(org1); @@ -172,7 +174,7 @@ public class BulkDeleteActionTest { } @Test - public void projects_and_views() throws IOException { + public void projects_and_views() { userSession.logIn().addPermission(ADMINISTER, db.getDefaultOrganization()); ComponentDto project = db.components().insertPrivateProject(); ComponentDto view = db.components().insertView(); @@ -183,7 +185,7 @@ public class BulkDeleteActionTest { } @Test - public void delete_by_key_query_with_partial_match_case_insensitive() throws IOException { + public void delete_by_key_query_with_partial_match_case_insensitive() { userSession.logIn().addPermission(ADMINISTER, db.getDefaultOrganization()); ComponentDto matchKeyProject = db.components().insertPrivateProject(p -> p.setDbKey("project-_%-key")); ComponentDto matchUppercaseKeyProject = db.components().insertPrivateProject(p -> p.setDbKey("PROJECT-_%-KEY")); @@ -195,7 +197,7 @@ public class BulkDeleteActionTest { } @Test - public void throw_ForbiddenException_if_organization_administrator_does_not_set_organization_parameter() throws Exception { + public void throw_ForbiddenException_if_organization_administrator_does_not_set_organization_parameter() { userSession.logIn().addPermission(ADMINISTER, org1); ComponentDto project = db.components().insertPrivateProject(org1); @@ -209,8 +211,25 @@ public class BulkDeleteActionTest { verifyNoDeletions(); } + /** + * SONAR-10356 + */ @Test - public void organization_administrator_deletes_projects_by_keys_in_his_organization() throws Exception { + public void delete_only_the_1000_first_projects() { + userSession.logIn().addPermission(ADMINISTER, org1); + List keys = IntStream.range(0, 1_010).mapToObj(i -> "key" + i).collect(MoreCollectors.toArrayList()); + keys.forEach(key -> db.components().insertPrivateProject(org1, p -> p.setDbKey(key))); + + ws.newRequest() + .setParam("organization", org1.getKey()) + .setParam("projects", StringUtils.join(keys, ",")) + .execute(); + + verify(componentCleanerService, times(1_000)).delete(any(DbSession.class), any(ComponentDto.class)); + } + + @Test + public void organization_administrator_deletes_projects_by_keys_in_his_organization() { userSession.logIn().addPermission(ADMINISTER, org1); ComponentDto toDelete = db.components().insertPrivateProject(org1); ComponentDto cantBeDeleted = db.components().insertPrivateProject(org2); @@ -224,7 +243,7 @@ public class BulkDeleteActionTest { } @Test - public void throw_UnauthorizedException_if_not_logged_in() throws Exception { + public void throw_UnauthorizedException_if_not_logged_in() { expectedException.expect(UnauthorizedException.class); expectedException.expectMessage("Authentication is required"); @@ -235,7 +254,7 @@ public class BulkDeleteActionTest { } @Test - public void throw_ForbiddenException_if_param_organization_is_not_set_and_not_system_administrator() throws Exception { + public void throw_ForbiddenException_if_param_organization_is_not_set_and_not_system_administrator() { userSession.logIn().setNonSystemAdministrator(); expectedException.expect(ForbiddenException.class); @@ -248,7 +267,7 @@ public class BulkDeleteActionTest { } @Test - public void throw_ForbiddenException_if_param_organization_is_set_but_not_organization_administrator() throws Exception { + public void throw_ForbiddenException_if_param_organization_is_set_but_not_organization_administrator() { userSession.logIn(); expectedException.expect(ForbiddenException.class); -- 2.39.5