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();
}
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);
*/
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);
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
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;
@Rule
public DbTester dbTester = DbTester.create(system2);
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
private DbClient dbClient = dbTester.getDbClient();
private DbSession dbSession = dbTester.getSession();
}
@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");
--- /dev/null
+/*
+ * 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();
+ }
+}