aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-db-dao
diff options
context:
space:
mode:
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>2017-05-30 17:40:00 +0200
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>2017-06-01 15:19:45 +0200
commit530977c23387e88f99533f9202c5cf670f26893a (patch)
tree0e63cb4fee8146c32dc6c0acc53b0d94641d0511 /server/sonar-db-dao
parenta9cd8d9ab2ed78c580af5283f36d581648168a09 (diff)
downloadsonarqube-530977c23387e88f99533f9202c5cf670f26893a.tar.gz
sonarqube-530977c23387e88f99533f9202c5cf670f26893a.zip
SONAR-9328 delete settings & manual measures by project/module
and by views/subviews
Diffstat (limited to 'server/sonar-db-dao')
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeCommands.java24
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeDao.java10
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/purge/PurgeMapper.java5
-rw-r--r--server/sonar-db-dao/src/main/resources/org/sonar/db/purge/PurgeMapper.xml16
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeDaoTest.java57
-rw-r--r--server/sonar-db-dao/src/test/java/org/sonar/db/purge/PurgeMapperTest.java163
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();
+ }
+}