]> source.dussan.org Git - sonarqube.git/blob
76d916163e3326e217d5893b57237bbb0d92b3ac
[sonarqube.git] /
1 /*
2  * SonarQube
3  * Copyright (C) 2009-2024 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.ce.task.projectanalysis.step;
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.HashMap;
26 import java.util.Map;
27 import java.util.Optional;
28 import javax.annotation.Nullable;
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.ce.task.projectanalysis.analysis.Branch;
34 import org.sonar.ce.task.projectanalysis.analysis.MutableAnalysisMetadataHolderRule;
35 import org.sonar.ce.task.projectanalysis.batch.BatchReportReaderRule;
36 import org.sonar.ce.task.projectanalysis.component.Component;
37 import org.sonar.ce.task.projectanalysis.component.DefaultBranchImpl;
38 import org.sonar.ce.task.projectanalysis.component.MutableTreeRootHolderRule;
39 import org.sonar.ce.task.step.TestComputationStepContext;
40 import org.sonar.db.DbClient;
41 import org.sonar.db.DbTester;
42 import org.sonar.db.component.BranchType;
43 import org.sonar.db.component.ComponentDto;
44 import org.sonar.db.component.SnapshotDto;
45 import org.sonar.scanner.protocol.output.ScannerReport;
46 import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType;
47 import org.sonar.scanner.protocol.output.ScannerReport.Component.FileStatus;
48 import org.sonar.server.project.Project;
49
50 import static java.util.Optional.ofNullable;
51 import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
52 import static org.apache.commons.lang3.RandomStringUtils.randomAlphanumeric;
53 import static org.assertj.core.api.Assertions.assertThat;
54 import static org.assertj.core.api.Assertions.assertThatThrownBy;
55 import static org.mockito.ArgumentMatchers.any;
56 import static org.mockito.Mockito.mock;
57 import static org.mockito.Mockito.when;
58 import static org.sonar.db.component.BranchDto.DEFAULT_MAIN_BRANCH_NAME;
59 import static org.sonar.db.component.ComponentTesting.newDirectory;
60 import static org.sonar.db.component.ComponentTesting.newFileDto;
61 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
62 import static org.sonar.db.component.SnapshotTesting.newAnalysis;
63 import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.FILE;
64 import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.PROJECT;
65
66 @RunWith(DataProviderRunner.class)
67 public class BuildComponentTreeStepIT {
68   private static final String NO_SCANNER_PROJECT_VERSION = null;
69   private static final String NO_SCANNER_BUILD_STRING = null;
70
71   private static final int ROOT_REF = 1;
72   private static final int FILE_1_REF = 4;
73   private static final int FILE_2_REF = 5;
74   private static final int FILE_3_REF = 7;
75   private static final int UNCHANGED_FILE_REF = 10;
76
77   private static final String REPORT_PROJECT_KEY = "REPORT_PROJECT_KEY";
78   private static final String REPORT_DIR_PATH_1 = "src/main/java/dir1";
79   private static final String REPORT_FILE_PATH_1 = "src/main/java/dir1/File1.java";
80   private static final String REPORT_FILE_NAME_1 = "File1.java";
81   private static final String REPORT_DIR_PATH_2 = "src/main/java/dir2";
82   private static final String REPORT_FILE_PATH_2 = "src/main/java/dir2/File2.java";
83   private static final String REPORT_FILE_PATH_3 = "src/main/java/dir2/File3.java";
84   private static final String REPORT_UNCHANGED_FILE_PATH = "src/main/File3.java";
85
86   private static final long ANALYSIS_DATE = 123456789L;
87
88   @Rule
89   public DbTester dbTester = DbTester.create(System2.INSTANCE);
90   @Rule
91   public BatchReportReaderRule reportReader = new BatchReportReaderRule().setMetadata(createReportMetadata(NO_SCANNER_PROJECT_VERSION, NO_SCANNER_BUILD_STRING));
92   @Rule
93   public MutableTreeRootHolderRule treeRootHolder = new MutableTreeRootHolderRule();
94   @Rule
95   public MutableAnalysisMetadataHolderRule analysisMetadataHolder = new MutableAnalysisMetadataHolderRule();
96
97   private DbClient dbClient = dbTester.getDbClient();
98   private BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder);
99
100   @Test
101   public void fails_if_root_component_does_not_exist_in_reportReader() {
102     setAnalysisMetadataHolder();
103
104     assertThatThrownBy(() -> underTest.execute(new TestComputationStepContext()))
105       .isInstanceOf(NullPointerException.class);
106   }
107
108   @Test
109   public void verify_tree_is_correctly_built() {
110     setAnalysisMetadataHolder();
111     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, FILE_1_REF, FILE_2_REF, FILE_3_REF));
112     reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_PATH_1));
113     reportReader.putComponent(componentWithPath(FILE_2_REF, FILE, REPORT_FILE_PATH_2));
114     reportReader.putComponent(componentWithPath(FILE_3_REF, FILE, REPORT_FILE_PATH_3));
115
116     TestComputationStepContext context = new TestComputationStepContext();
117     underTest.execute(context);
118
119     Component root = treeRootHolder.getRoot();
120     assertThat(root).isNotNull();
121     verifyComponent(root, Component.Type.PROJECT, ROOT_REF, 1);
122
123     Component dir = root.getChildren().iterator().next();
124     verifyComponent(dir, Component.Type.DIRECTORY, null, 2);
125
126     Component dir1 = dir.getChildren().get(0);
127     verifyComponent(dir1, Component.Type.DIRECTORY, null, 1);
128     verifyComponent(dir1.getChildren().get(0), Component.Type.FILE, FILE_1_REF, 0);
129
130     Component dir2 = dir.getChildren().get(1);
131     verifyComponent(dir2, Component.Type.DIRECTORY, null, 2);
132     verifyComponent(dir2.getChildren().get(0), Component.Type.FILE, FILE_2_REF, 0);
133     verifyComponent(dir2.getChildren().get(1), Component.Type.FILE, FILE_3_REF, 0);
134
135     context.getStatistics().assertValue("components", 7);
136   }
137
138   @Test
139   public void verify_tree_is_correctly_built_in_prs() {
140     setAnalysisMetadataHolder(true);
141     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, FILE_1_REF, FILE_2_REF, FILE_3_REF, UNCHANGED_FILE_REF));
142     reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_PATH_1));
143     reportReader.putComponent(componentWithPath(FILE_2_REF, FILE, REPORT_FILE_PATH_2));
144     reportReader.putComponent(componentWithPath(FILE_3_REF, FILE, REPORT_FILE_PATH_3));
145     reportReader.putComponent(unchangedComponentWithPath(UNCHANGED_FILE_REF, FILE, REPORT_UNCHANGED_FILE_PATH));
146
147     TestComputationStepContext context = new TestComputationStepContext();
148     underTest.execute(context);
149
150     // modified root
151     Component mRoot = treeRootHolder.getRoot();
152     verifyComponent(mRoot, Component.Type.PROJECT, ROOT_REF, 1);
153
154     Component mDir = mRoot.getChildren().get(0);
155     assertThat(mDir.getName()).isEqualTo("src/main/java");
156     verifyComponent(mDir, Component.Type.DIRECTORY, null, 2);
157
158     Component mDir1 = mDir.getChildren().get(0);
159     assertThat(mDir1.getName()).isEqualTo("src/main/java/dir1");
160     verifyComponent(mDir1, Component.Type.DIRECTORY, null, 1);
161     verifyComponent(mDir1.getChildren().get(0), Component.Type.FILE, FILE_1_REF, 0);
162
163     Component mDir2 = mDir.getChildren().get(1);
164     assertThat(mDir2.getName()).isEqualTo("src/main/java/dir2");
165     verifyComponent(mDir2, Component.Type.DIRECTORY, null, 2);
166     verifyComponent(mDir2.getChildren().get(0), Component.Type.FILE, FILE_2_REF, 0);
167     verifyComponent(mDir2.getChildren().get(1), Component.Type.FILE, FILE_3_REF, 0);
168
169     // root
170     Component root = treeRootHolder.getReportTreeRoot();
171     verifyComponent(root, Component.Type.PROJECT, ROOT_REF, 1);
172
173     Component dir = root.getChildren().get(0);
174     assertThat(dir.getName()).isEqualTo("src/main");
175     verifyComponent(dir, Component.Type.DIRECTORY, null, 2);
176
177     Component dir1 = dir.getChildren().get(0);
178     assertThat(dir1.getName()).isEqualTo("src/main/java");
179     verifyComponent(dir1, Component.Type.DIRECTORY, null, 2);
180     verifyComponent(dir1.getChildren().get(0), Component.Type.DIRECTORY, null, 1);
181     verifyComponent(dir1.getChildren().get(1), Component.Type.DIRECTORY, null, 2);
182
183     Component dir2 = dir1.getChildren().get(0);
184     assertThat(dir2.getName()).isEqualTo("src/main/java/dir1");
185     verifyComponent(dir2, Component.Type.DIRECTORY, null, 1);
186     verifyComponent(dir2.getChildren().get(0), Component.Type.FILE, FILE_1_REF, 0);
187
188     Component dir3 = dir1.getChildren().get(1);
189     assertThat(dir3.getName()).isEqualTo("src/main/java/dir2");
190     verifyComponent(dir3, Component.Type.DIRECTORY, null, 2);
191     verifyComponent(dir3.getChildren().get(0), Component.Type.FILE, FILE_2_REF, 0);
192     verifyComponent(dir3.getChildren().get(1), Component.Type.FILE, FILE_3_REF, 0);
193
194     context.getStatistics().assertValue("components", 7);
195   }
196
197   /**
198    * SONAR-13262
199    */
200   @Test
201   public void verify_tree_is_correctly_built_in_prs_with_repeated_names() {
202     setAnalysisMetadataHolder(true);
203     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, FILE_1_REF));
204     reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_PROJECT_KEY + "/file.js"));
205
206     TestComputationStepContext context = new TestComputationStepContext();
207     underTest.execute(context);
208
209     // modified root
210     Component mRoot = treeRootHolder.getRoot();
211     verifyComponent(mRoot, Component.Type.PROJECT, ROOT_REF, 1);
212
213     Component dir = mRoot.getChildren().get(0);
214     assertThat(dir.getName()).isEqualTo(REPORT_PROJECT_KEY);
215     assertThat(dir.getShortName()).isEqualTo(REPORT_PROJECT_KEY);
216
217     verifyComponent(dir, Component.Type.DIRECTORY, null, 1);
218   }
219
220   @Test
221   public void compute_keys_and_uuids() {
222     setAnalysisMetadataHolder();
223     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, FILE_1_REF));
224     reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_PATH_1));
225
226     underTest.execute(new TestComputationStepContext());
227
228     verifyComponentByRef(ROOT_REF, REPORT_PROJECT_KEY, analysisMetadataHolder.getProject().getName());
229     verifyComponentByKey(REPORT_PROJECT_KEY + ":" + REPORT_DIR_PATH_1, REPORT_DIR_PATH_1);
230     verifyComponentByRef(FILE_1_REF, REPORT_PROJECT_KEY + ":" + REPORT_FILE_PATH_1, REPORT_FILE_NAME_1);
231   }
232
233   @Test
234   public void return_existing_uuids() {
235     setAnalysisMetadataHolder();
236     ComponentDto mainBranch = dbTester.components().insertPrivateProject("ABCD", p -> p.setKey(REPORT_PROJECT_KEY)).getMainBranchComponent();
237     ComponentDto directory = newDirectory(mainBranch, "CDEF", REPORT_DIR_PATH_1);
238     insertComponent(directory.setKey(REPORT_PROJECT_KEY + ":" + REPORT_DIR_PATH_1));
239     insertComponent(newFileDto(mainBranch, directory, "DEFG")
240       .setKey(REPORT_PROJECT_KEY + ":" + REPORT_FILE_PATH_1)
241       .setPath(REPORT_FILE_PATH_1));
242
243     // new structure, without modules
244     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, FILE_1_REF));
245     reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_PATH_1));
246
247     underTest.execute(new TestComputationStepContext());
248
249     verifyComponentByRef(ROOT_REF, REPORT_PROJECT_KEY, analysisMetadataHolder.getProject().getName(), mainBranch.uuid());
250     verifyComponentByKey(REPORT_PROJECT_KEY + ":" + REPORT_DIR_PATH_1, REPORT_DIR_PATH_1, "CDEF");
251     verifyComponentByRef(FILE_1_REF, REPORT_PROJECT_KEY + ":" + REPORT_FILE_PATH_1, REPORT_FILE_NAME_1, "DEFG");
252   }
253
254   @Test
255   public void generate_keys_when_using_new_branch() {
256     Branch branch = mock(Branch.class);
257     when(branch.getName()).thenReturn("origin/feature");
258     when(branch.isMain()).thenReturn(false);
259     when(branch.generateKey(any(), any())).thenReturn("generated");
260     analysisMetadataHolder.setRootComponentRef(ROOT_REF)
261       .setAnalysisDate(ANALYSIS_DATE)
262       .setProject(Project.from(newPrivateProjectDto().setKey(REPORT_PROJECT_KEY)))
263       .setBranch(branch);
264     BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder);
265     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, FILE_1_REF));
266     reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_PATH_1));
267
268     underTest.execute(new TestComputationStepContext());
269
270     verifyComponentByRef(ROOT_REF, "generated", analysisMetadataHolder.getProject().getName(), null);
271     verifyComponentByRef(FILE_1_REF, "generated", REPORT_FILE_NAME_1, null);
272   }
273
274   @Test
275   public void generate_keys_when_using_existing_branch() {
276     ComponentDto projectDto = dbTester.components().insertPublicProject().getMainBranchComponent();
277     String branchName = randomAlphanumeric(248);
278     ComponentDto componentDto = dbTester.components().insertProjectBranch(projectDto, b -> b.setKey(branchName));
279     Branch branch = mock(Branch.class);
280     when(branch.getName()).thenReturn(branchName);
281     when(branch.isMain()).thenReturn(false);
282     when(branch.generateKey(any(), any())).thenReturn(componentDto.getKey());
283     analysisMetadataHolder.setRootComponentRef(ROOT_REF)
284       .setAnalysisDate(ANALYSIS_DATE)
285       .setProject(Project.from(projectDto))
286       .setBranch(branch);
287     BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder);
288     reportReader.putComponent(component(ROOT_REF, PROJECT, componentDto.getKey()));
289
290     underTest.execute(new TestComputationStepContext());
291
292     verifyComponentByRef(ROOT_REF, componentDto.getKey(), analysisMetadataHolder.getProject().getName(), componentDto.uuid());
293   }
294
295   @Test
296   public void generate_keys_when_using_main_branch() {
297     setAnalysisMetadataHolder();
298     BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder);
299     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, FILE_1_REF));
300     reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_PATH_1));
301
302     underTest.execute(new TestComputationStepContext());
303
304     verifyComponentByRef(ROOT_REF, REPORT_PROJECT_KEY, analysisMetadataHolder.getProject().getName(), null);
305     verifyComponentByKey(REPORT_PROJECT_KEY + ":" + REPORT_DIR_PATH_1, REPORT_DIR_PATH_1);
306     verifyComponentByRef(FILE_1_REF, REPORT_PROJECT_KEY + ":" + REPORT_FILE_PATH_1, REPORT_FILE_NAME_1, null);
307   }
308
309   @Test
310   public void compute_keys_and_uuids_on_project_having_module_and_directory() {
311     setAnalysisMetadataHolder();
312     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, FILE_1_REF, FILE_2_REF));
313     reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_PATH_1));
314     reportReader.putComponent(componentWithPath(FILE_2_REF, FILE, REPORT_FILE_PATH_2));
315
316     underTest.execute(new TestComputationStepContext());
317
318     verifyComponentByRef(ROOT_REF, REPORT_PROJECT_KEY, analysisMetadataHolder.getProject().getName());
319     verifyComponentByKey(REPORT_PROJECT_KEY + ":" + REPORT_DIR_PATH_1, "dir1");
320     verifyComponentByRef(FILE_1_REF, REPORT_PROJECT_KEY + ":" + REPORT_FILE_PATH_1, REPORT_FILE_NAME_1);
321     verifyComponentByKey(REPORT_PROJECT_KEY + ":" + REPORT_DIR_PATH_2, "dir2");
322     verifyComponentByRef(FILE_2_REF, REPORT_PROJECT_KEY + ":" + REPORT_FILE_PATH_2, "File2.java");
323   }
324
325   @Test
326   public void compute_keys_and_uuids_on_multi_modules() {
327     setAnalysisMetadataHolder();
328     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, FILE_1_REF));
329     reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_PATH_1));
330
331     underTest.execute(new TestComputationStepContext());
332
333     verifyComponentByRef(ROOT_REF, REPORT_PROJECT_KEY, analysisMetadataHolder.getProject().getName());
334     verifyComponentByKey(REPORT_PROJECT_KEY + ":" + REPORT_DIR_PATH_1, REPORT_DIR_PATH_1);
335     verifyComponentByRef(FILE_1_REF, REPORT_PROJECT_KEY + ":" + REPORT_FILE_PATH_1, REPORT_FILE_NAME_1);
336   }
337
338   @Test
339   public void set_no_base_project_snapshot_when_no_snapshot() {
340     setAnalysisMetadataHolder();
341     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY));
342     underTest.execute(new TestComputationStepContext());
343
344     assertThat(analysisMetadataHolder.isFirstAnalysis()).isTrue();
345   }
346
347   @Test
348   public void set_no_base_project_snapshot_when_no_last_snapshot() {
349     setAnalysisMetadataHolder();
350     ComponentDto project = insertComponent(newPrivateProjectDto("ABCD").setKey(REPORT_PROJECT_KEY));
351     insertSnapshot(newAnalysis(project).setLast(false));
352
353     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY));
354     underTest.execute(new TestComputationStepContext());
355
356     assertThat(analysisMetadataHolder.isFirstAnalysis()).isTrue();
357   }
358
359   @Test
360   public void set_base_project_snapshot_when_last_snapshot_exist() {
361     setAnalysisMetadataHolder();
362     ComponentDto project = dbTester.components().insertPrivateProject("ABCD", p -> p.setKey(REPORT_PROJECT_KEY)).getMainBranchComponent();
363     insertSnapshot(newAnalysis(project).setLast(true));
364
365     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY));
366     underTest.execute(new TestComputationStepContext());
367
368     assertThat(analysisMetadataHolder.isFirstAnalysis()).isFalse();
369   }
370
371   @Test
372   public void set_projectVersion_to_not_provided_when_not_set_on_first_analysis() {
373     setAnalysisMetadataHolder();
374     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY));
375
376     underTest.execute(new TestComputationStepContext());
377
378     assertThat(treeRootHolder.getReportTreeRoot().getProjectAttributes().getProjectVersion()).isEqualTo("not provided");
379   }
380
381   @Test
382   @UseDataProvider("oneParameterNullNonNullCombinations")
383   public void set_projectVersion_to_previous_analysis_when_not_set(@Nullable String previousAnalysisProjectVersion) {
384     setAnalysisMetadataHolder();
385     ComponentDto project = dbTester.components().insertPrivateProject("ABCD", p -> p.setKey(REPORT_PROJECT_KEY)).getMainBranchComponent();
386     insertSnapshot(newAnalysis(project).setProjectVersion(previousAnalysisProjectVersion).setLast(true));
387     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY));
388
389     underTest.execute(new TestComputationStepContext());
390
391     String projectVersion = treeRootHolder.getReportTreeRoot().getProjectAttributes().getProjectVersion();
392     if (previousAnalysisProjectVersion == null) {
393       assertThat(projectVersion).isEqualTo("not provided");
394     } else {
395       assertThat(projectVersion).isEqualTo(previousAnalysisProjectVersion);
396     }
397   }
398
399   @Test
400   public void set_projectVersion_when_it_is_set_on_first_analysis() {
401     String scannerProjectVersion = randomAlphabetic(12);
402     setAnalysisMetadataHolder();
403     reportReader.setMetadata(createReportMetadata(scannerProjectVersion, NO_SCANNER_BUILD_STRING));
404     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY));
405
406     underTest.execute(new TestComputationStepContext());
407
408     assertThat(treeRootHolder.getReportTreeRoot().getProjectAttributes().getProjectVersion())
409       .isEqualTo(scannerProjectVersion);
410   }
411
412   @Test
413   @UseDataProvider("oneParameterNullNonNullCombinations")
414   public void set_projectVersion_when_it_is_set_on_later_analysis(@Nullable String previousAnalysisProjectVersion) {
415     String scannerProjectVersion = randomAlphabetic(12);
416     setAnalysisMetadataHolder();
417     reportReader.setMetadata(createReportMetadata(scannerProjectVersion, NO_SCANNER_BUILD_STRING));
418     ComponentDto project = insertComponent(newPrivateProjectDto("ABCD").setKey(REPORT_PROJECT_KEY));
419     insertSnapshot(newAnalysis(project).setProjectVersion(previousAnalysisProjectVersion).setLast(true));
420     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY));
421
422     underTest.execute(new TestComputationStepContext());
423
424     assertThat(treeRootHolder.getReportTreeRoot().getProjectAttributes().getProjectVersion())
425       .isEqualTo(scannerProjectVersion);
426   }
427
428   @Test
429   @UseDataProvider("oneParameterNullNonNullCombinations")
430   public void set_buildString(@Nullable String buildString) {
431     String projectVersion = randomAlphabetic(7);
432     setAnalysisMetadataHolder();
433     reportReader.setMetadata(createReportMetadata(projectVersion, buildString));
434     reportReader.putComponent(component(ROOT_REF, PROJECT, REPORT_PROJECT_KEY));
435
436     underTest.execute(new TestComputationStepContext());
437
438     assertThat(treeRootHolder.getReportTreeRoot().getProjectAttributes().getBuildString()).isEqualTo(Optional.ofNullable(buildString));
439   }
440
441   @DataProvider
442   public static Object[][] oneParameterNullNonNullCombinations() {
443     return new Object[][] {
444       {null},
445       {randomAlphabetic(7)}
446     };
447   }
448
449   private void verifyComponent(Component component, Component.Type type, @Nullable Integer componentRef, int size) {
450     assertThat(component.getType()).isEqualTo(type);
451     assertThat(component.getReportAttributes().getRef()).isEqualTo(componentRef);
452     assertThat(component.getChildren()).hasSize(size);
453   }
454
455   private void verifyComponentByRef(int ref, String key, String shortName) {
456     verifyComponentByRef(ref, key, shortName, null);
457   }
458
459   private void verifyComponentByKey(String key, String shortName) {
460     verifyComponentByKey(key, shortName, null);
461   }
462
463   private void verifyComponentByKey(String key, String shortName, @Nullable String uuid) {
464     Map<String, Component> componentsByKey = indexAllComponentsInTreeByKey(treeRootHolder.getRoot());
465     Component component = componentsByKey.get(key);
466     assertThat(component.getKey()).isEqualTo(key);
467     assertThat(component.getReportAttributes().getRef()).isNull();
468     assertThat(component.getShortName()).isEqualTo(shortName);
469     if (uuid != null) {
470       assertThat(component.getUuid()).isEqualTo(uuid);
471     } else {
472       assertThat(component.getUuid()).isNotNull();
473     }
474   }
475
476   private void verifyComponentByRef(int ref, String key, String shortName, @Nullable String uuid) {
477     Map<Integer, Component> componentsByRef = indexAllComponentsInTreeByRef(treeRootHolder.getRoot());
478     Component component = componentsByRef.get(ref);
479     assertThat(component.getKey()).isEqualTo(key);
480     assertThat(component.getShortName()).isEqualTo(shortName);
481     if (uuid != null) {
482       assertThat(component.getUuid()).isEqualTo(uuid);
483     } else {
484       assertThat(component.getUuid()).isNotNull();
485     }
486   }
487
488   private static ScannerReport.Component component(int componentRef, ComponentType componentType, String key, int... children) {
489     return component(componentRef, componentType, key, FileStatus.CHANGED, null, children);
490   }
491
492   private static ScannerReport.Component unchangedComponentWithPath(int componentRef, ComponentType componentType, String path, int... children) {
493     return component(componentRef, componentType, REPORT_PROJECT_KEY + ":" + path, FileStatus.SAME, path, children);
494   }
495
496   private static ScannerReport.Component componentWithPath(int componentRef, ComponentType componentType, String path, int... children) {
497     return component(componentRef, componentType, REPORT_PROJECT_KEY + ":" + path, FileStatus.CHANGED, path, children);
498   }
499
500   private static ScannerReport.Component component(int componentRef, ComponentType componentType, String key, FileStatus status, @Nullable String path, int... children) {
501     ScannerReport.Component.Builder builder = ScannerReport.Component.newBuilder()
502       .setType(componentType)
503       .setRef(componentRef)
504       .setName(key)
505       .setStatus(status)
506       .setLines(1)
507       .setKey(key);
508     if (path != null) {
509       builder.setProjectRelativePath(path);
510     }
511     for (int child : children) {
512       builder.addChildRef(child);
513     }
514     return builder.build();
515   }
516
517   private static Map<Integer, Component> indexAllComponentsInTreeByRef(Component root) {
518     Map<Integer, Component> componentsByRef = new HashMap<>();
519     feedComponentByRef(root, componentsByRef);
520     return componentsByRef;
521   }
522
523   private static Map<String, Component> indexAllComponentsInTreeByKey(Component root) {
524     Map<String, Component> componentsByKey = new HashMap<>();
525     feedComponentByKey(root, componentsByKey);
526     return componentsByKey;
527   }
528
529   private static void feedComponentByKey(Component component, Map<String, Component> map) {
530     map.put(component.getKey(), component);
531     for (Component child : component.getChildren()) {
532       feedComponentByKey(child, map);
533     }
534   }
535
536   private static void feedComponentByRef(Component component, Map<Integer, Component> map) {
537     if (component.getReportAttributes().getRef() != null) {
538       map.put(component.getReportAttributes().getRef(), component);
539     }
540     for (Component child : component.getChildren()) {
541       feedComponentByRef(child, map);
542     }
543   }
544
545   private ComponentDto insertComponent(ComponentDto component) {
546     return dbTester.components().insertComponent(component);
547   }
548
549   private SnapshotDto insertSnapshot(SnapshotDto snapshot) {
550     dbClient.snapshotDao().insert(dbTester.getSession(), snapshot);
551     dbTester.getSession().commit();
552     return snapshot;
553   }
554
555   private void setAnalysisMetadataHolder() {
556     setAnalysisMetadataHolder(false);
557   }
558
559   private void setAnalysisMetadataHolder(boolean isPr) {
560     Branch branch = isPr ? new PrBranch(DEFAULT_MAIN_BRANCH_NAME) : new DefaultBranchImpl(DEFAULT_MAIN_BRANCH_NAME);
561     analysisMetadataHolder.setRootComponentRef(ROOT_REF)
562       .setAnalysisDate(ANALYSIS_DATE)
563       .setBranch(branch)
564       .setProject(Project.from(newPrivateProjectDto().setKey(REPORT_PROJECT_KEY).setName(REPORT_PROJECT_KEY)));
565   }
566
567   public static ScannerReport.Metadata createReportMetadata(@Nullable String projectVersion, @Nullable String buildString) {
568     ScannerReport.Metadata.Builder builder = ScannerReport.Metadata.newBuilder()
569       .setProjectKey(REPORT_PROJECT_KEY)
570       .setRootComponentRef(ROOT_REF);
571     ofNullable(projectVersion).ifPresent(builder::setProjectVersion);
572     ofNullable(buildString).ifPresent(builder::setBuildString);
573     return builder.build();
574   }
575
576   private static class PrBranch extends DefaultBranchImpl {
577     public PrBranch(String branch) {
578       super(branch);
579     }
580
581     @Override
582     public BranchType getType() {
583       return BranchType.PULL_REQUEST;
584     }
585   }
586 }