3 * Copyright (C) 2009-2020 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.issue.index;
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.Arrays;
26 import java.util.Collections;
27 import java.util.List;
28 import java.util.stream.IntStream;
29 import org.junit.Rule;
30 import org.junit.Test;
31 import org.junit.runner.RunWith;
32 import org.sonar.api.utils.System2;
33 import org.sonar.db.DbSession;
34 import org.sonar.db.DbTester;
35 import org.sonar.db.ce.CeActivityDto;
36 import org.sonar.db.ce.CeQueueDto;
37 import org.sonar.db.ce.CeQueueDto.Status;
38 import org.sonar.db.ce.CeTaskTypes;
39 import org.sonar.db.component.ComponentDto;
40 import org.sonar.db.project.ProjectDto;
41 import org.sonar.server.es.EsIndexSyncInProgressException;
43 import static java.util.Collections.singletonList;
44 import static org.assertj.core.api.Assertions.assertThat;
45 import static org.assertj.core.api.Assertions.assertThatThrownBy;
46 import static org.sonar.db.ce.CeActivityDto.Status.FAILED;
47 import static org.sonar.db.ce.CeActivityDto.Status.SUCCESS;
49 @RunWith(DataProviderRunner.class)
50 public class IssueIndexSyncProgressCheckerTest {
52 private System2 system2 = new System2();
55 public DbTester db = DbTester.create(System2.INSTANCE);
57 private IssueIndexSyncProgressChecker underTest = new IssueIndexSyncProgressChecker(db.getDbClient());
60 public void return_100_if_there_is_no_tasks_left() {
61 IssueSyncProgress issueSyncProgress = underTest.getIssueSyncProgress(db.getSession());
62 assertThat(issueSyncProgress.getCompleted()).isZero();
63 assertThat(issueSyncProgress.getTotal()).isZero();
64 assertThat(issueSyncProgress.toPercentCompleted()).isEqualTo(100);
65 assertThat(issueSyncProgress.isCompleted()).isTrue();
66 assertThat(issueSyncProgress.hasFailures()).isFalse();
70 public void return_100_if_all_branches_have_need_issue_sync_set_FALSE() {
71 IntStream.range(0, 13).forEach(value -> insertProjectWithBranches(false, 2));
72 IntStream.range(0, 14).forEach(value -> insertProjectWithBranches(false, 4));
73 IntStream.range(0, 4).forEach(value -> insertProjectWithBranches(false, 10));
75 IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
76 assertThat(result.getCompleted()).isEqualTo(153);
77 assertThat(result.getTotal()).isEqualTo(153);
78 assertThat(result.toPercentCompleted()).isEqualTo(100);
79 assertThat(result.isCompleted()).isTrue();
83 public void return_has_failure_true_if_exists_task() {
84 assertThat(underTest.getIssueSyncProgress(db.getSession()).hasFailures()).isFalse();
86 ProjectDto projectDto1 = insertProjectWithBranches(false, 0);
87 insertCeActivity("TASK_1", projectDto1, SUCCESS);
89 ProjectDto projectDto2 = insertProjectWithBranches(false, 0);
90 insertCeActivity("TASK_2", projectDto2, SUCCESS);
92 assertThat(underTest.getIssueSyncProgress(db.getSession()).hasFailures()).isFalse();
94 ProjectDto projectDto3 = insertProjectWithBranches(true, 0);
95 insertCeActivity("TASK_3", projectDto3, FAILED);
97 assertThat(underTest.getIssueSyncProgress(db.getSession()).hasFailures()).isTrue();
101 @UseDataProvider("various_task_numbers")
102 public void return_correct_percent_value_for_branches_to_sync(int toSync, int synced, int expectedPercent) {
103 IntStream.range(0, toSync).forEach(value -> insertProjectWithBranches(true, 0));
104 IntStream.range(0, synced).forEach(value -> insertProjectWithBranches(false, 0));
106 IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
107 assertThat(result.getCompleted()).isEqualTo(synced);
108 assertThat(result.getTotal()).isEqualTo(toSync + synced);
109 assertThat(result.toPercentCompleted()).isEqualTo(expectedPercent);
113 public static Object[][] various_task_numbers() {
114 return new Object[][] {
115 // toSync, synced, expected result
130 public void return_0_if_all_branches_have_need_issue_sync_set_true() {
132 IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 0));
134 // project + additional branch
135 IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 1));
137 IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
138 assertThat(result.getCompleted()).isZero();
139 assertThat(result.getTotal()).isEqualTo(30);
140 assertThat(result.toPercentCompleted()).isZero();
144 public void return_is_completed_true_if_no_pending_or_in_progress_tasks() {
146 IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 0));
148 // project + additional branch
149 IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
151 IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
152 assertThat(result.isCompleted()).isTrue();
156 public void return_is_completed_true_if_pending_task_exist_but_all_branches_have_been_synced() {
157 insertCeQueue("TASK_1", Status.PENDING);
159 IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 0));
161 // project + additional branch
162 IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
164 IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
165 assertThat(result.isCompleted()).isTrue();
169 public void return_is_completed_true_if_in_progress_task_exist_but_all_branches_have_been_synced() {
170 insertCeQueue("TASK_1", Status.IN_PROGRESS);
172 IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 0));
174 // project + additional branch
175 IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
177 IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
178 assertThat(result.isCompleted()).isTrue();
182 public void return_is_completed_false_if_pending_task_exist_and_branches_need_issue_sync() {
183 insertCeQueue("TASK_1", Status.PENDING);
185 IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 0));
187 // project + additional branch
188 IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
190 IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
191 assertThat(result.isCompleted()).isFalse();
195 public void return_is_completed_false_if_in_progress_task_exist_and_branches_need_issue_sync() {
196 insertCeQueue("TASK_1", Status.IN_PROGRESS);
198 IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 0));
200 // project + additional branch
201 IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
203 IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
204 assertThat(result.isCompleted()).isFalse();
208 public void checkIfAnyComponentsIssueSyncInProgress_throws_exception_if_all_components_have_need_issue_sync_TRUE() {
209 ProjectDto projectDto1 = insertProjectWithBranches(true, 0);
210 ProjectDto projectDto2 = insertProjectWithBranches(true, 0);
211 DbSession session = db.getSession();
212 List<String> projectKeys = Arrays.asList(projectDto1.getKey(), projectDto2.getKey());
213 assertThatThrownBy(() -> underTest.checkIfAnyComponentsNeedIssueSync(session, projectKeys))
214 .isInstanceOf(EsIndexSyncInProgressException.class)
215 .hasFieldOrPropertyWithValue("httpCode", 503)
216 .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
220 public void checkIfAnyComponentsIssueSyncInProgress_does_not_throw_exception_if_all_components_have_need_issue_sync_FALSE() {
221 underTest.checkIfAnyComponentsNeedIssueSync(db.getSession(), Collections.emptyList());
222 ProjectDto projectDto1 = insertProjectWithBranches(false, 0);
223 ProjectDto projectDto2 = insertProjectWithBranches(false, 0);
224 underTest.checkIfAnyComponentsNeedIssueSync(db.getSession(), Arrays.asList(projectDto1.getKey(), projectDto2.getKey()));
228 public void checkIfAnyComponentsIssueSyncInProgress_throws_exception_if_at_least_one_component_has_need_issue_sync_TRUE() {
229 ProjectDto projectDto1 = insertProjectWithBranches(false, 0);
230 ProjectDto projectDto2 = insertProjectWithBranches(true, 0);
232 DbSession session = db.getSession();
233 List<String> projectKeys = Arrays.asList(projectDto1.getKey(), projectDto2.getKey());
234 assertThatThrownBy(() -> underTest.checkIfAnyComponentsNeedIssueSync(session, projectKeys))
235 .isInstanceOf(EsIndexSyncInProgressException.class)
236 .hasFieldOrPropertyWithValue("httpCode", 503)
237 .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
241 public void checkIfAnyComponentsIssueSyncInProgress_single_component() {
242 ProjectDto projectDto1 = insertProjectWithBranches(true, 0);
243 ProjectDto projectDto2 = insertProjectWithBranches(false, 0);
245 DbSession session = db.getSession();
246 List<String> projectKey1 = singletonList(projectDto2.getKey());
247 // do nothing when need issue sync false
248 underTest.checkIfAnyComponentsNeedIssueSync(session, projectKey1);
250 List<String> projectKey2 = singletonList(projectDto1.getKey());
251 // throws if flag set to TRUE
252 assertThatThrownBy(() -> underTest.checkIfAnyComponentsNeedIssueSync(session,
254 .isInstanceOf(EsIndexSyncInProgressException.class)
255 .hasFieldOrPropertyWithValue("httpCode", 503)
256 .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
260 public void checkIfAnyComponentsNeedIssueSync_single_view_subview_or_app() {
261 ProjectDto projectDto1 = insertProjectWithBranches(true, 0);
263 ComponentDto app = db.components().insertPublicApplication();
264 ComponentDto view = db.components().insertPrivatePortfolio();
265 ComponentDto subview = db.components().insertSubView(view);
267 DbSession session = db.getSession();
268 List<String> appViewOrSubviewKeys = Arrays.asList(projectDto1.getKey(), app.getDbKey(), view.getDbKey(), subview.getDbKey());
270 // throws if flag set to TRUE
271 assertThatThrownBy(() -> underTest.checkIfAnyComponentsNeedIssueSync(session,
272 appViewOrSubviewKeys))
273 .isInstanceOf(EsIndexSyncInProgressException.class)
274 .hasFieldOrPropertyWithValue("httpCode", 503)
275 .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
279 public void checkIfIssueSyncInProgress_throws_exception_if_at_least_one_component_has_need_issue_sync_TRUE() {
280 insertProjectWithBranches(false, 0);
281 underTest.checkIfIssueSyncInProgress(db.getSession());
282 insertProjectWithBranches(true, 0);
284 DbSession session = db.getSession();
285 assertThatThrownBy(() -> underTest.checkIfIssueSyncInProgress(session))
286 .isInstanceOf(EsIndexSyncInProgressException.class)
287 .hasFieldOrPropertyWithValue("httpCode", 503)
288 .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
292 public void doProjectNeedIssueSync() {
293 ProjectDto projectDto1 = insertProjectWithBranches(false, 0);
294 assertThat(underTest.doProjectNeedIssueSync(db.getSession(), projectDto1.getUuid())).isFalse();
295 ProjectDto projectDto2 = insertProjectWithBranches(true, 0);
296 assertThat(underTest.doProjectNeedIssueSync(db.getSession(), projectDto2.getUuid())).isTrue();
300 public void findProjectUuidsWithIssuesSyncNeed() {
301 ProjectDto projectDto1 = insertProjectWithBranches(false, 0);
302 ProjectDto projectDto2 = insertProjectWithBranches(false, 0);
303 ProjectDto projectDto3 = insertProjectWithBranches(true, 0);
304 ProjectDto projectDto4 = insertProjectWithBranches(true, 0);
306 assertThat(underTest.findProjectUuidsWithIssuesSyncNeed(db.getSession(),
307 Arrays.asList(projectDto1.getUuid(), projectDto2.getUuid(), projectDto3.getUuid(), projectDto4.getUuid())))
308 .containsOnly(projectDto3.getUuid(), projectDto4.getUuid());
311 private ProjectDto insertProjectWithBranches(boolean needIssueSync, int numberOfBranches) {
312 ProjectDto projectDto = db.components()
313 .insertPrivateProjectDto(db.getDefaultOrganization(), branchDto -> branchDto.setNeedIssueSync(needIssueSync));
314 IntStream.range(0, numberOfBranches).forEach(
315 i -> db.components().insertProjectBranch(projectDto, branchDto -> branchDto.setNeedIssueSync(needIssueSync)));
319 private CeQueueDto insertCeQueue(String uuid, CeQueueDto.Status status) {
320 CeQueueDto queueDto = new CeQueueDto();
321 queueDto.setUuid(uuid);
322 queueDto.setStatus(status);
323 queueDto.setTaskType(CeTaskTypes.BRANCH_ISSUE_SYNC);
324 db.getDbClient().ceQueueDao().insert(db.getSession(), queueDto);
328 private CeActivityDto insertCeActivity(String uuid, ProjectDto projectDto, CeActivityDto.Status status) {
329 CeQueueDto queueDto = new CeQueueDto();
330 queueDto.setUuid(uuid);
331 queueDto.setTaskType(CeTaskTypes.BRANCH_ISSUE_SYNC);
333 CeActivityDto dto = new CeActivityDto(queueDto);
334 dto.setComponentUuid(projectDto.getUuid());
335 dto.setMainComponentUuid(projectDto.getUuid());
336 dto.setStatus(status);
337 dto.setTaskType(CeTaskTypes.BRANCH_ISSUE_SYNC);
338 dto.setAnalysisUuid(uuid + "_AA");
339 dto.setCreatedAt(system2.now());
340 db.getDbClient().ceActivityDao().insert(db.getSession(), dto);