]> source.dussan.org Git - sonarqube.git/blob
c9cab2dc339006b2ebe1cb46d0aa3313800ef322
[sonarqube.git] /
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
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.component.ProjectData;
41 import org.sonar.server.es.EsIndexSyncInProgressException;
42
43 import static org.assertj.core.api.Assertions.assertThat;
44 import static org.assertj.core.api.Assertions.assertThatThrownBy;
45 import static org.sonar.db.ce.CeActivityDto.Status.FAILED;
46 import static org.sonar.db.ce.CeActivityDto.Status.SUCCESS;
47
48 @RunWith(DataProviderRunner.class)
49 public class IssueIndexSyncProgressCheckerTest {
50
51   private final System2 system2 = new System2();
52
53   @Rule
54   public DbTester db = DbTester.create(System2.INSTANCE);
55
56   private final IssueIndexSyncProgressChecker underTest = new IssueIndexSyncProgressChecker(db.getDbClient());
57
58   @Test
59   public void return_100_if_there_is_no_tasks_left() {
60     IssueSyncProgress issueSyncProgress = underTest.getIssueSyncProgress(db.getSession());
61     assertThat(issueSyncProgress.getCompleted()).isZero();
62     assertThat(issueSyncProgress.getTotal()).isZero();
63     assertThat(issueSyncProgress.toPercentCompleted()).isEqualTo(100);
64     assertThat(issueSyncProgress.isCompleted()).isTrue();
65     assertThat(issueSyncProgress.hasFailures()).isFalse();
66   }
67
68   @Test
69   public void return_100_if_all_branches_have_need_issue_sync_set_FALSE() {
70     IntStream.range(0, 13).forEach(value -> insertProjectWithBranches(false, 2));
71     IntStream.range(0, 14).forEach(value -> insertProjectWithBranches(false, 4));
72     IntStream.range(0, 4).forEach(value -> insertProjectWithBranches(false, 10));
73
74     IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
75     assertThat(result.getCompleted()).isEqualTo(153);
76     assertThat(result.getTotal()).isEqualTo(153);
77     assertThat(result.toPercentCompleted()).isEqualTo(100);
78     assertThat(result.isCompleted()).isTrue();
79   }
80
81   @Test
82   public void return_has_failure_true_if_exists_task() {
83     assertThat(underTest.getIssueSyncProgress(db.getSession()).hasFailures()).isFalse();
84
85     ProjectData projectData1 = insertProjectWithBranches(false, 0);
86     insertCeActivity("TASK_1", projectData1, SUCCESS);
87
88     ProjectData projectData2 = insertProjectWithBranches(false, 0);
89     insertCeActivity("TASK_2", projectData2, SUCCESS);
90
91     assertThat(underTest.getIssueSyncProgress(db.getSession()).hasFailures()).isFalse();
92
93     ProjectData projectData3 = insertProjectWithBranches(true, 0);
94     insertCeActivity("TASK_3", projectData3, FAILED);
95
96     assertThat(underTest.getIssueSyncProgress(db.getSession()).hasFailures()).isTrue();
97   }
98
99   @Test
100   @UseDataProvider("various_task_numbers")
101   public void return_correct_percent_value_for_branches_to_sync(int toSync, int synced, int expectedPercent) {
102     IntStream.range(0, toSync).forEach(value -> insertProjectWithBranches(true, 0));
103     IntStream.range(0, synced).forEach(value -> insertProjectWithBranches(false, 0));
104
105     IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
106     assertThat(result.getCompleted()).isEqualTo(synced);
107     assertThat(result.getTotal()).isEqualTo(toSync + synced);
108     assertThat(result.toPercentCompleted()).isEqualTo(expectedPercent);
109   }
110
111   @DataProvider
112   public static Object[][] various_task_numbers() {
113     return new Object[][] {
114       // toSync, synced, expected result
115       {0, 0, 100},
116       {0, 9, 100},
117       {10, 0, 0},
118       {99, 1, 1},
119       {2, 1, 33},
120       {6, 4, 40},
121       {7, 7, 50},
122       {1, 2, 66},
123       {4, 10, 71},
124       {1, 99, 99},
125     };
126   }
127
128   @Test
129   public void return_0_if_all_branches_have_need_issue_sync_set_true() {
130     // only project
131     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 0));
132
133     // project + additional branch
134     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 1));
135
136     IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
137     assertThat(result.getCompleted()).isZero();
138     assertThat(result.getTotal()).isEqualTo(30);
139     assertThat(result.toPercentCompleted()).isZero();
140   }
141
142   @Test
143   public void return_is_completed_true_if_no_pending_or_in_progress_tasks() {
144     // only project
145     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 0));
146
147     // project + additional branch
148     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
149
150     IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
151     assertThat(result.isCompleted()).isTrue();
152   }
153
154   @Test
155   public void return_is_completed_true_if_pending_task_exist_but_all_branches_have_been_synced() {
156     insertCeQueue("TASK_1", Status.PENDING);
157     // only project
158     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 0));
159
160     // project + additional branch
161     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
162
163     IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
164     assertThat(result.isCompleted()).isTrue();
165   }
166
167   @Test
168   public void return_is_completed_true_if_in_progress_task_exist_but_all_branches_have_been_synced() {
169     insertCeQueue("TASK_1", Status.IN_PROGRESS);
170     // only project
171     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 0));
172
173     // project + additional branch
174     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
175
176     IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
177     assertThat(result.isCompleted()).isTrue();
178   }
179
180   @Test
181   public void return_is_completed_false_if_pending_task_exist_and_branches_need_issue_sync() {
182     insertCeQueue("TASK_1", Status.PENDING);
183     // only project
184     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 0));
185
186     // project + additional branch
187     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
188
189     IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
190     assertThat(result.isCompleted()).isFalse();
191   }
192
193   @Test
194   public void return_is_completed_false_if_in_progress_task_exist_and_branches_need_issue_sync() {
195     insertCeQueue("TASK_1", Status.IN_PROGRESS);
196     // only project
197     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 0));
198
199     // project + additional branch
200     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
201
202     IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
203     assertThat(result.isCompleted()).isFalse();
204   }
205
206   @Test
207   public void checkIfAnyComponentsNeedIssueSync_throws_exception_if_all_components_have_need_issue_sync_TRUE() {
208     ProjectData projectData1 = insertProjectWithBranches(true, 0);
209     ProjectData projectData2 = insertProjectWithBranches(true, 0);
210     DbSession session = db.getSession();
211     List<String> projectKeys = Arrays.asList(projectData1.getProjectDto().getKey(), projectData2.getProjectDto().getKey());
212     assertThatThrownBy(() -> underTest.checkIfAnyComponentsNeedIssueSync(session, projectKeys))
213       .isInstanceOf(EsIndexSyncInProgressException.class)
214       .hasFieldOrPropertyWithValue("httpCode", 503)
215       .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
216   }
217
218   @Test
219   public void checkIfAnyComponentsNeedIssueSync_does_not_throw_exception_if_all_components_have_need_issue_sync_FALSE() {
220     underTest.checkIfAnyComponentsNeedIssueSync(db.getSession(), Collections.emptyList());
221     ProjectData projectData1 = insertProjectWithBranches(false, 0);
222     ProjectData projectData2 = insertProjectWithBranches(false, 0);
223     underTest.checkIfAnyComponentsNeedIssueSync(db.getSession(), Arrays.asList(projectData1.getProjectDto().getKey(), projectData2.getProjectDto().getKey()));
224   }
225
226   @Test
227   public void checkIfAnyComponentsNeedIssueSync_throws_exception_if_at_least_one_component_has_need_issue_sync_TRUE() {
228     ProjectData projectData1 = insertProjectWithBranches(false, 0);
229     ProjectData projectData2 = insertProjectWithBranches(true, 0);
230
231     DbSession session = db.getSession();
232     List<String> projectKeys = Arrays.asList(projectData1.getProjectDto().getKey(), projectData2.getProjectDto().getKey());
233     assertThatThrownBy(() -> underTest.checkIfAnyComponentsNeedIssueSync(session, projectKeys))
234       .isInstanceOf(EsIndexSyncInProgressException.class)
235       .hasFieldOrPropertyWithValue("httpCode", 503)
236       .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
237   }
238
239   @Test
240   public void checkIfComponentNeedIssueSync_single_component() {
241     ProjectData projectData1 = insertProjectWithBranches(true, 0);
242     ProjectData projectData2 = insertProjectWithBranches(false, 0);
243
244     DbSession session = db.getSession();
245     // do nothing when need issue sync false
246     underTest.checkIfComponentNeedIssueSync(session, projectData2.getProjectDto().getKey());
247
248     // throws if flag set to TRUE
249     String key = projectData1.getProjectDto().getKey();
250     assertThatThrownBy(() -> underTest.checkIfComponentNeedIssueSync(session, key))
251       .isInstanceOf(EsIndexSyncInProgressException.class)
252       .hasFieldOrPropertyWithValue("httpCode", 503)
253       .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
254   }
255
256   @Test
257   public void checkIfAnyComponentsNeedIssueSync_single_view_subview_or_app() {
258     ProjectData projectData1 = insertProjectWithBranches(true, 0);
259
260     ComponentDto app = db.components().insertPublicApplication().getMainBranchComponent();
261     ComponentDto view = db.components().insertPrivatePortfolio();
262     ComponentDto subview = db.components().insertSubView(view);
263
264     DbSession session = db.getSession();
265     List<String> appViewOrSubviewKeys = Arrays.asList(projectData1.getProjectDto().getKey(), app.getKey(), view.getKey(), subview.getKey());
266
267     // throws if flag set to TRUE
268     assertThatThrownBy(() -> underTest.checkIfAnyComponentsNeedIssueSync(session,
269       appViewOrSubviewKeys))
270         .isInstanceOf(EsIndexSyncInProgressException.class)
271         .hasFieldOrPropertyWithValue("httpCode", 503)
272         .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
273   }
274
275   @Test
276   public void checkIfIssueSyncInProgress_throws_exception_if_at_least_one_component_has_need_issue_sync_TRUE() {
277     insertProjectWithBranches(false, 0);
278     underTest.checkIfIssueSyncInProgress(db.getSession());
279     insertProjectWithBranches(true, 0);
280
281     DbSession session = db.getSession();
282     assertThatThrownBy(() -> underTest.checkIfIssueSyncInProgress(session))
283       .isInstanceOf(EsIndexSyncInProgressException.class)
284       .hasFieldOrPropertyWithValue("httpCode", 503)
285       .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
286   }
287
288   @Test
289   public void doProjectNeedIssueSync() {
290     ProjectData projectData1 = insertProjectWithBranches(false, 0);
291     assertThat(underTest.doProjectNeedIssueSync(db.getSession(), projectData1.getProjectDto().getUuid())).isFalse();
292     ProjectData projectData2 = insertProjectWithBranches(true, 0);
293     assertThat(underTest.doProjectNeedIssueSync(db.getSession(), projectData2.getProjectDto().getUuid())).isTrue();
294   }
295
296   @Test
297   public void findProjectUuidsWithIssuesSyncNeed() {
298     ProjectData projectData1 = insertProjectWithBranches(false, 0);
299     ProjectData projectData2 = insertProjectWithBranches(false, 0);
300     ProjectData projectData3 = insertProjectWithBranches(true, 0);
301     ProjectData projectData4 = insertProjectWithBranches(true, 0);
302
303     assertThat(underTest.findProjectUuidsWithIssuesSyncNeed(db.getSession(),
304       Arrays.asList(projectData1.getProjectDto().getUuid(), projectData2.getProjectDto().getUuid(), projectData3.getProjectDto().getUuid(), projectData4.getProjectDto().getUuid())))
305         .containsOnly(projectData3.getProjectDto().getUuid(), projectData4.getProjectDto().getUuid());
306   }
307
308   private ProjectData insertProjectWithBranches(boolean needIssueSync, int numberOfBranches) {
309     ProjectData projectData = db.components()
310       .insertPrivateProject(branchDto -> branchDto.setNeedIssueSync(needIssueSync), c -> {
311       }, p -> {
312       });
313     IntStream.range(0, numberOfBranches).forEach(
314       i -> db.components().insertProjectBranch(projectData.getProjectDto(), branchDto -> branchDto.setNeedIssueSync(needIssueSync)));
315     return projectData;
316   }
317
318   private CeQueueDto insertCeQueue(String uuid, CeQueueDto.Status status) {
319     CeQueueDto queueDto = new CeQueueDto();
320     queueDto.setUuid(uuid);
321     queueDto.setStatus(status);
322     queueDto.setTaskType(CeTaskTypes.BRANCH_ISSUE_SYNC);
323     db.getDbClient().ceQueueDao().insert(db.getSession(), queueDto);
324     return queueDto;
325   }
326
327   private CeActivityDto insertCeActivity(String uuid, ProjectData projectData, CeActivityDto.Status status) {
328     CeQueueDto queueDto = new CeQueueDto();
329     queueDto.setUuid(uuid);
330     queueDto.setTaskType(CeTaskTypes.BRANCH_ISSUE_SYNC);
331
332     CeActivityDto dto = new CeActivityDto(queueDto);
333     dto.setComponentUuid(projectData.getMainBranchComponent().uuid());
334     dto.setEntityUuid(projectData.projectUuid());
335     dto.setStatus(status);
336     dto.setTaskType(CeTaskTypes.BRANCH_ISSUE_SYNC);
337     dto.setAnalysisUuid(uuid + "_AA");
338     dto.setCreatedAt(system2.now());
339     db.getDbClient().ceActivityDao().insert(db.getSession(), dto);
340     return dto;
341   }
342 }