3 * Copyright (C) 2009-2022 SonarSource SA
4 * mailto:info AT sonarsource DOT com
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 package org.sonar.server.component;
22 import java.util.List;
23 import org.junit.Rule;
24 import org.junit.Test;
25 import org.sonar.api.resources.ResourceType;
26 import org.sonar.api.resources.ResourceTypes;
27 import org.sonar.api.utils.System2;
28 import org.sonar.db.DbClient;
29 import org.sonar.db.DbSession;
30 import org.sonar.db.DbTester;
31 import org.sonar.db.component.BranchDto;
32 import org.sonar.db.component.ComponentDto;
33 import org.sonar.db.component.ComponentTesting;
34 import org.sonar.db.component.SnapshotDto;
35 import org.sonar.db.issue.IssueDto;
36 import org.sonar.db.project.ProjectDto;
37 import org.sonar.db.rule.RuleDefinitionDto;
38 import org.sonar.db.webhook.WebhookDto;
39 import org.sonar.server.es.TestProjectIndexers;
41 import static java.util.Arrays.asList;
42 import static org.assertj.core.api.Assertions.assertThat;
43 import static org.assertj.core.api.Assertions.assertThatThrownBy;
44 import static org.mockito.ArgumentMatchers.anyString;
45 import static org.mockito.Mockito.mock;
46 import static org.mockito.Mockito.when;
47 import static org.sonar.db.component.ComponentTesting.newFileDto;
48 import static org.sonar.server.es.ProjectIndexer.Cause.PROJECT_DELETION;
50 public class ComponentCleanerServiceTest {
52 private final System2 system2 = System2.INSTANCE;
55 public final DbTester db = DbTester.create(system2);
57 private final DbClient dbClient = db.getDbClient();
58 private final DbSession dbSession = db.getSession();
59 private final TestProjectIndexers projectIndexers = new TestProjectIndexers();
60 private final ResourceTypes mockResourceTypes = mock(ResourceTypes.class);
61 private final ComponentCleanerService underTest = new ComponentCleanerService(dbClient, mockResourceTypes, projectIndexers);
64 public void delete_project_from_db_and_index() {
65 DbData data1 = insertProjectData();
66 DbData data2 = insertProjectData();
68 underTest.delete(dbSession, data1.project);
70 assertNotExists(data1);
75 public void delete_list_of_projects_from_db_and_index() {
76 DbData data1 = insertProjectData();
77 DbData data2 = insertProjectData();
78 DbData data3 = insertProjectData();
80 underTest.delete(dbSession, asList(data1.project, data2.project));
83 assertNotExists(data1);
84 assertNotExists(data2);
89 public void delete_list_of_components_from_db() {
90 ComponentDto componentDto1 = db.components().insertPublicProject();
91 ComponentDto componentDto2 = db.components().insertPublicProject();
92 ComponentDto componentDto3 = db.components().insertPublicProject();
94 mockResourceTypeAsValidProject();
96 underTest.deleteComponents(dbSession, asList(componentDto1, componentDto2));
99 assertNotExists(componentDto1);
100 assertNotExists(componentDto2);
101 assertExists(componentDto3);
105 public void fail_with_IAE_if_project_non_deletable() {
106 ComponentDto componentDto1 = db.components().insertPublicProject();
107 ComponentDto componentDto2 = db.components().insertPublicProject();
109 mockResourceTypeAsNonDeletable();
113 List<ComponentDto> componentDtos = asList(componentDto1, componentDto2);
115 assertThatThrownBy(() -> underTest.deleteComponents(dbSession, componentDtos))
116 .withFailMessage("Only projects can be deleted")
117 .isInstanceOf(IllegalArgumentException.class);
121 public void delete_application_from_db_and_index() {
122 DbData data1 = insertProjectData();
123 DbData data2 = insertProjectData();
124 DbData data3 = insertProjectData();
125 ProjectDto app1 = insertApplication(data2.project);
126 ProjectDto app2 = insertApplication(data3.project);
128 underTest.deleteApplication(dbSession, app1);
131 assertProjectOrAppExists(app1, false);
132 assertProjectOrAppExists(app2, true);
138 private ProjectDto insertApplication(ProjectDto project) {
139 ProjectDto app = db.components().insertPublicApplicationDto();
140 db.components().addApplicationProject(app, project);
145 public void delete_branch() {
146 DbData data1 = insertProjectData();
147 DbData data2 = insertProjectData();
148 DbData data3 = insertProjectData();
150 underTest.deleteBranch(dbSession, data1.branch);
153 assertNotExists(data1);
159 public void delete_webhooks_from_projects() {
160 ProjectDto project1 = db.components().insertPrivateProjectDto();
161 WebhookDto webhook1 = db.webhooks().insertWebhook(project1);
162 db.webhookDelivery().insert(webhook1);
163 ProjectDto project2 = db.components().insertPrivateProjectDto();
164 WebhookDto webhook2 = db.webhooks().insertWebhook(project2);
165 db.webhookDelivery().insert(webhook2);
166 ProjectDto projectNotToBeDeleted = db.components().insertPrivateProjectDto();
167 WebhookDto webhook3 = db.webhooks().insertWebhook(projectNotToBeDeleted);
168 db.webhookDelivery().insert(webhook3);
170 ProjectDto projectDto1 = dbClient.projectDao().selectByUuid(dbSession, project1.getUuid()).get();
171 ProjectDto projectDto2 = dbClient.projectDao().selectByUuid(dbSession, project2.getUuid()).get();
173 mockResourceTypeAsValidProject();
175 underTest.delete(dbSession, asList(projectDto1, projectDto2));
177 assertThat(db.countRowsOfTable(db.getSession(), "webhooks")).isOne();
178 assertThat(db.countRowsOfTable(db.getSession(), "webhook_deliveries")).isOne();
182 public void fail_with_IAE_if_not_a_project() {
183 mockResourceTypeAsValidProject();
184 ComponentDto project = ComponentTesting.newPrivateProjectDto();
185 db.components().insertComponent(project);
186 ComponentDto file = newFileDto(project, null);
187 dbClient.componentDao().insert(dbSession, file);
190 assertThatThrownBy(() -> underTest.delete(dbSession, file))
191 .isInstanceOf(IllegalArgumentException.class);
194 private DbData insertProjectData() {
195 ComponentDto componentDto = db.components().insertPublicProject();
196 ProjectDto project = dbClient.projectDao().selectByUuid(dbSession, componentDto.uuid()).get();
197 BranchDto branch = dbClient.branchDao().selectByUuid(dbSession, project.getUuid()).get();
199 RuleDefinitionDto rule = db.rules().insert();
200 IssueDto issue = db.issues().insert(rule, project, componentDto);
201 SnapshotDto analysis = db.components().insertSnapshot(componentDto);
202 mockResourceTypeAsValidProject();
203 return new DbData(project, branch, analysis, issue);
206 private void mockResourceTypeAsValidProject() {
207 ResourceType resourceType = mock(ResourceType.class);
208 when(resourceType.getBooleanProperty(anyString())).thenReturn(true);
209 when(mockResourceTypes.get(anyString())).thenReturn(resourceType);
212 private void mockResourceTypeAsNonDeletable() {
213 ResourceType resourceType = mock(ResourceType.class);
214 when(resourceType.getBooleanProperty("deletable")).thenReturn(false);
215 when(mockResourceTypes.get(anyString())).thenReturn(resourceType);
218 private void assertNotExists(DbData data) {
219 assertDataInDb(data, false);
220 assertThat(projectIndexers.hasBeenCalled(data.branch.getUuid(), PROJECT_DELETION)).isTrue();
223 private void assertExists(DbData data) {
224 assertDataInDb(data, true);
225 assertThat(projectIndexers.hasBeenCalled(data.branch.getUuid(), PROJECT_DELETION)).isFalse();
228 private void assertDataInDb(DbData data, boolean exists) {
229 assertProjectOrAppExists(data.project, exists);
230 assertThat(dbClient.snapshotDao().selectByUuid(dbSession, data.snapshot.getUuid()).isPresent()).isEqualTo(exists);
231 assertThat(dbClient.issueDao().selectByKey(dbSession, data.issue.getKey()).isPresent()).isEqualTo(exists);
234 private void assertProjectOrAppExists(ProjectDto appOrProject, boolean exists) {
235 assertThat(dbClient.projectDao().selectByUuid(dbSession, appOrProject.getUuid()).isPresent()).isEqualTo(exists);
236 assertThat(dbClient.componentDao().selectByUuid(dbSession, appOrProject.getUuid()).isPresent()).isEqualTo(exists);
237 assertThat(dbClient.branchDao().selectByUuid(dbSession, appOrProject.getUuid()).isPresent()).isEqualTo(exists);
240 private void assertNotExists(ComponentDto componentDto) {
241 assertComponentExists(componentDto, false);
244 private void assertExists(ComponentDto componentDto) {
245 assertComponentExists(componentDto, true);
248 private void assertComponentExists(ComponentDto componentDto, boolean exists) {
249 assertThat(dbClient.componentDao().selectByUuid(dbSession, componentDto.uuid()).isPresent()).isEqualTo(exists);
252 private static class DbData {
253 final ProjectDto project;
254 final BranchDto branch;
255 final SnapshotDto snapshot;
256 final IssueDto issue;
258 DbData(ProjectDto project, BranchDto branch, SnapshotDto snapshot, IssueDto issue) {
259 this.project = project;
260 this.branch = branch;
261 this.snapshot = snapshot;