You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BranchPersisterImplIT.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 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. import com.tngtech.java.junit.dataprovider.DataProvider;
  22. import com.tngtech.java.junit.dataprovider.DataProviderRunner;
  23. import com.tngtech.java.junit.dataprovider.UseDataProvider;
  24. import java.util.Collections;
  25. import java.util.Optional;
  26. import javax.annotation.Nullable;
  27. import org.assertj.core.api.ThrowableAssert;
  28. import org.junit.Rule;
  29. import org.junit.Test;
  30. import org.junit.runner.RunWith;
  31. import org.sonar.api.config.internal.ConfigurationBridge;
  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.component.ProjectData;
  43. import org.sonar.db.protobuf.DbProjectBranches;
  44. import org.sonar.server.project.Project;
  45. import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
  46. import static org.assertj.core.api.Assertions.assertThat;
  47. import static org.assertj.core.api.Assertions.assertThatThrownBy;
  48. import static org.mockito.Mockito.mock;
  49. import static org.mockito.Mockito.when;
  50. import static org.sonar.ce.task.projectanalysis.component.ReportComponent.builder;
  51. import static org.sonar.core.config.PurgeConstants.BRANCHES_TO_KEEP_WHEN_INACTIVE;
  52. import static org.sonar.db.component.BranchType.BRANCH;
  53. import static org.sonar.db.component.BranchType.PULL_REQUEST;
  54. @RunWith(DataProviderRunner.class)
  55. public class BranchPersisterImplIT {
  56. private final static Component MAIN = builder(Component.Type.PROJECT, 1, "PROJECT_KEY").setUuid("PROJECT_UUID").setName("p1").build();
  57. private final static Component BRANCH1 = builder(Component.Type.PROJECT, 2, "BRANCH_KEY").setUuid("BRANCH_UUID").build();
  58. private final static Component PR1 = builder(Component.Type.PROJECT, 3, "develop").setUuid("PR_UUID").build();
  59. private static final Project PROJECT = new Project("PROJECT_UUID", MAIN.getKey(), MAIN.getName(), null, Collections.emptyList());
  60. @Rule
  61. public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule();
  62. @Rule
  63. public DbTester dbTester = DbTester.create(System2.INSTANCE);
  64. @Rule
  65. public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
  66. private final MapSettings settings = new MapSettings();
  67. private final ConfigurationRepository configurationRepository = new TestSettingsRepository(new ConfigurationBridge(settings));
  68. private final BranchPersister underTest = new BranchPersisterImpl(dbTester.getDbClient(), treeRootHolder, analysisMetadataHolder, configurationRepository);
  69. @Test
  70. public void persist_fails_with_ISE_if_no_component_for_main_branches() {
  71. analysisMetadataHolder.setBranch(createBranch(BRANCH, true, "master"));
  72. analysisMetadataHolder.setProject(PROJECT);
  73. treeRootHolder.setRoot(MAIN);
  74. DbSession dbSession = dbTester.getSession();
  75. expectMissingComponentISE(() -> underTest.persist(dbSession));
  76. }
  77. @Test
  78. public void persist_fails_with_ISE_if_no_component_for_branches() {
  79. analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "foo"));
  80. analysisMetadataHolder.setProject(PROJECT);
  81. treeRootHolder.setRoot(BRANCH1);
  82. DbSession dbSession = dbTester.getSession();
  83. expectMissingComponentISE(() -> underTest.persist(dbSession));
  84. }
  85. @Test
  86. public void persist_fails_with_ISE_if_no_component_for_pull_request() {
  87. analysisMetadataHolder.setBranch(createBranch(BranchType.PULL_REQUEST, false, "12"));
  88. analysisMetadataHolder.setProject(PROJECT);
  89. treeRootHolder.setRoot(BRANCH1);
  90. DbSession dbSession = dbTester.getSession();
  91. expectMissingComponentISE(() -> underTest.persist(dbSession));
  92. }
  93. @Test
  94. @UseDataProvider("nullOrNotNullString")
  95. public void persist_creates_row_in_PROJECTS_BRANCHES_for_branch(@Nullable String mergeBranchUuid) {
  96. String branchName = "branch";
  97. // add project and branch in table PROJECTS
  98. ComponentDto mainComponent = ComponentTesting.newPrivateProjectDto(MAIN.getUuid()).setKey(MAIN.getKey());
  99. ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
  100. new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
  101. dbTester.components().insertComponents(mainComponent, component);
  102. // set project in metadata
  103. treeRootHolder.setRoot(BRANCH1);
  104. analysisMetadataHolder.setBranch(createBranch(BRANCH, false, branchName, mergeBranchUuid));
  105. analysisMetadataHolder.setProject(Project.from(mainComponent));
  106. underTest.persist(dbTester.getSession());
  107. dbTester.getSession().commit();
  108. assertThat(dbTester.countRowsOfTable("components")).isEqualTo(2);
  109. Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
  110. assertThat(branchDto).isPresent();
  111. assertThat(branchDto.get().getBranchType()).isEqualTo(BRANCH);
  112. assertThat(branchDto.get().getKey()).isEqualTo(branchName);
  113. assertThat(branchDto.get().getMergeBranchUuid()).isEqualTo(mergeBranchUuid);
  114. assertThat(branchDto.get().getProjectUuid()).isEqualTo(MAIN.getUuid());
  115. assertThat(branchDto.get().getPullRequestData()).isNull();
  116. }
  117. @Test
  118. public void main_branch_is_excluded_from_branch_purge_by_default() {
  119. analysisMetadataHolder.setBranch(createBranch(BRANCH, true, "master"));
  120. analysisMetadataHolder.setProject(PROJECT);
  121. treeRootHolder.setRoot(MAIN);
  122. dbTester.components().insertPublicProject(p -> p.setKey(MAIN.getKey()).setUuid(MAIN.getUuid())).getMainBranchComponent();
  123. dbTester.commit();
  124. underTest.persist(dbTester.getSession());
  125. Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), MAIN.getUuid());
  126. assertThat(branchDto).isPresent();
  127. assertThat(branchDto.get().isExcludeFromPurge()).isTrue();
  128. }
  129. @Test
  130. public void non_main_branch_is_excluded_from_branch_purge_if_matches_sonar_dbcleaner_keepFromPurge_property() {
  131. settings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "BRANCH.*");
  132. analysisMetadataHolder.setProject(PROJECT);
  133. analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "BRANCH_KEY"));
  134. treeRootHolder.setRoot(BRANCH1);
  135. ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setKey(MAIN.getKey()).setUuid(MAIN.getUuid())).getMainBranchComponent();
  136. ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
  137. new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
  138. dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component, false);
  139. dbTester.commit();
  140. underTest.persist(dbTester.getSession());
  141. Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
  142. assertThat(branchDto).isPresent();
  143. assertThat(branchDto.get().isExcludeFromPurge()).isTrue();
  144. }
  145. @Test
  146. public void branch_is_excluded_from_purge_when_it_matches_setting() {
  147. analysisMetadataHolder.setProject(PROJECT);
  148. analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "BRANCH_KEY"));
  149. treeRootHolder.setRoot(BRANCH1);
  150. ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setKey(MAIN.getKey()).setUuid(MAIN.getUuid())).getMainBranchComponent();
  151. ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
  152. new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
  153. dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component, false);
  154. settings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "BRANCH.*");
  155. dbTester.commit();
  156. underTest.persist(dbTester.getSession());
  157. Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
  158. assertThat(branchDto).isPresent();
  159. assertThat(branchDto.get().isExcludeFromPurge()).isTrue();
  160. }
  161. @Test
  162. public void branch_is_not_excluded_from_purge_when_it_does_not_match_setting() {
  163. analysisMetadataHolder.setProject(PROJECT);
  164. analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "BRANCH_KEY"));
  165. treeRootHolder.setRoot(BRANCH1);
  166. ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setKey(MAIN.getKey()).setUuid(MAIN.getUuid())).getMainBranchComponent();
  167. ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
  168. new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
  169. dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component, false);
  170. settings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "abc.*");
  171. dbTester.commit();
  172. underTest.persist(dbTester.getSession());
  173. Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
  174. assertThat(branchDto).isPresent();
  175. assertThat(branchDto.get().isExcludeFromPurge()).isFalse();
  176. }
  177. @Test
  178. public void pull_request_is_never_excluded_from_branch_purge_even_if_its_source_branch_name_matches_sonar_dbcleaner_keepFromPurge_property() {
  179. settings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "develop");
  180. analysisMetadataHolder.setBranch(createPullRequest(PR1.getKey(), MAIN.getUuid()));
  181. analysisMetadataHolder.setProject(PROJECT);
  182. analysisMetadataHolder.setPullRequestKey(PR1.getKey());
  183. treeRootHolder.setRoot(PR1);
  184. ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setKey(MAIN.getKey()).setUuid(MAIN.getUuid())).getMainBranchComponent();
  185. ComponentDto component = ComponentTesting.newBranchComponent(mainComponent, new BranchDto()
  186. .setUuid(PR1.getUuid())
  187. .setKey(PR1.getKey())
  188. .setProjectUuid(MAIN.getUuid())
  189. .setBranchType(PULL_REQUEST)
  190. .setMergeBranchUuid(MAIN.getUuid()));
  191. dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component, false);
  192. dbTester.commit();
  193. underTest.persist(dbTester.getSession());
  194. Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), PR1.getUuid());
  195. assertThat(branchDto).isPresent();
  196. assertThat(branchDto.get().isExcludeFromPurge()).isFalse();
  197. }
  198. @Test
  199. public void non_main_branch_is_included_in_branch_purge_if_branch_name_does_not_match_sonar_dbcleaner_keepFromPurge_property() {
  200. settings.setProperty(BRANCHES_TO_KEEP_WHEN_INACTIVE, "foobar-.*");
  201. analysisMetadataHolder.setProject(PROJECT);
  202. analysisMetadataHolder.setBranch(createBranch(BRANCH, false, "BRANCH_KEY"));
  203. treeRootHolder.setRoot(BRANCH1);
  204. ComponentDto mainComponent = dbTester.components().insertPublicProject(p -> p.setKey(MAIN.getKey()).setUuid(MAIN.getUuid())).getMainBranchComponent();
  205. ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
  206. new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(BRANCH));
  207. dbTester.getDbClient().componentDao().insert(dbTester.getSession(), component, false);
  208. dbTester.commit();
  209. underTest.persist(dbTester.getSession());
  210. Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
  211. assertThat(branchDto).isPresent();
  212. assertThat(branchDto.get().isExcludeFromPurge()).isFalse();
  213. }
  214. @DataProvider
  215. public static Object[][] nullOrNotNullString() {
  216. return new Object[][] {
  217. {null},
  218. {randomAlphabetic(12)}
  219. };
  220. }
  221. @Test
  222. public void persist_creates_row_in_PROJECTS_BRANCHES_for_pull_request() {
  223. String pullRequestId = "pr-123";
  224. // add project and branch in table PROJECTS
  225. ProjectData projectData = dbTester.components().insertPrivateProject(p -> p.setKey(MAIN.getKey()).setUuid(MAIN.getUuid()));
  226. ComponentDto mainComponent = projectData.getMainBranchComponent();
  227. ComponentDto component = ComponentTesting.newBranchComponent(mainComponent,
  228. new BranchDto().setUuid(BRANCH1.getUuid()).setKey(BRANCH1.getKey()).setBranchType(PULL_REQUEST));
  229. dbTester.components().insertComponents(component);
  230. // set project in metadata
  231. treeRootHolder.setRoot(BRANCH1);
  232. analysisMetadataHolder.setBranch(createBranch(PULL_REQUEST, false, pullRequestId, "mergeBanchUuid"));
  233. analysisMetadataHolder.setProject(Project.from(projectData.getProjectDto()));
  234. analysisMetadataHolder.setPullRequestKey(pullRequestId);
  235. underTest.persist(dbTester.getSession());
  236. dbTester.getSession().commit();
  237. assertThat(dbTester.countRowsOfTable("components")).isEqualTo(2);
  238. Optional<BranchDto> branchDto = dbTester.getDbClient().branchDao().selectByUuid(dbTester.getSession(), BRANCH1.getUuid());
  239. assertThat(branchDto).isPresent();
  240. assertThat(branchDto.get().getBranchType()).isEqualTo(PULL_REQUEST);
  241. assertThat(branchDto.get().getKey()).isEqualTo(pullRequestId);
  242. assertThat(branchDto.get().getMergeBranchUuid()).isEqualTo("mergeBanchUuid");
  243. assertThat(branchDto.get().getProjectUuid()).isEqualTo(projectData.projectUuid());
  244. assertThat(branchDto.get().getPullRequestData()).isEqualTo(DbProjectBranches.PullRequestData.newBuilder()
  245. .setBranch(pullRequestId)
  246. .setTarget("mergeBanchUuid")
  247. .setTitle(pullRequestId)
  248. .build());
  249. }
  250. private static Branch createBranch(BranchType type, boolean isMain, String name) {
  251. return createBranch(type, isMain, name, null);
  252. }
  253. private static Branch createPullRequest(String key, String mergeBranchUuid) {
  254. Branch branch = createBranch(PULL_REQUEST, false, key, mergeBranchUuid);
  255. when(branch.getPullRequestKey()).thenReturn(key);
  256. return branch;
  257. }
  258. private static Branch createBranch(BranchType type, boolean isMain, String name, @Nullable String mergeBranchUuid) {
  259. Branch branch = mock(Branch.class);
  260. when(branch.getType()).thenReturn(type);
  261. when(branch.getName()).thenReturn(name);
  262. when(branch.isMain()).thenReturn(isMain);
  263. when(branch.getReferenceBranchUuid()).thenReturn(mergeBranchUuid);
  264. when(branch.getTargetBranchName()).thenReturn(mergeBranchUuid);
  265. return branch;
  266. }
  267. private void expectMissingComponentISE(ThrowableAssert.ThrowingCallable callable) {
  268. assertThatThrownBy(callable)
  269. .isInstanceOf(IllegalStateException.class)
  270. .hasMessage("Component has been deleted by end-user during analysis");
  271. }
  272. }