]> source.dussan.org Git - sonarqube.git/blob
254d2f58ba59b7715e21dd8dba43db717f33106c
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2020 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.project.ProjectDto;
41 import org.sonar.server.es.EsIndexSyncInProgressException;
42
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;
48
49 @RunWith(DataProviderRunner.class)
50 public class IssueIndexSyncProgressCheckerTest {
51
52   private System2 system2 = new System2();
53
54   @Rule
55   public DbTester db = DbTester.create(System2.INSTANCE);
56
57   private IssueIndexSyncProgressChecker underTest = new IssueIndexSyncProgressChecker(db.getDbClient());
58
59   @Test
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();
67   }
68
69   @Test
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));
74
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();
80   }
81
82   @Test
83   public void return_has_failure_true_if_exists_task() {
84     assertThat(underTest.getIssueSyncProgress(db.getSession()).hasFailures()).isFalse();
85
86     ProjectDto projectDto1 = insertProjectWithBranches(false, 0);
87     insertCeActivity("TASK_1", projectDto1, SUCCESS);
88
89     ProjectDto projectDto2 = insertProjectWithBranches(false, 0);
90     insertCeActivity("TASK_2", projectDto2, SUCCESS);
91
92     assertThat(underTest.getIssueSyncProgress(db.getSession()).hasFailures()).isFalse();
93
94     ProjectDto projectDto3 = insertProjectWithBranches(true, 0);
95     insertCeActivity("TASK_3", projectDto3, FAILED);
96
97     assertThat(underTest.getIssueSyncProgress(db.getSession()).hasFailures()).isTrue();
98   }
99
100   @Test
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));
105
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);
110   }
111
112   @DataProvider
113   public static Object[][] various_task_numbers() {
114     return new Object[][] {
115       // toSync, synced, expected result
116       {0, 0, 100},
117       {0, 9, 100},
118       {10, 0, 0},
119       {99, 1, 1},
120       {2, 1, 33},
121       {6, 4, 40},
122       {7, 7, 50},
123       {1, 2, 66},
124       {4, 10, 71},
125       {1, 99, 99},
126     };
127   }
128
129   @Test
130   public void return_0_if_all_branches_have_need_issue_sync_set_true() {
131     // only project
132     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 0));
133
134     // project + additional branch
135     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 1));
136
137     IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
138     assertThat(result.getCompleted()).isZero();
139     assertThat(result.getTotal()).isEqualTo(30);
140     assertThat(result.toPercentCompleted()).isZero();
141   }
142
143   @Test
144   public void return_is_completed_true_if_no_pending_or_in_progress_tasks() {
145     // only project
146     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 0));
147
148     // project + additional branch
149     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
150
151     IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
152     assertThat(result.isCompleted()).isTrue();
153   }
154
155   @Test
156   public void return_is_completed_true_if_pending_task_exist_but_all_branches_have_been_synced() {
157     insertCeQueue("TASK_1", Status.PENDING);
158     // only project
159     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 0));
160
161     // project + additional branch
162     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
163
164     IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
165     assertThat(result.isCompleted()).isTrue();
166   }
167
168   @Test
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);
171     // only project
172     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 0));
173
174     // project + additional branch
175     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
176
177     IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
178     assertThat(result.isCompleted()).isTrue();
179   }
180
181   @Test
182   public void return_is_completed_false_if_pending_task_exist_and_branches_need_issue_sync() {
183     insertCeQueue("TASK_1", Status.PENDING);
184     // only project
185     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 0));
186
187     // project + additional branch
188     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
189
190     IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
191     assertThat(result.isCompleted()).isFalse();
192   }
193
194   @Test
195   public void return_is_completed_false_if_in_progress_task_exist_and_branches_need_issue_sync() {
196     insertCeQueue("TASK_1", Status.IN_PROGRESS);
197     // only project
198     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(true, 0));
199
200     // project + additional branch
201     IntStream.range(0, 10).forEach(value -> insertProjectWithBranches(false, 1));
202
203     IssueSyncProgress result = underTest.getIssueSyncProgress(db.getSession());
204     assertThat(result.isCompleted()).isFalse();
205   }
206
207   @Test
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.");
217   }
218
219   @Test
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()));
225   }
226
227   @Test
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);
231
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.");
238   }
239
240   @Test
241   public void checkIfAnyComponentsIssueSyncInProgress_single_component() {
242     ProjectDto projectDto1 = insertProjectWithBranches(true, 0);
243     ProjectDto projectDto2 = insertProjectWithBranches(false, 0);
244
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);
249
250     List<String> projectKey2 = singletonList(projectDto1.getKey());
251     // throws if flag set to TRUE
252     assertThatThrownBy(() -> underTest.checkIfAnyComponentsNeedIssueSync(session,
253       projectKey2))
254         .isInstanceOf(EsIndexSyncInProgressException.class)
255         .hasFieldOrPropertyWithValue("httpCode", 503)
256         .hasMessage("Results are temporarily unavailable. Indexing of issues is in progress.");
257   }
258
259   @Test
260   public void checkIfAnyComponentsNeedIssueSync_single_view_subview_or_app() {
261     ProjectDto projectDto1 = insertProjectWithBranches(true, 0);
262
263     ComponentDto app = db.components().insertPublicApplication();
264     ComponentDto view = db.components().insertPrivatePortfolio();
265     ComponentDto subview = db.components().insertSubView(view);
266
267     DbSession session = db.getSession();
268     List<String> appViewOrSubviewKeys = Arrays.asList(projectDto1.getKey(), app.getDbKey(), view.getDbKey(), subview.getDbKey());
269
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.");
276   }
277
278   @Test
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);
283
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.");
289   }
290
291   @Test
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();
297   }
298
299   @Test
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);
305
306     assertThat(underTest.findProjectUuidsWithIssuesSyncNeed(db.getSession(),
307       Arrays.asList(projectDto1.getUuid(), projectDto2.getUuid(), projectDto3.getUuid(), projectDto4.getUuid())))
308         .containsOnly(projectDto3.getUuid(), projectDto4.getUuid());
309   }
310
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)));
316     return projectDto;
317   }
318
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);
325     return queueDto;
326   }
327
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);
332
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);
341     return dto;
342   }
343 }