From f44552d26beabb3a99e0483c575bc486a72ef8eb Mon Sep 17 00:00:00 2001 From: Guillaume Jambet Date: Tue, 13 Feb 2018 17:11:00 +0100 Subject: [PATCH] SONAR-10345 Ensure that no orphaned webhooks remains when deleting an organization or a project. --- .../java/org/sonar/db/webhook/WebhookDao.java | 9 +++++ .../org/sonar/db/webhook/WebhookMapper.java | 3 ++ .../org/sonar/db/webhook/WebhookMapper.xml | 12 +++++++ .../org/sonar/db/webhook/WebhookDaoTest.java | 36 +++++++++++++++++++ .../component/ComponentCleanerService.java | 1 + .../server/organization/ws/DeleteAction.java | 2 ++ 6 files changed, 63 insertions(+) diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDao.java index dd6c9300305..9860570b3e2 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDao.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookDao.java @@ -72,4 +72,13 @@ public class WebhookDao implements Dao { private static WebhookMapper mapper(DbSession dbSession) { return dbSession.getMapper(WebhookMapper.class); } + + public void cleanWebhooks(DbSession dbSession, OrganizationDto organization) { + mapper(dbSession).deleteForOrganizationUuid(organization.getUuid()); + } + + public void cleanWebhooks(DbSession dbSession, ComponentDto componentDto) { + mapper(dbSession).deleteForProjectUuid(componentDto.uuid()); + } + } diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookMapper.java index 354f0d2de5d..870b032c09a 100644 --- a/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookMapper.java +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/webhook/WebhookMapper.java @@ -38,4 +38,7 @@ public interface WebhookMapper { void delete(@Param("uuid") String uuid); + void deleteForOrganizationUuid(@Param("organizationUuid") String organizationUuid); + + void deleteForProjectUuid(@Param("projectUuid") String organizationUuid); } diff --git a/server/sonar-db-dao/src/main/resources/org/sonar/db/webhook/WebhookMapper.xml b/server/sonar-db-dao/src/main/resources/org/sonar/db/webhook/WebhookMapper.xml index bdba2cdec54..c9cd317f832 100644 --- a/server/sonar-db-dao/src/main/resources/org/sonar/db/webhook/WebhookMapper.xml +++ b/server/sonar-db-dao/src/main/resources/org/sonar/db/webhook/WebhookMapper.xml @@ -69,4 +69,16 @@ uuid = #{uuid,jdbcType=VARCHAR} + + delete from webhooks + where + organization_uuid = #{organizationUuid,jdbcType=VARCHAR} + + + + delete from webhooks + where + project_uuid = #{projectUuid,jdbcType=VARCHAR} + + diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookDaoTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookDaoTest.java index 2b16e6535eb..3f722570012 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookDaoTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/webhook/WebhookDaoTest.java @@ -28,6 +28,8 @@ import org.sonar.api.utils.System2; import org.sonar.db.DbClient; import org.sonar.db.DbSession; import org.sonar.db.DbTester; +import org.sonar.db.component.ComponentDbTester; +import org.sonar.db.component.ComponentDto; import org.sonar.db.organization.OrganizationDbTester; import org.sonar.db.organization.OrganizationDto; @@ -47,8 +49,10 @@ public class WebhookDaoTest { private final DbSession dbSession = dbTester.getSession(); private final WebhookDao underTest = dbClient.webhookDao(); private final WebhookDbTester webhookDbTester = dbTester.webhooks(); + private final ComponentDbTester componentDbTester = dbTester.components(); private final OrganizationDbTester organizationDbTester = dbTester.organizations(); + @Test public void selectByUuid_returns_empty_if_uuid_does_not_exist() { assertThat(underTest.selectByUuid(dbSession, "missing")).isEmpty(); @@ -116,10 +120,42 @@ public class WebhookDaoTest { assertThat(new Date(reloaded.getUpdatedAt())).isInSameMinuteWindowAs(new Date(system2.now())); } + @Test + public void cleanWebhooksOfAProject() { + + OrganizationDto organization = organizationDbTester.insert(); + ComponentDto componentDto = componentDbTester.insertPrivateProject(organization); + webhookDbTester.insertWebhook(componentDto); + webhookDbTester.insertWebhook(componentDto); + webhookDbTester.insertWebhook(componentDto); + webhookDbTester.insertWebhook(componentDto); + + underTest.cleanWebhooks(dbSession, componentDto); + + Optional reloaded = underTest.selectByUuid(dbSession, componentDto.uuid()); + assertThat(reloaded).isEmpty(); + } + + @Test + public void cleanWebhooksOfAnOrganization() { + + OrganizationDto organization = organizationDbTester.insert(); + webhookDbTester.insertWebhook(organization); + webhookDbTester.insertWebhook(organization); + webhookDbTester.insertWebhook(organization); + webhookDbTester.insertWebhook(organization); + + underTest.cleanWebhooks(dbSession, organization); + + Optional reloaded = underTest.selectByUuid(dbSession, organization.getUuid()); + assertThat(reloaded).isEmpty(); + } + @Test public void delete() { OrganizationDto organization = organizationDbTester.insert(); + WebhookDto dto = webhookDbTester.insertWebhook(organization); underTest.delete(dbSession, dto.getUuid()); diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java index cf9d93f4ff7..66f91d1e276 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ComponentCleanerService.java @@ -62,6 +62,7 @@ public class ComponentCleanerService { checkArgument(!hasNotProjectScope(project) && !isNotDeletable(project) && project.getMainBranchProjectUuid() == null, "Only projects can be deleted"); dbClient.purgeDao().deleteProject(dbSession, project.uuid()); dbClient.userDao().cleanHomepage(dbSession, project); + dbClient.webhookDao().cleanWebhooks(dbSession, project); projectIndexers.commitAndIndex(dbSession, singletonList(project), ProjectIndexer.Cause.PROJECT_DELETION); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java index 2b43241f19e..6405afdd11f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/organization/ws/DeleteAction.java @@ -115,6 +115,7 @@ public class DeleteAction implements OrganizationsWsAction { private void deleteProjects(DbSession dbSession, OrganizationDto organization) { List roots = dbClient.componentDao().selectAllRootsByOrganization(dbSession, organization.getUuid()); + roots.forEach(project -> dbClient.webhookDao().cleanWebhooks(dbSession, project)); componentCleanerService.delete(dbSession, roots); } @@ -151,6 +152,7 @@ public class DeleteAction implements OrganizationsWsAction { dbClient.organizationMemberDao().deleteByOrganizationUuid(dbSession, organization.getUuid()); dbClient.organizationDao().deleteByUuid(dbSession, organization.getUuid()); dbClient.userDao().cleanHomepage(dbSession, organization); + dbClient.webhookDao().cleanWebhooks(dbSession, organization); userIndexer.commitAndIndexByLogins(dbSession, logins); } -- 2.39.5