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 java.util.Arrays;
23 import java.util.Collection;
24 import java.util.HashSet;
25 import java.util.List;
26 import java.util.Optional;
27 import org.junit.Before;
28 import org.junit.Rule;
29 import org.junit.Test;
30 import org.mockito.ArgumentCaptor;
31 import org.sonar.api.utils.System2;
32 import org.sonar.api.utils.log.LogTester;
33 import org.sonar.api.utils.log.LoggerLevel;
34 import org.sonar.ce.queue.CeQueue;
35 import org.sonar.ce.queue.CeTaskSubmit;
36 import org.sonar.core.util.SequenceUuidFactory;
37 import org.sonar.core.util.UuidFactory;
38 import org.sonar.db.DbClient;
39 import org.sonar.db.DbTester;
40 import org.sonar.db.ce.CeActivityDto;
41 import org.sonar.db.ce.CeActivityDto.Status;
42 import org.sonar.db.ce.CeQueueDto;
43 import org.sonar.db.ce.CeTaskCharacteristicDto;
44 import org.sonar.db.component.BranchDto;
45 import org.sonar.db.component.SnapshotDto;
47 import static org.assertj.core.api.Assertions.assertThat;
48 import static org.assertj.core.api.Assertions.tuple;
49 import static org.mockito.ArgumentMatchers.anyCollection;
50 import static org.mockito.Mockito.mock;
51 import static org.mockito.Mockito.times;
52 import static org.mockito.Mockito.verify;
53 import static org.mockito.Mockito.when;
54 import static org.sonar.db.ce.CeTaskCharacteristicDto.BRANCH_TYPE_KEY;
55 import static org.sonar.db.ce.CeTaskTypes.BRANCH_ISSUE_SYNC;
56 import static org.sonar.db.ce.CeTaskTypes.REPORT;
57 import static org.sonar.db.component.BranchType.BRANCH;
58 import static org.sonar.db.component.BranchType.PULL_REQUEST;
59 import static org.sonar.db.component.SnapshotDto.STATUS_PROCESSED;
61 public class AsyncIssueIndexingImplTest {
64 public DbTester dbTester = DbTester.create(System2.INSTANCE);
66 public LogTester logTester = new LogTester();
68 private DbClient dbClient = dbTester.getDbClient();
69 private CeQueue ceQueue = mock(CeQueue.class);
70 private UuidFactory uuidFactory = new SequenceUuidFactory();
72 private final AsyncIssueIndexingImpl underTest = new AsyncIssueIndexingImpl(ceQueue, dbClient);
75 public void before() {
76 when(ceQueue.prepareSubmit()).thenReturn(new CeTaskSubmit.Builder(uuidFactory.create()));
80 public void triggerOnIndexCreation() {
81 BranchDto dto = new BranchDto()
82 .setBranchType(BRANCH)
84 .setUuid("branch_uuid")
85 .setProjectUuid("project_uuid");
86 dbClient.branchDao().insert(dbTester.getSession(), dto);
89 underTest.triggerOnIndexCreation();
91 Optional<BranchDto> branch = dbClient.branchDao().selectByUuid(dbTester.getSession(), "branch_uuid");
92 assertThat(branch).isPresent();
93 assertThat(branch.get().isNeedIssueSync()).isTrue();
94 verify(ceQueue, times(1)).prepareSubmit();
95 verify(ceQueue, times(1)).massSubmit(anyCollection());
96 assertThat(logTester.logs(LoggerLevel.INFO))
97 .contains("1 branch found in need of issue sync : BranchDto{uuid='branch_uuid', projectUuid='project_uuid'," +
98 " kee='branchName', keyType=BRANCH, branchType=BRANCH, mergeBranchUuid='null', excludeFromPurge=false, needIssueSync=true}");
102 public void triggerOnIndexCreation_no_branch() {
103 underTest.triggerOnIndexCreation();
105 assertThat(logTester.logs(LoggerLevel.INFO)).contains("No branch found in need of issue sync");
109 public void remove_existing_indexation_task() {
110 CeQueueDto reportTask = new CeQueueDto();
111 reportTask.setUuid("uuid_1");
112 reportTask.setTaskType(REPORT);
113 dbClient.ceQueueDao().insert(dbTester.getSession(), reportTask);
115 CeActivityDto reportActivity = new CeActivityDto(reportTask);
116 reportActivity.setStatus(Status.SUCCESS);
117 dbClient.ceActivityDao().insert(dbTester.getSession(), reportActivity);
118 CeQueueDto task = new CeQueueDto();
119 task.setUuid("uuid_2");
120 task.setTaskType(BRANCH_ISSUE_SYNC);
121 dbClient.ceQueueDao().insert(dbTester.getSession(), task);
123 CeActivityDto activityDto = new CeActivityDto(task);
124 activityDto.setStatus(Status.SUCCESS);
125 dbClient.ceActivityDao().insert(dbTester.getSession(), activityDto);
129 underTest.triggerOnIndexCreation();
131 assertThat(dbClient.ceQueueDao().selectAllInAscOrder(dbTester.getSession())).extracting("uuid")
132 .containsExactly(reportTask.getUuid());
133 assertThat(dbClient.ceActivityDao().selectByTaskType(dbTester.getSession(), BRANCH_ISSUE_SYNC)).isEmpty();
135 assertThat(dbClient.ceActivityDao().selectByTaskType(dbTester.getSession(), REPORT)).hasSize(1);
137 assertThat(dbClient.ceTaskCharacteristicsDao().selectByTaskUuids(dbTester.getSession(), new HashSet<>(Arrays.asList("uuid_2")))).hasSize(0);
139 assertThat(logTester.logs(LoggerLevel.INFO))
141 "1 pending indexation task found to be deleted...",
142 "1 completed indexation task found to be deleted...",
143 "Indexation task deletion complete.",
144 "Deleting tasks characteristics...",
145 "Tasks characteristics deletion complete.");
149 public void order_by_last_analysis_date() {
150 BranchDto dto = new BranchDto()
151 .setBranchType(BRANCH)
153 .setUuid("branch_uuid1")
154 .setProjectUuid("project_uuid1");
155 dbClient.branchDao().insert(dbTester.getSession(), dto);
157 insertSnapshot("analysis_1", "project_uuid1", 1);
159 BranchDto dto2 = new BranchDto()
160 .setBranchType(BRANCH)
162 .setUuid("branch_uuid2")
163 .setProjectUuid("project_uuid2");
164 dbClient.branchDao().insert(dbTester.getSession(), dto2);
166 insertSnapshot("analysis_2", "project_uuid2", 2);
168 underTest.triggerOnIndexCreation();
170 verify(ceQueue, times(2)).prepareSubmit();
172 ArgumentCaptor<Collection<CeTaskSubmit>> captor = ArgumentCaptor.forClass(Collection.class);
174 verify(ceQueue, times(1)).massSubmit(captor.capture());
175 List<Collection<CeTaskSubmit>> captures = captor.getAllValues();
176 assertThat(captures).hasSize(1);
177 Collection<CeTaskSubmit> tasks = captures.get(0);
178 assertThat(tasks).hasSize(2);
180 .extracting(p -> p.getComponent().get().getUuid())
181 .containsExactly("branch_uuid2", "branch_uuid1");
183 assertThat(logTester.logs(LoggerLevel.INFO))
184 .contains("2 projects found in need of issue sync.");
188 public void characteristics_are_defined() {
189 BranchDto dto = new BranchDto()
190 .setBranchType(BRANCH)
192 .setUuid("branch_uuid1")
193 .setProjectUuid("project_uuid1");
194 dbClient.branchDao().insert(dbTester.getSession(), dto);
196 insertSnapshot("analysis_1", "project_uuid1", 1);
198 BranchDto dto2 = new BranchDto()
199 .setBranchType(PULL_REQUEST)
201 .setUuid("pr_uuid_1")
202 .setProjectUuid("project_uuid2");
203 dbClient.branchDao().insert(dbTester.getSession(), dto2);
205 insertSnapshot("analysis_2", "project_uuid2", 2);
207 underTest.triggerOnIndexCreation();
209 ArgumentCaptor<Collection<CeTaskSubmit>> captor = ArgumentCaptor.forClass(Collection.class);
210 verify(ceQueue, times(1)).massSubmit(captor.capture());
211 List<Collection<CeTaskSubmit>> captures = captor.getAllValues();
212 assertThat(captures).hasSize(1);
213 Collection<CeTaskSubmit> tasks = captures.get(0);
214 assertThat(tasks).hasSize(2);
217 .extracting(p -> p.getCharacteristics().get(BRANCH_TYPE_KEY),
218 p -> p.getCharacteristics().get(CeTaskCharacteristicDto.BRANCH_KEY),
219 p -> p.getCharacteristics().get(CeTaskCharacteristicDto.PULL_REQUEST))
220 .containsExactlyInAnyOrder(
221 tuple("BRANCH", "branch_1", null),
222 tuple("PULL_REQUEST", null, "pr_1"));
225 private SnapshotDto insertSnapshot(String analysisUuid, String projectUuid, long createdAt) {
226 SnapshotDto snapshot = new SnapshotDto()
227 .setUuid(analysisUuid)
228 .setComponentUuid(projectUuid)
229 .setStatus(STATUS_PROCESSED)
230 .setCreatedAt(createdAt)
232 dbTester.getDbClient().snapshotDao().insert(dbTester.getSession(), snapshot);