diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2017-05-30 17:40:00 +0200 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2017-06-01 15:19:45 +0200 |
commit | 530977c23387e88f99533f9202c5cf670f26893a (patch) | |
tree | 0e63cb4fee8146c32dc6c0acc53b0d94641d0511 /server | |
parent | a9cd8d9ab2ed78c580af5283f36d581648168a09 (diff) | |
download | sonarqube-530977c23387e88f99533f9202c5cf670f26893a.tar.gz sonarqube-530977c23387e88f99533f9202c5cf670f26893a.zip |
SONAR-9328 delete settings & manual measures by project/module
and by views/subviews
Diffstat (limited to 'server')
6 files changed, 248 insertions, 27 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java index d3ed34b2cdc..1c673d97846 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java @@ -163,26 +163,24 @@ class PurgeCommands { profiler.stop(); } - void deleteComponents(List<IdUuidPair> componentIdUuids) { - List<List<Long>> componentIdPartitions = Lists.partition(IdUuidPairs.ids(componentIdUuids), MAX_RESOURCES_PER_QUERY); - List<List<String>> componentUuidsPartitions = Lists.partition(IdUuidPairs.uuids(componentIdUuids), MAX_RESOURCES_PER_QUERY); - // Note : do not merge the delete statements into a single loop of resource ids. It's - // voluntarily grouped by tables in order to benefit from JDBC batch mode. - // Batch requests can only relate to the same PreparedStatement. - - // possible missing optimization: filter requests according to resource scope + void deleteByRootAndModulesOrSubviews(List<IdUuidPair> rootAndModulesOrSubviewsIds) { + List<List<Long>> idPartitions = Lists.partition(IdUuidPairs.ids(rootAndModulesOrSubviewsIds), MAX_RESOURCES_PER_QUERY); + List<List<String>> uuidsPartitions = Lists.partition(IdUuidPairs.uuids(rootAndModulesOrSubviewsIds), MAX_RESOURCES_PER_QUERY); - profiler.start("deleteResourceProperties (properties)"); - componentIdPartitions.forEach(purgeMapper::deleteComponentProperties); + profiler.start("deleteByRootAndModulesOrSubviews (properties)"); + idPartitions.forEach(purgeMapper::deleteComponentProperties); session.commit(); profiler.stop(); - profiler.start("deleteResourceManualMeasures (manual_measures)"); - componentUuidsPartitions.forEach(purgeMapper::deleteComponentManualMeasures); + profiler.start("deleteByRootAndModulesOrSubviews (manual_measures)"); + uuidsPartitions.forEach(purgeMapper::deleteComponentManualMeasures); session.commit(); profiler.stop(); + } - profiler.start("deleteResource (projects)"); + void deleteComponents(List<IdUuidPair> componentIdUuids) { + List<List<String>> componentUuidsPartitions = Lists.partition(IdUuidPairs.uuids(componentIdUuids), MAX_RESOURCES_PER_QUERY); + profiler.start("deleteComponents (projects)"); componentUuidsPartitions.forEach(purgeMapper::deleteComponents); session.commit(); profiler.stop(); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java index c7ee2fc5e9e..fdeafba33c2 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java @@ -153,16 +153,18 @@ public class PurgeDao implements Dao { } private static void deleteProject(String rootUuid, PurgeMapper mapper, PurgeCommands commands) { - List<IdUuidPair> childrenIds = mapper.selectComponentsByProjectUuid(rootUuid); - long rootId = childrenIds.stream() + List<IdUuidPair> componentsIds = mapper.selectComponentsByProjectUuid(rootUuid); + List<IdUuidPair> rootAndModulesOrSubviews = mapper.selectRootAndModulesOrSubviewsByProjectUuid(rootUuid); + long rootId = rootAndModulesOrSubviews.stream() .filter(pair -> pair.getUuid().equals(rootUuid)) .map(IdUuidPair::getId) .findFirst() - .orElseThrow(() -> new IllegalStateException("Couldn't find component for root uuid " + rootUuid)); + .orElseThrow(() -> new IllegalArgumentException("Couldn't find root component with uuid " + rootUuid)); commands.deletePermissions(rootId); commands.deleteLinks(rootUuid); commands.deleteAnalyses(rootUuid); - commands.deleteComponents(childrenIds); + commands.deleteByRootAndModulesOrSubviews(rootAndModulesOrSubviews); + commands.deleteComponents(componentsIds); commands.deleteIssues(rootUuid); commands.deleteFileSources(rootUuid); commands.deleteCeActivity(rootUuid); diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java index 71f4d1afc67..e8e65b82cea 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java @@ -32,6 +32,11 @@ public interface PurgeMapper { */ List<IdUuidPair> selectComponentsByProjectUuid(String projectUuid); + /** + * Returns the list of modules/subviews and the view/project for the specified project_uuid. + */ + List<IdUuidPair> selectRootAndModulesOrSubviewsByProjectUuid(@Param("rootUuid") String rootUuid); + void deleteAnalyses(@Param("analysisUuids") List<String> analysisUuids); void deleteAnalysisDuplications(@Param("analysisUuids") List<String> analysisUuids); diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml index a2d461853e0..c1926a98446 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml @@ -55,6 +55,22 @@ select id, uuid from projects where project_uuid=#{uuid,jdbcType=VARCHAR} or uuid=#{uuid,jdbcType=VARCHAR} </select> + <select id="selectRootAndModulesOrSubviewsByProjectUuid" resultType="org.sonar.db.purge.IdUuidPair" parameterType="String"> + select + p.id, p.uuid + from + projects p + where + ( + p.project_uuid=#{rootUuid,jdbcType=VARCHAR} + and p.scope = 'PRJ' and p.qualifier in ('SVW','BRC') + ) + or ( + uuid=#{rootUuid,jdbcType=VARCHAR} + and p.scope = 'PRJ' and p.qualifier in ('VW','TRK') + ) + </select> + <delete id="deleteAnalysisMeasures" parameterType="map"> delete from project_measures where diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java index 02ff99161e2..4f6052a2ed6 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java @@ -27,6 +27,7 @@ import java.util.List; import org.apache.commons.lang.math.RandomUtils; import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.mockito.ArgumentCaptor; import org.sonar.api.resources.Scopes; import org.sonar.api.utils.System2; @@ -57,6 +58,8 @@ public class PurgeDaoTest { @Rule public DbTester dbTester = DbTester.create(system2); + @Rule + public ExpectedException expectedException = ExpectedException.none(); private DbClient dbClient = dbTester.getDbClient(); private DbSession dbSession = dbTester.getSession(); @@ -186,18 +189,52 @@ public class PurgeDaoTest { } @Test - public void delete_view_sub_view_and_tech_project() { - dbTester.prepareDbUnit(getClass(), "view_sub_view_and_tech_project.xml"); + public void deleteProject_fails_with_IAE_if_specified_component_is_module() { + ComponentDto privateProject = dbTester.components().insertPrivateProject(); + ComponentDto module = dbTester.components().insertComponent(ComponentTesting.newModuleDto(privateProject)); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Couldn't find root component with uuid " + module.uuid()); + + underTest.deleteProject(dbSession, module.uuid()); + } - // technical project - underTest.deleteProject(dbSession, "D"); - dbSession.commit(); - assertThat(dbTester.countSql("select count(1) from projects where uuid='D'")).isZero(); + @Test + public void deleteProject_fails_with_IAE_if_specified_component_is_directory() { + ComponentDto privateProject = dbTester.components().insertPrivateProject(); + ComponentDto directory = dbTester.components().insertComponent(ComponentTesting.newDirectory(privateProject, "A/B")); - // sub view - underTest.deleteProject(dbSession, "B"); - dbSession.commit(); - assertThat(dbTester.countSql("select count(1) from projects where uuid='B'")).isZero(); + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Couldn't find root component with uuid " + directory.uuid()); + + underTest.deleteProject(dbSession, directory.uuid()); + } + + @Test + public void deleteProject_fails_with_IAE_if_specified_component_is_file() { + ComponentDto privateProject = dbTester.components().insertPrivateProject(); + ComponentDto file = dbTester.components().insertComponent(ComponentTesting.newFileDto(privateProject)); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Couldn't find root component with uuid " + file.uuid()); + + underTest.deleteProject(dbSession, file.uuid()); + } + + @Test + public void deleteProject_fails_with_IAE_if_specified_component_is_subview() { + ComponentDto view = dbTester.components().insertView(); + ComponentDto subview = dbTester.components().insertComponent(ComponentTesting.newSubView(view)); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectMessage("Couldn't find root component with uuid " + subview.uuid()); + + underTest.deleteProject(dbSession, subview.uuid()); + } + + @Test + public void delete_view_sub_view_and_tech_project() { + dbTester.prepareDbUnit(getClass(), "view_sub_view_and_tech_project.xml"); // view underTest.deleteProject(dbSession, "A"); diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeMapperTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeMapperTest.java new file mode 100644 index 00000000000..f9da4da6e68 --- /dev/null +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeMapperTest.java @@ -0,0 +1,163 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.purge; + +import java.util.Random; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.utils.System2; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; +import org.sonar.db.component.ComponentDto; +import org.sonar.db.component.ComponentTesting; + +import static org.assertj.core.api.Assertions.assertThat; + +public class PurgeMapperTest { + + @Rule + public DbTester db = DbTester.create(System2.INSTANCE); + + private DbSession dbSession; + private PurgeMapper purgeMapper; + + @Before + public void setUp() throws Exception { + dbSession = db.getDbClient().openSession(false); + purgeMapper = dbSession.getMapper(PurgeMapper.class); + } + + @After + public void tearDown() throws Exception { + if (dbSession != null) { + dbSession.close(); + } + } + + @Test + public void selectRootAndModulesOrSubviewsByProjectUuid_returns_empty_when_table_is_empty() { + assertThat(purgeMapper.selectRootAndModulesOrSubviewsByProjectUuid("foo")).isEmpty(); + } + + @Test + public void selectRootAndModulesOrSubviewsByProjectUuid_returns_project_with_specified_uuid() { + ComponentDto project = randomPublicOrPrivateProject(); + + assertThat(purgeMapper.selectRootAndModulesOrSubviewsByProjectUuid(project.uuid())) + .extracting(IdUuidPair::getUuid) + .containsOnly(project.uuid()); + } + + @Test + public void selectRootAndModulesOrSubviewsByProjectUuid_returns_modules_with_specified_project_uuid_and_project() { + ComponentDto project = randomPublicOrPrivateProject(); + ComponentDto module1 = db.components().insertComponent(ComponentTesting.newModuleDto(project)); + ComponentDto module2 = db.components().insertComponent(ComponentTesting.newModuleDto(project)); + ComponentDto module3 = db.components().insertComponent(ComponentTesting.newModuleDto(project)); + + assertThat(purgeMapper.selectRootAndModulesOrSubviewsByProjectUuid(project.uuid())) + .extracting(IdUuidPair::getUuid) + .containsOnly(project.uuid(), module1.uuid(), module2.uuid(), module3.uuid()); + } + + private ComponentDto randomPublicOrPrivateProject() { + return new Random().nextBoolean() ? db.components().insertPrivateProject() : db.components().insertPublicProject(); + } + + @Test + public void selectRootAndModulesOrSubviewsByProjectUuid_returns_view_with_specified_uuid() { + ComponentDto view = db.components().insertView(); + + assertThat(purgeMapper.selectRootAndModulesOrSubviewsByProjectUuid(view.uuid())) + .extracting(IdUuidPair::getUuid) + .containsOnly(view.uuid()); + } + + @Test + public void selectRootAndModulesOrSubviewsByProjectUuid_returns_subviews_with_specified_project_uuid_and_view() { + ComponentDto view = db.components().insertView(); + ComponentDto subview1 = db.components().insertComponent(ComponentTesting.newSubView(view)); + ComponentDto subview2 = db.components().insertComponent(ComponentTesting.newSubView(view)); + ComponentDto subview3 = db.components().insertComponent(ComponentTesting.newSubView(view)); + + assertThat(purgeMapper.selectRootAndModulesOrSubviewsByProjectUuid(view.uuid())) + .extracting(IdUuidPair::getUuid) + .containsOnly(view.uuid(), subview1.uuid(), subview2.uuid(), subview3.uuid()); + } + + @Test + public void selectRootAndModulesOrSubviewsByProjectUuid_does_not_return_project_copy_with_specified_project_uuid() { + ComponentDto privateProject = db.components().insertPrivateProject(); + ComponentDto view = db.components().insertView(); + db.components().insertComponent(ComponentTesting.newProjectCopy("a", view, privateProject)); + + assertThat(purgeMapper.selectRootAndModulesOrSubviewsByProjectUuid(view.uuid())) + .extracting(IdUuidPair::getUuid) + .containsOnly(view.uuid()); + } + + @Test + public void selectRootAndModulesOrSubviewsByProjectUuid_does_not_return_module_with_specified_uuid() { + ComponentDto privateProject = db.components().insertPrivateProject(); + ComponentDto module = db.components().insertComponent(ComponentTesting.newModuleDto(privateProject)); + + assertThat(purgeMapper.selectRootAndModulesOrSubviewsByProjectUuid(module.uuid())) + .isEmpty(); + } + + @Test + public void selectRootAndModulesOrSubviewsByProjectUuid_does_not_return_directory_with_specified_uuid() { + ComponentDto privateProject = db.components().insertPrivateProject(); + ComponentDto directory = db.components().insertComponent(ComponentTesting.newDirectory(privateProject, "A/B")); + + assertThat(purgeMapper.selectRootAndModulesOrSubviewsByProjectUuid(directory.uuid())) + .isEmpty(); + } + + @Test + public void selectRootAndModulesOrSubviewsByProjectUuid_does_not_return_file_with_specified_uuid() { + ComponentDto privateProject = db.components().insertPrivateProject(); + ComponentDto file = db.components().insertComponent(ComponentTesting.newFileDto(privateProject)); + + assertThat(purgeMapper.selectRootAndModulesOrSubviewsByProjectUuid(file.uuid())) + .isEmpty(); + } + + @Test + public void selectRootAndModulesOrSubviewsByProjectUuid_does_not_return_subview_with_specified_uuid() { + ComponentDto view = db.components().insertView(); + ComponentDto subview = db.components().insertComponent(ComponentTesting.newSubView(view)); + + assertThat(purgeMapper.selectRootAndModulesOrSubviewsByProjectUuid(subview.uuid())) + .isEmpty(); + } + + @Test + public void selectRootAndModulesOrSubviewsByProjectUuid_does_not_return_technicalCopy_with_specified_uuid() { + ComponentDto privateProject = db.components().insertPrivateProject(); + ComponentDto view = db.components().insertView(); + ComponentDto technicalCopy = db.components().insertComponent(ComponentTesting.newProjectCopy("a", view, privateProject)); + + assertThat(purgeMapper.selectRootAndModulesOrSubviewsByProjectUuid(technicalCopy.uuid())) + .isEmpty(); + } +} |