]> source.dussan.org Git - sonarqube.git/blob
e8f8aa2913bd92988898eae5455e69d0d21cce6b
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2021 SonarSource SA
4  * mailto:info AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20 package org.sonar.ce.task.projectanalysis.component;
21
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.MapSettings;
33 import org.sonar.api.utils.System2;
34 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
35 import org.sonar.ce.task.projectanalysis.analysis.Branch;
36 import org.sonar.db.DbSession;
37 import org.sonar.db.DbTester;
38 import org.sonar.db.component.BranchDto;
39 import org.sonar.db.component.BranchType;
40 import org.sonar.db.component.ComponentDto;
41 import org.sonar.db.component.ComponentTesting;
42 import org.sonar.db.property.PropertyDto;
43 import org.sonar.db.protobuf.DbProjectBranches;
44 import org.sonar.server.project.Project;
45 import org.sonar.server.setting.ProjectConfigurationLoader;
46 import org.sonar.server.setting.ProjectConfigurationLoaderImpl;
47
48 import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
49 import static org.assertj.core.api.Assertions.assertThat;
50 import static org.assertj.core.api.Assertions.assertThatThrownBy;
51 import static org.mockito.Mockito.mock;
52 import static org.mockito.Mockito.when;
53 import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;
54 import static org.sonar.core.config.PurgeConstants.BRANCHES_TO_KEEP_WHEN_INACTIVE;
55 import static org.sonar.db.component.BranchType.BRANCH;
56 import static org.sonar.db.component.BranchType.PULL_REQUEST;
57
58 @RunWith(DataProviderRunner.class)
59 public class BranchPersisterImplTest {
60   private final static Component MAIN = builder(Component.Type.PROJECT, 1, "PROJECT_KEY").setUuid("PROJECT_UUID").setName("p1").build();
61   private final static Component BRANCH1 = builder(Component.Type.PROJECT, 2, "BRANCH_KEY").setUuid("BRANCH_UUID").build();
62   private final static Component PR1 = builder(Component.Type.PROJECT, 3, "develop").setUuid("PR_UUID").build();
63   private static final Project PROJECT = new Project(MAIN.getUuid(), MAIN.getKey(), MAIN.getName(), null, Collections.emptyList());
64
65   @Rule
66   public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule();
67   @Rule
68   public DbTester dbTester = DbTester.create(System2.INSTANCE);
69   @Rule
70   public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
71
72   private final MapSettings globalSettings = new MapSettings();
73   private final ProjectConfigurationLoader projectConfiguration = new ProjectConfigurationLoaderImpl(globalSettings, dbTester.getDbClient());
74   private final BranchPersister underTest = new BranchPersisterImpl(dbTester.getDbClient(), treeRootHolder, analysisMetadataHolder,
75     projectConfiguration);
76
77   @Test
78   public void persist_fails_with_ISE_if_no_component_for_main_branches() {
79     analysisMetadataHolder.setBranch(createBranch(BRANCH, true, "master"));
80     treeRootHolder.setRoot(MAIN);
81     DbSession dbSession = dbTester.getSession();
82
83     expectMissingComponentISE(() -> underTest.persist(dbSession));
84   }
85
86   @Test
87   public void persist_fails_with_ISE_if_no_component_for_branches() {
88     analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "foo"));
89     treeRootHolder.setRoot(BRANCH1);
90     DbSession dbSession = dbTester.getSession();
91
92     expectMissingComponentISE(() -> underTest.persist(dbSession));
93   }
94
95   @Test
96   public void persist_fails_with_ISE_if_no_component_for_pull_request() {
97     analysisMetadataHolder.setBranch(createBranch(BranchType.PULL_REQUEST, false, "12"));
98     treeRootHolder.setRoot(BRANCH1);
99     DbSession dbSession = dbTester.getSession();
100
101     expectMissingComponentISE(() -> underTest.persist(dbSession));
102   }
103
104   @Test
105   @UseDataProvider("nullOrNotNullString")
106   public void persist_creates_row_in_PROJECTS_BRANCHES_for_branch(@Nullable String mergeBranchUuid) {
107     String branchName = "branch";
108
109     // add project and branch in table PROJECTS
110     ComponentDto mainComponent = ComponentTesting.newPrivateProjectDto(MAIN.getUuid()).setDbKey(MAIN.getKey());
111     ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
112       new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
113     dbTester.components().insertComponents(mainComponent, component);
114     // set project in metadata
115     treeRootHolder.setRoot(BRANCH1);
116     analysisMetadataHolder.setBranch(createBranch(BRANCH, false, branchName, mergeBranchUuid));
117     analysisMetadataHolder.setProject(Project.from(mainComponent));
118
119     underTest.persist(dbTester.getSession());
120
121     dbTester.getSession().commit();
122
123     assertThat(dbTester.countRowsOfTable("components")).isEqualTo(2);
124     Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
125     assertThat(branchDto).isPresent();
126     assertThat(branchDto.get().getBranchType()).isEqualTo(BRANCH);
127     assertThat(branchDto.get().getKey()).isEqualTo(branchName);
128     assertThat(branchDto.get().getMergeBranchUuid()).isEqualTo(mergeBranchUuid);
129     assertThat(branchDto.get().getProjectUuid()).isEqualTo(MAIN.getUuid());
130     assertThat(branchDto.get().getPullRequestData()).isNull();
131   }
132
133   @Test
134   public void main_branch_is_excluded_from_branch_purge_by_default() {
135     analysisMetadataHolder.setBranch(createBranch(BRANCH, true, "master"));
136     treeRootHolder.setRoot(MAIN);
137     dbTester.components().insertPublicProject(p -> p.setDbKey(MAIN.getDbKey()).setUuid(MAIN.getUuid()));
138     dbTester.commit();
139
140     underTest.persist(dbTester.getSession());
141
142     Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), MAIN.getUuid());
143     assertThat(branchDto).isPresent();
144     assertThat(branchDto.get().isExcludeFromPurge()).isTrue();
145   }
146
147   @Test
148   public void non_main_branch_is_excluded_from_branch_purge_if_matches_sonar_dbcleaner_keepFromPurge_property() {
149     globalSettings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "BRANCH.*");
150     analysisMetadataHolder.setProject(PROJECT);
151     analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "BRANCH_KEY"));
152     treeRootHolder.setRoot(BRANCH1);
153     ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setDbKey(MAIN.getDbKey()).setUuid(MAIN.getUuid()));
154     ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
155       new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
156     dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component);
157     dbTester.commit();
158
159     underTest.persist(dbTester.getSession());
160
161     Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
162     assertThat(branchDto).isPresent();
163     assertThat(branchDto.get().isExcludeFromPurge()).isTrue();
164   }
165
166   @Test
167   public void branch_is_excluded_from_purge_when_it_matches_project_level_but_not_global_level_keepFromPurge_setting() {
168     analysisMetadataHolder.setProject(PROJECT);
169     analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "BRANCH_KEY"));
170     treeRootHolder.setRoot(BRANCH1);
171     ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setDbKey(MAIN.getDbKey()).setUuid(MAIN.getUuid()));
172     ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
173       new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
174     dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component);
175     globalSettings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "abc.*");
176     insertProjectProperty(mainComponent, BRANCHES_TO_KEEP_WHEN_INACTIVE, "BRANCH.*");
177     dbTester.commit();
178
179     underTest.persist(dbTester.getSession());
180
181     Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
182     assertThat(branchDto).isPresent();
183     assertThat(branchDto.get().isExcludeFromPurge()).isTrue();
184   }
185
186   @Test
187   public void branch_is_not_excluded_from_purge_when_it_does_not_match_overriden_global_keepFromPurge_setting_on_project_level() {
188     analysisMetadataHolder.setProject(PROJECT);
189     analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "BRANCH_KEY"));
190     treeRootHolder.setRoot(BRANCH1);
191     ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setDbKey(MAIN.getDbKey()).setUuid(MAIN.getUuid()));
192     ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
193       new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
194     dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component);
195     globalSettings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "BRANCH.*");
196     insertProjectProperty(mainComponent, BRANCHES_TO_KEEP_WHEN_INACTIVE, "abc.*");
197     dbTester.commit();
198
199     underTest.persist(dbTester.getSession());
200
201     Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
202     assertThat(branchDto).isPresent();
203     assertThat(branchDto.get().isExcludeFromPurge()).isFalse();
204   }
205
206   @Test
207   public void pull_request_is_never_excluded_from_branch_purge_even_if_its_source_branch_name_matches_sonar_dbcleaner_keepFromPurge_property() {
208     globalSettings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "develop");
209     analysisMetadataHolder.setBranch(createPullRequest(PR1.getKey(), MAIN.getUuid()));
210     analysisMetadataHolder.setPullRequestKey(PR1.getKey());
211     treeRootHolder.setRoot(PR1);
212     ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setDbKey(MAIN.getDbKey()).setUuid(MAIN.getUuid()));
213     ComponentDto component = ComponentTesting.newBranchComponent(mainComponent, new BranchDto()
214       .setUuid(PR1.getUuid())
215       .setKey(PR1.getKey())
216       .setProjectUuid(MAIN.getUuid())
217       .setBranchType(PULL_REQUEST)
218       .setMergeBranchUuid(MAIN.getUuid()));
219     dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component);
220     dbTester.commit();
221
222     underTest.persist(dbTester.getSession());
223
224     Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), PR1.getUuid());
225     assertThat(branchDto).isPresent();
226     assertThat(branchDto.get().isExcludeFromPurge()).isFalse();
227   }
228
229   @Test
230   public void non_main_branch_is_included_in_branch_purge_if_branch_name_does_not_match_sonar_dbcleaner_keepFromPurge_property() {
231     globalSettings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "foobar-.*");
232     analysisMetadataHolder.setProject(PROJECT);
233     analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "BRANCH_KEY"));
234     treeRootHolder.setRoot(BRANCH1);
235     ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setDbKey(MAIN.getDbKey()).setUuid(MAIN.getUuid()));
236     ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
237       new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
238     dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component);
239     dbTester.commit();
240
241     underTest.persist(dbTester.getSession());
242
243     Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
244     assertThat(branchDto).isPresent();
245     assertThat(branchDto.get().isExcludeFromPurge()).isFalse();
246   }
247
248   @DataProvider
249   public static Object[][] nullOrNotNullString() {
250     return new Object[][] {
251       {null},
252       {randomAlphabetic(12)}
253     };
254   }
255
256   @Test
257   public void persist_creates_row_in_PROJECTS_BRANCHES_for_pull_request() {
258     String pullRequestId = "pr-123";
259
260     // add project and branch in table PROJECTS
261     ComponentDto mainComponent = ComponentTesting.newPrivateProjectDto(MAIN.getUuid()).setDbKey(MAIN.getKey());
262     ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
263       new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(PULL_REQUEST));
264     dbTester.components().insertComponents(mainComponent, component);
265     // set project in metadata
266     treeRootHolder.setRoot(BRANCH1);
267     analysisMetadataHolder.setBranch(createBranch(PULL_REQUEST, false, pullRequestId, "mergeBanchUuid"));
268     analysisMetadataHolder.setProject(Project.from(mainComponent));
269     analysisMetadataHolder.setPullRequestKey(pullRequestId);
270
271     underTest.persist(dbTester.getSession());
272
273     dbTester.getSession().commit();
274
275     assertThat(dbTester.countRowsOfTable("components")).isEqualTo(2);
276     Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
277     assertThat(branchDto).isPresent();
278     assertThat(branchDto.get().getBranchType()).isEqualTo(PULL_REQUEST);
279     assertThat(branchDto.get().getKey()).isEqualTo(pullRequestId);
280     assertThat(branchDto.get().getMergeBranchUuid()).isEqualTo("mergeBanchUuid");
281     assertThat(branchDto.get().getProjectUuid()).isEqualTo(MAIN.getUuid());
282     assertThat(branchDto.get().getPullRequestData()).isEqualTo(DbProjectBranches.PullRequestData.newBuilder()
283       .setBranch(pullRequestId)
284       .setTarget("mergeBanchUuid")
285       .setTitle(pullRequestId)
286       .build());
287   }
288
289   private static Branch createBranch(BranchType type, boolean isMain, String name) {
290     return createBranch(type, isMain, name, null);
291   }
292
293   private static Branch createPullRequest(String key, String mergeBranchUuid) {
294     Branch branch = createBranch(PULL_REQUEST, false, key, mergeBranchUuid);
295     when(branch.getPullRequestKey()).thenReturn(key);
296     return branch;
297   }
298
299   private static Branch createBranch(BranchType type, boolean isMain, String name, @Nullable String mergeBranchUuid) {
300     Branch branch = mock(Branch.class);
301     when(branch.getType()).thenReturn(type);
302     when(branch.getName()).thenReturn(name);
303     when(branch.isMain()).thenReturn(isMain);
304     when(branch.getReferenceBranchUuid()).thenReturn(mergeBranchUuid);
305     when(branch.getTargetBranchName()).thenReturn(mergeBranchUuid);
306     return branch;
307   }
308
309   private void expectMissingComponentISE(ThrowableAssert.ThrowingCallable callable) {
310     assertThatThrownBy(callable)
311       .isInstanceOf(IllegalStateException.class)
312       .hasMessage("Component has been deleted by end-user during analysis");
313   }
314
315   private void insertProjectProperty(ComponentDto project, String propertyKey, String propertyValue) {
316     dbTester.properties().insertProperties(new PropertyDto().setKey(propertyKey).setValue(propertyValue).setComponentUuid(project.uuid()));
317   }
318 }