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.

IssueIndexSyncProgressCheckerTest.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 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.server.issue.index;
  21. import com.tngtech.java.junit.dataprovider.DataProviderRunner;
  22. import java.util.Arrays;
  23. import java.util.Collections;
  24. import java.util.List;
  25. import java.util.stream.IntStream;
  26. import org.junit.Rule;
  27. import org.junit.Test;
  28. import org.junit.runner.RunWith;
  29. import org.sonar.api.utils.System2;
  30. import org.sonar.db.DbSession;
  31. import org.sonar.db.DbTester;
  32. import org.sonar.db.ce.CeActivityDto;
  33. import org.sonar.db.ce.CeQueueDto;
  34. import org.sonar.db.ce.CeQueueDto.Status;
  35. import org.sonar.db.ce.CeTaskTypes;
  36. import org.sonar.db.component.ComponentDto;
  37. import org.sonar.db.component.ProjectData;
  38. import org.sonar.server.es.EsIndexSyncInProgressException;
  39. import static org.assertj.core.api.Assertions.assertThat;
  40. import static org.assertj.core.api.Assertions.assertThatThrownBy;
  41. import static org.sonar.db.ce.CeActivityDto.Status.FAILED;
  42. import static org.sonar.db.ce.CeActivityDto.Status.SUCCESS;
  43. @RunWith(DataProviderRunner.class)
  44. public class IssueIndexSyncProgressCheckerTest {
  45. private final System2 system2 = new System2();
  46. @Rule
  47. public DbTester db = DbTester.create(System2.INSTANCE);
  48. private final IssueIndexSyncProgressChecker underTest = new IssueIndexSyncProgressChecker(db.getDbClient());
  49. @Test
  50. public void getIssueSyncProgress_whenNoTasksLeft_shouldReturnCompleted() {
  51. IssueSyncProgress issueSyncProgress = underTest.getIssueSyncProgress(db.getSession());
  52. assertThat(issueSyncProgress.getCompletedCount()).isZero();
  53. assertThat(issueSyncProgress.getTotal()).isZero();
  54. assertThat(issueSyncProgress.isCompleted()).isTrue();
  55. assertThat(issueSyncProgress.hasFailures()).isFalse();
  56. }
  57. @Test
  58. public void getIssueSyncProgress_whenNoBranchesNeedsIssueSync_shouldReturnCompleted() {
  59. IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
  60. IntStream.range(0, 20).forEach(value -> insertProjectWithBranches(false, 2));
  61. IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
  62. assertThat(result.getCompletedCount()).isEqualTo(30);
  63. assertThat(result.getTotal()).isEqualTo(30);
  64. assertThat(result.isCompleted()).isTrue();
  65. }
  66. @Test
  67. public void getIssueSyncProgress_whenTasksExist_shouldReturnFailures() {
  68. assertThat(underTest.getIssueSyncProgress(db.getSession()).hasFailures()).isFalse();
  69. ProjectData projectData1 = insertProjectWithBranches(false, 0);
  70. insertCeActivity("TASK_1", projectData1, SUCCESS);
  71. ProjectData projectData2 = insertProjectWithBranches(false, 0);
  72. insertCeActivity("TASK_2", projectData2, SUCCESS);
  73. assertThat(underTest.getIssueSyncProgress(db.getSession()).hasFailures()).isFalse();
  74. ProjectData projectData3 = insertProjectWithBranches(true, 0);
  75. insertCeActivity("TASK_3", projectData3, FAILED);
  76. assertThat(underTest.getIssueSyncProgress(db.getSession()).hasFailures()).isTrue();
  77. }
  78. @Test
  79. public void getIssueSyncProgress_whenBranchesNeedIssueSync_shouldReturnNotCompleted() {
  80. insertCeQueue("TASK_1", Status.PENDING);
  81. // only project
  82. IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 0));
  83. // project + additional branch
  84. IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 1));
  85. IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
  86. assertThat(result.getCompletedCount()).isZero();
  87. assertThat(result.getTotal()).isEqualTo(20);
  88. assertThat(result.isCompleted()).isFalse();
  89. }
  90. @Test
  91. public void return_is_completed_true_if_no_pending_or_in_progress_tasks() {
  92. // only project
  93. IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 0));
  94. // project + additional branch
  95. IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
  96. IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
  97. assertThat(result.isCompleted()).isTrue();
  98. }
  99. @Test
  100. public void return_is_completed_true_if_pending_task_exist_but_all_branches_have_been_synced() {
  101. insertCeQueue("TASK_1", Status.PENDING);
  102. // only project
  103. IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 0));
  104. // project + additional branch
  105. IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
  106. IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
  107. assertThat(result.isCompleted()).isTrue();
  108. }
  109. @Test
  110. public void return_is_completed_true_if_in_progress_task_exist_but_all_branches_have_been_synced() {
  111. insertCeQueue("TASK_1", Status.IN_PROGRESS);
  112. // only project
  113. IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 0));
  114. // project + additional branch
  115. IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
  116. IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
  117. assertThat(result.isCompleted()).isTrue();
  118. }
  119. @Test
  120. public void return_is_completed_false_if_pending_task_exist_and_branches_need_issue_sync() {
  121. insertCeQueue("TASK_1", Status.PENDING);
  122. // only project
  123. IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 0));
  124. // project + additional branch
  125. IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
  126. IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
  127. assertThat(result.isCompleted()).isFalse();
  128. }
  129. @Test
  130. public void return_is_completed_false_if_in_progress_task_exist_and_branches_need_issue_sync() {
  131. insertCeQueue("TASK_1", Status.IN_PROGRESS);
  132. // only project
  133. IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 0));
  134. // project + additional branch
  135. IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
  136. IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
  137. assertThat(result.isCompleted()).isFalse();
  138. }
  139. @Test
  140. public void checkIfAnyComponentsNeedIssueSync_throws_exception_if_all_components_have_need_issue_sync_TRUE() {
  141. ProjectData projectData1 = insertProjectWithBranches(true, 0);
  142. ProjectData projectData2 = insertProjectWithBranches(true, 0);
  143. DbSession session = db.getSession();
  144. List<String> projectKeys = Arrays.asList(projectData1.getProjectDto().getKey(), projectData2.getProjectDto().getKey());
  145. assertThatThrownBy(() -> underTest.checkIfAnyComponentsNeedIssueSync(session, projectKeys))
  146. .isInstanceOf(EsIndexSyncInProgressException.class)
  147. .hasFieldOrPropertyWithValue("httpCode", 503)
  148. .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
  149. }
  150. @Test
  151. public void checkIfAnyComponentsNeedIssueSync_does_not_throw_exception_if_all_components_have_need_issue_sync_FALSE() {
  152. underTest.checkIfAnyComponentsNeedIssueSync(db.getSession(), Collections.emptyList());
  153. ProjectData projectData1 = insertProjectWithBranches(false, 0);
  154. ProjectData projectData2 = insertProjectWithBranches(false, 0);
  155. underTest.checkIfAnyComponentsNeedIssueSync(db.getSession(), Arrays.asList(projectData1.getProjectDto().getKey(), projectData2.getProjectDto().getKey()));
  156. }
  157. @Test
  158. public void checkIfAnyComponentsNeedIssueSync_throws_exception_if_at_least_one_component_has_need_issue_sync_TRUE() {
  159. ProjectData projectData1 = insertProjectWithBranches(false, 0);
  160. ProjectData projectData2 = insertProjectWithBranches(true, 0);
  161. DbSession session = db.getSession();
  162. List<String> projectKeys = Arrays.asList(projectData1.getProjectDto().getKey(), projectData2.getProjectDto().getKey());
  163. assertThatThrownBy(() -> underTest.checkIfAnyComponentsNeedIssueSync(session, projectKeys))
  164. .isInstanceOf(EsIndexSyncInProgressException.class)
  165. .hasFieldOrPropertyWithValue("httpCode", 503)
  166. .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
  167. }
  168. @Test
  169. public void checkIfComponentNeedIssueSync_single_component() {
  170. ProjectData projectData1 = insertProjectWithBranches(true, 0);
  171. ProjectData projectData2 = insertProjectWithBranches(false, 0);
  172. DbSession session = db.getSession();
  173. // do nothing when need issue sync false
  174. underTest.checkIfComponentNeedIssueSync(session, projectData2.getProjectDto().getKey());
  175. // throws if flag set to TRUE
  176. String key = projectData1.getProjectDto().getKey();
  177. assertThatThrownBy(() -> underTest.checkIfComponentNeedIssueSync(session, key))
  178. .isInstanceOf(EsIndexSyncInProgressException.class)
  179. .hasFieldOrPropertyWithValue("httpCode", 503)
  180. .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
  181. }
  182. @Test
  183. public void checkIfAnyComponentsNeedIssueSync_single_view_subview_or_app() {
  184. ProjectData projectData1 = insertProjectWithBranches(true, 0);
  185. ComponentDto app = db.components().insertPublicApplication().getMainBranchComponent();
  186. ComponentDto view = db.components().insertPrivatePortfolio();
  187. ComponentDto subview = db.components().insertSubView(view);
  188. DbSession session = db.getSession();
  189. List<String> appViewOrSubviewKeys = Arrays.asList(projectData1.getProjectDto().getKey(), app.getKey(), view.getKey(), subview.getKey());
  190. // throws if flag set to TRUE
  191. assertThatThrownBy(() -> underTest.checkIfAnyComponentsNeedIssueSync(session,
  192. appViewOrSubviewKeys))
  193. .isInstanceOf(EsIndexSyncInProgressException.class)
  194. .hasFieldOrPropertyWithValue("httpCode", 503)
  195. .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
  196. }
  197. @Test
  198. public void checkIfIssueSyncInProgress_throws_exception_if_at_least_one_component_has_need_issue_sync_TRUE() {
  199. insertProjectWithBranches(false, 0);
  200. underTest.checkIfIssueSyncInProgress(db.getSession());
  201. insertProjectWithBranches(true, 0);
  202. DbSession session = db.getSession();
  203. assertThatThrownBy(() -> underTest.checkIfIssueSyncInProgress(session))
  204. .isInstanceOf(EsIndexSyncInProgressException.class)
  205. .hasFieldOrPropertyWithValue("httpCode", 503)
  206. .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
  207. }
  208. @Test
  209. public void doProjectNeedIssueSync() {
  210. ProjectData projectData1 = insertProjectWithBranches(false, 0);
  211. assertThat(underTest.doProjectNeedIssueSync(db.getSession(), projectData1.getProjectDto().getUuid())).isFalse();
  212. ProjectData projectData2 = insertProjectWithBranches(true, 0);
  213. assertThat(underTest.doProjectNeedIssueSync(db.getSession(), projectData2.getProjectDto().getUuid())).isTrue();
  214. }
  215. @Test
  216. public void findProjectUuidsWithIssuesSyncNeed() {
  217. ProjectData projectData1 = insertProjectWithBranches(false, 0);
  218. ProjectData projectData2 = insertProjectWithBranches(false, 0);
  219. ProjectData projectData3 = insertProjectWithBranches(true, 0);
  220. ProjectData projectData4 = insertProjectWithBranches(true, 0);
  221. assertThat(underTest.findProjectUuidsWithIssuesSyncNeed(db.getSession(),
  222. Arrays.asList(projectData1.getProjectDto().getUuid(), projectData2.getProjectDto().getUuid(), projectData3.getProjectDto().getUuid(), projectData4.getProjectDto().getUuid())))
  223. .containsOnly(projectData3.getProjectDto().getUuid(), projectData4.getProjectDto().getUuid());
  224. }
  225. private ProjectData insertProjectWithBranches(boolean needIssueSync, int numberOfBranches) {
  226. ProjectData projectData = db.components()
  227. .insertPrivateProject(branchDto -> branchDto.setNeedIssueSync(needIssueSync), c -> {
  228. }, p -> {
  229. });
  230. IntStream.range(0, numberOfBranches).forEach(
  231. i -> db.components().insertProjectBranch(projectData.getProjectDto(), branchDto -> branchDto.setNeedIssueSync(needIssueSync)));
  232. return projectData;
  233. }
  234. private CeQueueDto insertCeQueue(String uuid, CeQueueDto.Status status) {
  235. CeQueueDto queueDto = new CeQueueDto();
  236. queueDto.setUuid(uuid);
  237. queueDto.setStatus(status);
  238. queueDto.setTaskType(CeTaskTypes.BRANCH_ISSUE_SYNC);
  239. db.getDbClient().ceQueueDao().insert(db.getSession(), queueDto);
  240. return queueDto;
  241. }
  242. private CeActivityDto insertCeActivity(String uuid, ProjectData projectData, CeActivityDto.Status status) {
  243. CeQueueDto queueDto = new CeQueueDto();
  244. queueDto.setUuid(uuid);
  245. queueDto.setTaskType(CeTaskTypes.BRANCH_ISSUE_SYNC);
  246. CeActivityDto dto = new CeActivityDto(queueDto);
  247. dto.setComponentUuid(projectData.getMainBranchComponent().uuid());
  248. dto.setEntityUuid(projectData.projectUuid());
  249. dto.setStatus(status);
  250. dto.setTaskType(CeTaskTypes.BRANCH_ISSUE_SYNC);
  251. dto.setAnalysisUuid(uuid + "_AA");
  252. dto.setCreatedAt(system2.now());
  253. db.getDbClient().ceActivityDao().insert(db.getSession(), dto);
  254. return dto;
  255. }
  256. }