3 * Copyright (C) 2009-2019 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.ce.task.projectanalysis.api.posttask;
22 import com.google.common.collect.ImmutableMap;
23 import com.tngtech.java.junit.dataprovider.DataProvider;
24 import com.tngtech.java.junit.dataprovider.DataProviderRunner;
25 import com.tngtech.java.junit.dataprovider.UseDataProvider;
26 import java.util.Date;
27 import java.util.List;
28 import java.util.Random;
29 import javax.annotation.Nullable;
30 import org.apache.commons.lang.RandomStringUtils;
31 import org.junit.Before;
32 import org.junit.Rule;
33 import org.junit.Test;
34 import org.junit.runner.RunWith;
35 import org.mockito.ArgumentCaptor;
36 import org.mockito.InOrder;
37 import org.sonar.api.ce.posttask.PostProjectAnalysisTask;
38 import org.sonar.api.ce.posttask.Project;
39 import org.sonar.api.utils.System2;
40 import org.sonar.ce.task.CeTask;
41 import org.sonar.ce.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
42 import org.sonar.ce.task.projectanalysis.analysis.Branch;
43 import org.sonar.ce.task.projectanalysis.analysis.Organization;
44 import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
45 import org.sonar.ce.task.projectanalysis.component.DefaultBranchImpl;
46 import org.sonar.ce.task.projectanalysis.metric.Metric;
47 import org.sonar.ce.task.projectanalysis.qualitygate.Condition;
48 import org.sonar.ce.task.projectanalysis.qualitygate.ConditionStatus;
49 import org.sonar.ce.task.projectanalysis.qualitygate.MutableQualityGateHolderRule;
50 import org.sonar.ce.task.projectanalysis.qualitygate.MutableQualityGateStatusHolderRule;
51 import org.sonar.ce.task.projectanalysis.qualitygate.QualityGate;
52 import org.sonar.ce.task.projectanalysis.qualitygate.QualityGateStatus;
53 import org.sonar.db.component.BranchType;
54 import org.sonar.db.organization.OrganizationDto;
55 import org.sonar.scanner.protocol.output.ScannerReport;
57 import static com.google.common.collect.ImmutableList.of;
58 import static java.util.Arrays.asList;
59 import static org.assertj.core.api.Assertions.assertThat;
60 import static org.assertj.core.data.MapEntry.entry;
61 import static org.mockito.ArgumentMatchers.any;
62 import static org.mockito.Mockito.doThrow;
63 import static org.mockito.Mockito.inOrder;
64 import static org.mockito.Mockito.mock;
65 import static org.mockito.Mockito.verify;
66 import static org.mockito.Mockito.when;
68 @RunWith(DataProviderRunner.class)
69 public class PostProjectAnalysisTasksExecutorTest {
70 private static final long QUALITY_GATE_ID = 98451;
71 private static final String QUALITY_GATE_NAME = "qualityGate name";
72 private static final Condition CONDITION_1 = createCondition("metric key 1");
73 private static final Condition CONDITION_2 = createCondition("metric key 2");
76 public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule();
78 public MutableQualityGateHolderRule qualityGateHolder = new MutableQualityGateHolderRule();
80 public MutableQualityGateStatusHolderRule qualityGateStatusHolder = new MutableQualityGateStatusHolderRule();
82 public BatchReportReaderRule reportReader = new BatchReportReaderRule();
84 private String organizationUuid = "org1";
85 private String organizationKey = organizationUuid + "_key";
86 private String organizationName = organizationUuid + "_name";
87 private System2 system2 = mock(System2.class);
88 private ArgumentCaptor<PostProjectAnalysisTask.ProjectAnalysis> projectAnalysisArgumentCaptor = ArgumentCaptor.forClass(PostProjectAnalysisTask.ProjectAnalysis.class);
89 private CeTask.Component component = new CeTask.Component("component uuid", "component key", "component name");
90 private CeTask ceTask = new CeTask.Builder()
91 .setOrganizationUuid(organizationUuid)
94 .setComponent(component)
95 .setMainComponent(component)
97 private PostProjectAnalysisTask postProjectAnalysisTask = mock(PostProjectAnalysisTask.class);
98 private PostProjectAnalysisTasksExecutor underTest = new PostProjectAnalysisTasksExecutor(
99 ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder,
100 reportReader, system2,
101 new PostProjectAnalysisTask[] {postProjectAnalysisTask});
104 public void setUp() throws Exception {
105 qualityGateHolder.setQualityGate(new QualityGate(QUALITY_GATE_ID, QUALITY_GATE_NAME, of(CONDITION_1, CONDITION_2)));
106 qualityGateStatusHolder.setStatus(QualityGateStatus.OK, ImmutableMap.of(
107 CONDITION_1, ConditionStatus.create(ConditionStatus.EvaluationStatus.OK, "value"),
108 CONDITION_2, ConditionStatus.NO_VALUE_STATUS));
109 Branch branch = mock(Branch.class);
110 when(branch.getType()).thenReturn(BranchType.LONG);
111 analysisMetadataHolder
113 .setOrganizationsEnabled(new Random().nextBoolean())
114 .setOrganization(Organization.from(
115 new OrganizationDto().setKey(organizationKey).setName(organizationName).setUuid(organizationUuid).setDefaultQualityGateUuid("foo")));
117 reportReader.setMetadata(ScannerReport.Metadata.newBuilder().build());
121 @UseDataProvider("booleanValues")
122 public void does_not_fail_when_there_is_no_PostProjectAnalysisTasksExecutor(boolean allStepsExecuted) {
123 new PostProjectAnalysisTasksExecutor(ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder, reportReader, system2)
124 .finished(allStepsExecuted);
128 @UseDataProvider("booleanValues")
129 public void finished_calls_all_PostProjectAnalysisTask_in_order_of_the_array_and_passes_the_same_object_to_all(boolean allStepsExecuted) {
130 PostProjectAnalysisTask postProjectAnalysisTask1 = mock(PostProjectAnalysisTask.class);
131 PostProjectAnalysisTask postProjectAnalysisTask2 = mock(PostProjectAnalysisTask.class);
132 InOrder inOrder = inOrder(postProjectAnalysisTask1, postProjectAnalysisTask2);
134 new PostProjectAnalysisTasksExecutor(
135 ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder, reportReader,
136 system2, new PostProjectAnalysisTask[] {postProjectAnalysisTask1, postProjectAnalysisTask2})
137 .finished(allStepsExecuted);
139 inOrder.verify(postProjectAnalysisTask1).finished(projectAnalysisArgumentCaptor.capture());
140 inOrder.verify(postProjectAnalysisTask2).finished(projectAnalysisArgumentCaptor.capture());
141 inOrder.verifyNoMoreInteractions();
143 List<PostProjectAnalysisTask.ProjectAnalysis> allValues = projectAnalysisArgumentCaptor.getAllValues();
144 assertThat(allValues).hasSize(2);
145 assertThat(allValues.get(0)).isSameAs(allValues.get(1));
149 @UseDataProvider("booleanValues")
150 public void organization_is_null_when_organization_are_disabled(boolean allStepsExecuted) {
151 analysisMetadataHolder
152 .setOrganizationsEnabled(false)
153 .setOrganization(Organization.from(
154 new OrganizationDto().setKey(organizationKey).setName(organizationName).setUuid(organizationUuid).setDefaultQualityGateUuid("foo")));
155 underTest.finished(allStepsExecuted);
157 verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());
159 assertThat(projectAnalysisArgumentCaptor.getValue().getOrganization()).isEmpty();
163 @UseDataProvider("booleanValues")
164 public void organization_is_not_null_when_organization_are_enabled(boolean allStepsExecuted) {
165 analysisMetadataHolder
166 .setOrganizationsEnabled(true)
167 .setOrganization(Organization.from(
168 new OrganizationDto().setKey(organizationKey).setName(organizationName).setUuid(organizationUuid).setDefaultQualityGateUuid("foo")));
169 underTest.finished(allStepsExecuted);
171 verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());
173 org.sonar.api.ce.posttask.Organization organization = projectAnalysisArgumentCaptor.getValue().getOrganization().get();
174 assertThat(organization.getKey()).isEqualTo(organizationKey);
175 assertThat(organization.getName()).isEqualTo(organizationName);
179 @UseDataProvider("booleanValues")
180 public void CeTask_status_depends_on_finished_method_argument_is_true_or_false(boolean allStepsExecuted) {
181 underTest.finished(allStepsExecuted);
183 verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());
185 assertThat(projectAnalysisArgumentCaptor.getValue().getCeTask().getStatus())
187 allStepsExecuted ? org.sonar.api.ce.posttask.CeTask.Status.SUCCESS : org.sonar.api.ce.posttask.CeTask.Status.FAILED);
191 public void ceTask_uuid_is_UUID_of_CeTask() {
192 underTest.finished(true);
194 verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());
196 assertThat(projectAnalysisArgumentCaptor.getValue().getCeTask().getId())
197 .isEqualTo(ceTask.getUuid());
201 public void project_uuid_key_and_name_come_from_CeTask() {
202 underTest.finished(true);
204 verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());
206 Project project = projectAnalysisArgumentCaptor.getValue().getProject();
207 assertThat(project.getUuid()).isEqualTo(ceTask.getComponent().get().getUuid());
208 assertThat(project.getKey()).isEqualTo(ceTask.getComponent().get().getKey().get());
209 assertThat(project.getName()).isEqualTo(ceTask.getComponent().get().getName().get());
213 public void date_comes_from_AnalysisMetadataHolder() {
214 analysisMetadataHolder.setAnalysisDate(8_465_132_498L);
215 analysisMetadataHolder.setUuid(RandomStringUtils.randomAlphanumeric(40));
217 underTest.finished(true);
219 verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());
221 assertThat(projectAnalysisArgumentCaptor.getValue().getDate())
222 .isEqualTo(new Date(analysisMetadataHolder.getAnalysisDate()));
226 public void date_comes_from_system2_if_not_set_in_AnalysisMetadataHolder() {
227 long now = 1_999_663L;
228 when(system2.now()).thenReturn(now);
230 underTest.finished(false);
232 verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());
234 assertThat(projectAnalysisArgumentCaptor.getValue().getDate()).isEqualTo(new Date(now));
238 public void analysisDate_and_analysisUuid_comes_from_AnalysisMetadataHolder_when_set() {
239 analysisMetadataHolder.setAnalysisDate(8465132498L);
240 analysisMetadataHolder.setUuid(RandomStringUtils.randomAlphanumeric(40));
242 underTest.finished(true);
244 verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());
246 assertThat(projectAnalysisArgumentCaptor.getValue().getAnalysis().get().getDate())
247 .isEqualTo(new Date(analysisMetadataHolder.getAnalysisDate()));
248 assertThat(projectAnalysisArgumentCaptor.getValue().getAnalysis().get().getAnalysisUuid())
249 .isEqualTo(analysisMetadataHolder.getUuid());
253 public void analysis_is_empty_when_not_set_in_AnalysisMetadataHolder() {
254 underTest.finished(false);
256 verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());
258 assertThat(projectAnalysisArgumentCaptor.getValue().getAnalysis()).isEmpty();
262 public void branch_is_empty_when_legacy_branch_implementation_is_used() {
263 analysisMetadataHolder.setBranch(new DefaultBranchImpl("feature/foo"));
265 underTest.finished(true);
267 verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());
269 assertThat(projectAnalysisArgumentCaptor.getValue().getBranch()).isEmpty();
273 public void branch_comes_from_AnalysisMetadataHolder_when_set() {
274 analysisMetadataHolder.setBranch(new Branch() {
276 public BranchType getType() {
277 return BranchType.SHORT;
281 public boolean isMain() {
286 public boolean isLegacyFeature() {
291 public String getMergeBranchUuid() {
292 throw new UnsupportedOperationException();
296 public String getName() {
297 return "feature/foo";
301 public boolean supportsCrossProjectCpd() {
302 throw new UnsupportedOperationException();
306 public String getPullRequestKey() {
307 throw new UnsupportedOperationException();
311 public String getTargetBranchName() {
312 throw new UnsupportedOperationException();
316 public String generateKey(String projectKey, @Nullable String fileOrDirPath) {
317 throw new UnsupportedOperationException();
321 underTest.finished(true);
323 verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());
325 org.sonar.api.ce.posttask.Branch branch = projectAnalysisArgumentCaptor.getValue().getBranch().get();
326 assertThat(branch.isMain()).isFalse();
327 assertThat(branch.getName()).hasValue("feature/foo");
328 assertThat(branch.getType()).isEqualTo(BranchImpl.Type.SHORT);
332 public void qualityGate_is_null_when_finished_method_argument_is_false() {
333 underTest.finished(false);
335 verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());
337 assertThat(projectAnalysisArgumentCaptor.getValue().getQualityGate()).isNull();
341 public void qualityGate_is_populated_when_finished_method_argument_is_true() {
342 underTest.finished(true);
344 verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());
346 org.sonar.api.ce.posttask.QualityGate qualityGate = projectAnalysisArgumentCaptor.getValue().getQualityGate();
347 assertThat(qualityGate.getStatus()).isEqualTo(org.sonar.api.ce.posttask.QualityGate.Status.OK);
348 assertThat(qualityGate.getId()).isEqualTo(String.valueOf(QUALITY_GATE_ID));
349 assertThat(qualityGate.getName()).isEqualTo(QUALITY_GATE_NAME);
350 assertThat(qualityGate.getConditions()).hasSize(2);
354 public void scannerContext_loads_properties_from_scanner_report() {
355 reportReader.putContextProperties(asList(ScannerReport.ContextProperty.newBuilder().setKey("foo").setValue("bar").build()));
356 underTest.finished(true);
358 verify(postProjectAnalysisTask).finished(projectAnalysisArgumentCaptor.capture());
360 org.sonar.api.ce.posttask.ScannerContext scannerContext = projectAnalysisArgumentCaptor.getValue().getScannerContext();
361 assertThat(scannerContext.getProperties()).containsExactly(entry("foo", "bar"));
365 @UseDataProvider("booleanValues")
366 public void finished_does_not_fail_if_listener_throws_exception_and_execute_subsequent_listeners(boolean allStepsExecuted) {
367 PostProjectAnalysisTask postProjectAnalysisTask1 = mock(PostProjectAnalysisTask.class);
368 PostProjectAnalysisTask postProjectAnalysisTask2 = mock(PostProjectAnalysisTask.class);
369 PostProjectAnalysisTask postProjectAnalysisTask3 = mock(PostProjectAnalysisTask.class);
370 InOrder inOrder = inOrder(postProjectAnalysisTask1, postProjectAnalysisTask2, postProjectAnalysisTask3);
372 doThrow(new RuntimeException("Faking a listener throws an exception"))
373 .when(postProjectAnalysisTask2)
374 .finished(any(PostProjectAnalysisTask.ProjectAnalysis.class));
376 new PostProjectAnalysisTasksExecutor(
377 ceTask, analysisMetadataHolder, qualityGateHolder, qualityGateStatusHolder, reportReader,
378 system2, new PostProjectAnalysisTask[] {postProjectAnalysisTask1, postProjectAnalysisTask2, postProjectAnalysisTask3})
379 .finished(allStepsExecuted);
381 inOrder.verify(postProjectAnalysisTask1).finished(projectAnalysisArgumentCaptor.capture());
382 inOrder.verify(postProjectAnalysisTask2).finished(projectAnalysisArgumentCaptor.capture());
383 inOrder.verify(postProjectAnalysisTask3).finished(projectAnalysisArgumentCaptor.capture());
384 inOrder.verifyNoMoreInteractions();
388 public static Object[][] booleanValues() {
389 return new Object[][] {
395 private static Condition createCondition(String metricKey) {
396 Metric metric = mock(Metric.class);
397 when(metric.getKey()).thenReturn(metricKey);
398 return new Condition(metric, Condition.Operator.LESS_THAN.getDbValue(), "error threshold");