import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.System2;
import org.sonar.db.DbSession;
import org.sonar.db.audit.AuditPersister;
import org.sonar.db.audit.model.ComponentNewValue;
+import org.sonar.db.component.BranchDto;
import org.sonar.db.component.BranchMapper;
import org.sonar.db.component.ComponentDto;
private final System2 system2;
private AuditPersister auditPersister;
- public PurgeDao(System2 system2) {
+ public PurgeDao(System2 system2) {
this.system2 = system2;
}
PurgeCommands purgeCommands = new PurgeCommands(session, profiler, system2);
long start = System2.INSTANCE.now();
- session.getMapper(BranchMapper.class).selectByProjectUuid(uuid).stream()
+ List<String> branchUuids = session.getMapper(BranchMapper.class).selectByProjectUuid(uuid).stream()
.filter(branch -> !uuid.equals(branch.getUuid()))
- .forEach(branch -> deleteRootComponent(branch.getUuid(), purgeMapper, purgeCommands));
+ .map(BranchDto::getUuid)
+ .collect(Collectors.toList());
+
+ branchUuids.stream()
+ .forEach(id -> deleteRootComponent(id, purgeMapper, purgeCommands));
deleteRootComponent(uuid, purgeMapper, purgeCommands);
commands.deleteComponentsByMainBranchProjectUuid(rootUuid);
commands.deleteProject(rootUuid);
commands.deleteUserDismissedMessages(rootUuid);
+ commands.deleteOutdatedProperties(rootUuid);
}
/**
assertThat(countAnalysisPropertiesOf(otherAnalysis)).isEqualTo(count);
}
+ @Test
+ @UseDataProvider("projects")
+ public void deleteOutdatedProperties_deletes_properties_by_component_uuid(ComponentDto project) {
+ ComponentDto component = dbTester.components().insertComponent(project);
+ ComponentDto anotherComponent = dbTester.components().insertPublicProject();
+ int count = 4;
+ IntStream.range(0, count).forEach(i -> {
+ insertRandomProperty(component);
+ insertRandomProperty(anotherComponent);
+ });
+
+ underTest.deleteOutdatedProperties(component.uuid());
+
+ assertThat(countPropertiesOf(component)).isZero();
+ assertThat(countPropertiesOf(anotherComponent)).isEqualTo(count);
+ }
+
@Test
@UseDataProvider("projectsAndViews")
public void deleteIssues_deletes_all_issues_of_specified_root_component(ComponentDto projectOrView) {
return dbTester.countSql("select count(1) from analysis_properties where analysis_uuid='" + analysis.getUuid() + "'");
}
+ private int countPropertiesOf(ComponentDto componentDto) {
+ return dbTester.countSql("select count(1) from properties where component_uuid='" + componentDto.uuid() + "'");
+ }
+
private int countEventsOf(SnapshotDto analysis) {
return dbTester.countSql("select count(1) from events where analysis_uuid='" + analysis.getUuid() + "'");
}
"CREATED_AT", 1L);
}
+ private void insertRandomProperty(ComponentDto component) {
+ boolean isEmpty = new Random().nextBoolean();
+ dbTester.executeInsert(
+ "PROPERTIES",
+ "UUID", newUuid(),
+ "PROP_KEY", randomAlphabetic(10),
+ "COMPONENT_UUID", component.uuid(),
+ "TEXT_VALUE", randomAlphabetic(10),
+ "IS_EMPTY", isEmpty,
+ "CREATED_AT", 1L);
+ }
+
private int countAnalysesOfRoot(ComponentDto projectOrView) {
return dbTester.countSql("select count(1) from snapshots where component_uuid='" + projectOrView.uuid() + "'");
}
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
ComponentDto branch1 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH));
db.components().insertSnapshot(branch1, dto -> dto.setCreatedAt(DateUtils.addDays(new Date(), -31).getTime()));
- // branch with other components and issues, updated 31 days ago
+ // branches with other components and issues, updated 31 days ago
ComponentDto branch2 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.PULL_REQUEST));
db.components().insertSnapshot(branch2, dto -> dto.setCreatedAt(DateUtils.addDays(new Date(), -31).getTime()));
ComponentDto file = db.components().insertComponent(newFileDto(branch2));
db.issues().insert(rule, branch2, file);
+ ComponentDto branch3 = db.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH));
+ db.components().insertSnapshot(branch3, dto -> dto.setCreatedAt(DateUtils.addDays(new Date(), -31).getTime()));
+
+ // properties exist or active and for inactive branch
+ insertPropertyFor(branch3, branch1);
+
// analysing branch1
underTest.purge(dbSession, newConfigurationWith30Days(System2.INSTANCE, branch1.uuid(), branch1.getMainBranchProjectUuid()), PurgeListener.EMPTY, new PurgeProfiler());
dbSession.commit();
// branch1 wasn't deleted since it was being analyzed!
assertThat(uuidsIn("components")).containsOnly(project.uuid(), nonMainBranch.uuid(), branch1.uuid());
assertThat(uuidsIn("projects")).containsOnly(project.uuid());
+ assertThat(componentUuidsIn("properties")).containsOnly(branch1.uuid());
}
@Test
db.components().addProjectBranchToApplicationBranch(dbClient.branchDao().selectByUuid(dbSession, appBranch.uuid()).get(), projectBranch);
db.components().addProjectBranchToApplicationBranch(dbClient.branchDao().selectByUuid(dbSession, otherAppBranch.uuid()).get(), projectBranch);
+ // properties exist or active and for inactive branch
+ insertPropertyFor(appBranch, otherAppBranch);
+
underTest.deleteBranch(dbSession, appBranch.uuid());
dbSession.commit();
assertThat(uuidsIn("project_measures")).containsOnly(appMeasure.getUuid(), otherAppMeasure.getUuid(), otherAppBranchMeasure.getUuid());
assertThat(uuidsIn("app_projects", "application_uuid")).containsOnly(app.uuid(), otherApp.uuid());
assertThat(uuidsIn("app_branch_project_branch", "application_branch_uuid")).containsOnly(otherAppBranch.uuid());
+ assertThat(componentUuidsIn("properties")).containsOnly(otherAppBranch.uuid());
+
}
@Test
int projectEntryCount = db.countRowsOfTable("components");
int issueCount = db.countRowsOfTable("issues");
int branchCount = db.countRowsOfTable("project_branches");
+ Collection<BranchDto> anotherLivingProjectBranches = db.getDbClient().branchDao()
+ .selectByComponent(db.getSession(), anotherLivingProject);
+ insertPropertyFor(anotherLivingProjectBranches);
+
+ assertThat(db.countRowsOfTable("properties")).isEqualTo(anotherLivingProjectBranches.size());
ComponentDto projectToDelete = insertProjectWithBranchAndRelatedData();
+ Collection<BranchDto> projectToDeleteBranches = db.getDbClient().branchDao()
+ .selectByComponent(db.getSession(), projectToDelete);
+ insertPropertyFor(projectToDeleteBranches);
+
+ assertThat(db.countRowsOfTable("properties")).isEqualTo(anotherLivingProjectBranches.size() + projectToDeleteBranches.size());
assertThat(db.countRowsOfTable("components")).isGreaterThan(projectEntryCount);
assertThat(db.countRowsOfTable("issues")).isGreaterThan(issueCount);
assertThat(db.countRowsOfTable("project_branches")).isGreaterThan(branchCount);
assertThat(db.countRowsOfTable("components")).isEqualTo(projectEntryCount);
assertThat(db.countRowsOfTable("issues")).isEqualTo(issueCount);
assertThat(db.countRowsOfTable("project_branches")).isEqualTo(branchCount);
+ assertThat(db.countRowsOfTable("properties")).isEqualTo(anotherLivingProjectBranches.size());
}
@Test
componentDto.name(), null));
}
+ private void insertPropertyFor(Collection<BranchDto> branches) {
+ branches.stream().forEach(branchDto -> db.properties().insertProperty(new PropertyDto()
+ .setKey(randomAlphabetic(3))
+ .setValue(randomAlphabetic(3))
+ .setComponentUuid(branchDto.getUuid()),
+ branchDto.getKey(), null));
+ }
+
private Stream<String> getComponentUuidsOfMeasures() {
return db.select("select component_uuid as \"COMPONENT_UUID\" from project_measures").stream()
.map(row -> (String) row.get("COMPONENT_UUID"));
return uuidsIn(tableName, "uuid");
}
+ private Stream<String> componentUuidsIn(String tableName) {
+ return uuidsIn(tableName, "component_uuid");
+ }
+
private Stream<String> taskUuidsIn(String tableName) {
return uuidsIn(tableName, "task_uuid");
}