3 * Copyright (C) 2009-2023 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.ce.task.projectanalysis.component;
22 import com.tngtech.java.junit.dataprovider.DataProvider;
23 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
24 import com.tngtech.java.junit.dataprovider.UseDataProvider;
25 import java.util.Collections;
26 import java.util.Optional;
27 import javax.annotation.Nullable;
28 import org.assertj.core.api.ThrowableAssert;
29 import org.junit.Rule;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 import org.sonar.api.config.internal.ConfigurationBridge;
33 import org.sonar.api.config.internal.MapSettings;
34 import org.sonar.api.utils.System2;
35 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
36 import org.sonar.ce.task.projectanalysis.analysis.Branch;
37 import org.sonar.db.DbSession;
38 import org.sonar.db.DbTester;
39 import org.sonar.db.component.BranchDto;
40 import org.sonar.db.component.BranchType;
41 import org.sonar.db.component.ComponentDto;
42 import org.sonar.db.component.ComponentTesting;
43 import org.sonar.db.protobuf.DbProjectBranches;
44 import org.sonar.server.project.Project;
46 import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
47 import static org.assertj.core.api.Assertions.assertThat;
48 import static org.assertj.core.api.Assertions.assertThatThrownBy;
49 import static org.mockito.Mockito.mock;
50 import static org.mockito.Mockito.when;
51 import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;
52 import static org.sonar.core.config.PurgeConstants.BRANCHES_TO_KEEP_WHEN_INACTIVE;
53 import static org.sonar.db.component.BranchType.BRANCH;
54 import static org.sonar.db.component.BranchType.PULL_REQUEST;
56 @RunWith(DataProviderRunner.class)
57 public class BranchPersisterImplIT {
58 private final static Component MAIN = builder(Component.Type.PROJECT, 1, "PROJECT_KEY").setUuid("PROJECT_UUID").setName("p1").build();
59 private final static Component BRANCH1 = builder(Component.Type.PROJECT, 2, "BRANCH_KEY").setUuid("BRANCH_UUID").build();
60 private final static Component PR1 = builder(Component.Type.PROJECT, 3, "develop").setUuid("PR_UUID").build();
61 private static final Project PROJECT = new Project(MAIN.getUuid(), MAIN.getKey(), MAIN.getName(), null, Collections.emptyList());
64 public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule();
66 public DbTester dbTester = DbTester.create(System2.INSTANCE);
68 public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
70 private final MapSettings settings = new MapSettings();
71 private final ConfigurationRepository configurationRepository = new TestSettingsRepository(new ConfigurationBridge(settings));
72 private final BranchPersister underTest = new BranchPersisterImpl(dbTester.getDbClient(), treeRootHolder, analysisMetadataHolder, configurationRepository);
75 public void persist_fails_with_ISE_if_no_component_for_main_branches() {
76 analysisMetadataHolder.setBranch(createBranch(BRANCH, true, "master"));
77 analysisMetadataHolder.setProject(PROJECT);
78 treeRootHolder.setRoot(MAIN);
79 DbSession dbSession = dbTester.getSession();
81 expectMissingComponentISE(() -> underTest.persist(dbSession));
85 public void persist_fails_with_ISE_if_no_component_for_branches() {
86 analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "foo"));
87 analysisMetadataHolder.setProject(PROJECT);
89 treeRootHolder.setRoot(BRANCH1);
90 DbSession dbSession = dbTester.getSession();
92 expectMissingComponentISE(() -> underTest.persist(dbSession));
96 public void persist_fails_with_ISE_if_no_component_for_pull_request() {
97 analysisMetadataHolder.setBranch(createBranch(BranchType.PULL_REQUEST, false, "12"));
98 analysisMetadataHolder.setProject(PROJECT);
100 treeRootHolder.setRoot(BRANCH1);
101 DbSession dbSession = dbTester.getSession();
103 expectMissingComponentISE(() -> underTest.persist(dbSession));
107 @UseDataProvider("nullOrNotNullString")
108 public void persist_creates_row_in_PROJECTS_BRANCHES_for_branch(@Nullable String mergeBranchUuid) {
109 String branchName = "branch";
111 // add project and branch in table PROJECTS
112 ComponentDto mainComponent = ComponentTesting.newPrivateProjectDto(MAIN.getUuid()).setKey(MAIN.getKey());
113 ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
114 new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
115 dbTester.components().insertComponents(mainComponent, component);
116 // set project in metadata
117 treeRootHolder.setRoot(BRANCH1);
118 analysisMetadataHolder.setBranch(createBranch(BRANCH, false, branchName, mergeBranchUuid));
119 analysisMetadataHolder.setProject(Project.from(mainComponent));
121 underTest.persist(dbTester.getSession());
123 dbTester.getSession().commit();
125 assertThat(dbTester.countRowsOfTable("components")).isEqualTo(2);
126 Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
127 assertThat(branchDto).isPresent();
128 assertThat(branchDto.get().getBranchType()).isEqualTo(BRANCH);
129 assertThat(branchDto.get().getKey()).isEqualTo(branchName);
130 assertThat(branchDto.get().getMergeBranchUuid()).isEqualTo(mergeBranchUuid);
131 assertThat(branchDto.get().getProjectUuid()).isEqualTo(MAIN.getUuid());
132 assertThat(branchDto.get().getPullRequestData()).isNull();
136 public void main_branch_is_excluded_from_branch_purge_by_default() {
137 analysisMetadataHolder.setBranch(createBranch(BRANCH, true, "master"));
138 analysisMetadataHolder.setProject(PROJECT);
139 treeRootHolder.setRoot(MAIN);
140 dbTester.components().insertPublicProject(p -> p.setKey(MAIN.getKey()).setUuid(MAIN.getUuid()));
143 underTest.persist(dbTester.getSession());
145 Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), MAIN.getUuid());
146 assertThat(branchDto).isPresent();
147 assertThat(branchDto.get().isExcludeFromPurge()).isTrue();
151 public void non_main_branch_is_excluded_from_branch_purge_if_matches_sonar_dbcleaner_keepFromPurge_property() {
152 settings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "BRANCH.*");
153 analysisMetadataHolder.setProject(PROJECT);
154 analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "BRANCH_KEY"));
155 treeRootHolder.setRoot(BRANCH1);
156 ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setKey(MAIN.getKey()).setUuid(MAIN.getUuid()));
157 ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
158 new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
159 dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component);
162 underTest.persist(dbTester.getSession());
164 Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
165 assertThat(branchDto).isPresent();
166 assertThat(branchDto.get().isExcludeFromPurge()).isTrue();
170 public void branch_is_excluded_from_purge_when_it_matches_setting() {
171 analysisMetadataHolder.setProject(PROJECT);
172 analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "BRANCH_KEY"));
173 treeRootHolder.setRoot(BRANCH1);
174 ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setKey(MAIN.getKey()).setUuid(MAIN.getUuid()));
175 ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
176 new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
177 dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component);
178 settings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "BRANCH.*");
181 underTest.persist(dbTester.getSession());
183 Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
184 assertThat(branchDto).isPresent();
185 assertThat(branchDto.get().isExcludeFromPurge()).isTrue();
189 public void branch_is_not_excluded_from_purge_when_it_does_not_match_setting() {
190 analysisMetadataHolder.setProject(PROJECT);
191 analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "BRANCH_KEY"));
192 treeRootHolder.setRoot(BRANCH1);
193 ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setKey(MAIN.getKey()).setUuid(MAIN.getUuid()));
194 ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
195 new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
196 dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component);
197 settings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "abc.*");
201 underTest.persist(dbTester.getSession());
203 Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
204 assertThat(branchDto).isPresent();
205 assertThat(branchDto.get().isExcludeFromPurge()).isFalse();
209 public void pull_request_is_never_excluded_from_branch_purge_even_if_its_source_branch_name_matches_sonar_dbcleaner_keepFromPurge_property() {
210 settings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "develop");
211 analysisMetadataHolder.setBranch(createPullRequest(PR1.getKey(), MAIN.getUuid()));
212 analysisMetadataHolder.setProject(PROJECT);
214 analysisMetadataHolder.setPullRequestKey(PR1.getKey());
215 treeRootHolder.setRoot(PR1);
216 ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setKey(MAIN.getKey()).setUuid(MAIN.getUuid()));
217 ComponentDto component = ComponentTesting.newBranchComponent(mainComponent, new BranchDto()
218 .setUuid(PR1.getUuid())
219 .setKey(PR1.getKey())
220 .setProjectUuid(MAIN.getUuid())
221 .setBranchType(PULL_REQUEST)
222 .setMergeBranchUuid(MAIN.getUuid()));
223 dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component);
226 underTest.persist(dbTester.getSession());
228 Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), PR1.getUuid());
229 assertThat(branchDto).isPresent();
230 assertThat(branchDto.get().isExcludeFromPurge()).isFalse();
234 public void non_main_branch_is_included_in_branch_purge_if_branch_name_does_not_match_sonar_dbcleaner_keepFromPurge_property() {
235 settings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "foobar-.*");
236 analysisMetadataHolder.setProject(PROJECT);
237 analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "BRANCH_KEY"));
238 treeRootHolder.setRoot(BRANCH1);
239 ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setKey(MAIN.getKey()).setUuid(MAIN.getUuid()));
240 ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
241 new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
242 dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component);
245 underTest.persist(dbTester.getSession());
247 Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
248 assertThat(branchDto).isPresent();
249 assertThat(branchDto.get().isExcludeFromPurge()).isFalse();
253 public static Object[][] nullOrNotNullString() {
254 return new Object[][] {
256 {randomAlphabetic(12)}
261 public void persist_creates_row_in_PROJECTS_BRANCHES_for_pull_request() {
262 String pullRequestId = "pr-123";
264 // add project and branch in table PROJECTS
265 ComponentDto mainComponent = ComponentTesting.newPrivateProjectDto(MAIN.getUuid()).setKey(MAIN.getKey());
266 ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
267 new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(PULL_REQUEST));
268 dbTester.components().insertComponents(mainComponent, component);
269 // set project in metadata
270 treeRootHolder.setRoot(BRANCH1);
271 analysisMetadataHolder.setBranch(createBranch(PULL_REQUEST, false, pullRequestId, "mergeBanchUuid"));
272 analysisMetadataHolder.setProject(Project.from(mainComponent));
273 analysisMetadataHolder.setPullRequestKey(pullRequestId);
275 underTest.persist(dbTester.getSession());
277 dbTester.getSession().commit();
279 assertThat(dbTester.countRowsOfTable("components")).isEqualTo(2);
280 Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
281 assertThat(branchDto).isPresent();
282 assertThat(branchDto.get().getBranchType()).isEqualTo(PULL_REQUEST);
283 assertThat(branchDto.get().getKey()).isEqualTo(pullRequestId);
284 assertThat(branchDto.get().getMergeBranchUuid()).isEqualTo("mergeBanchUuid");
285 assertThat(branchDto.get().getProjectUuid()).isEqualTo(MAIN.getUuid());
286 assertThat(branchDto.get().getPullRequestData()).isEqualTo(DbProjectBranches.PullRequestData.newBuilder()
287 .setBranch(pullRequestId)
288 .setTarget("mergeBanchUuid")
289 .setTitle(pullRequestId)
293 private static Branch createBranch(BranchType type, boolean isMain, String name) {
294 return createBranch(type, isMain, name, null);
297 private static Branch createPullRequest(String key, String mergeBranchUuid) {
298 Branch branch = createBranch(PULL_REQUEST, false, key, mergeBranchUuid);
299 when(branch.getPullRequestKey()).thenReturn(key);
303 private static Branch createBranch(BranchType type, boolean isMain, String name, @Nullable String mergeBranchUuid) {
304 Branch branch = mock(Branch.class);
305 when(branch.getType()).thenReturn(type);
306 when(branch.getName()).thenReturn(name);
307 when(branch.isMain()).thenReturn(isMain);
308 when(branch.getReferenceBranchUuid()).thenReturn(mergeBranchUuid);
309 when(branch.getTargetBranchName()).thenReturn(mergeBranchUuid);
313 private void expectMissingComponentISE(ThrowableAssert.ThrowingCallable callable) {
314 assertThatThrownBy(callable)
315 .isInstanceOf(IllegalStateException.class)
316 .hasMessage("Component has been deleted by end-user during analysis");