3 * Copyright (C) 2009-2017 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.computation.task.projectanalysis.step;
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;
27 import javax.annotation.Nullable;
28 import org.junit.Rule;
29 import org.junit.Test;
30 import org.junit.runner.RunWith;
31 import org.sonar.api.utils.System2;
32 import org.sonar.db.DbClient;
33 import org.sonar.db.DbTester;
34 import org.sonar.db.component.ComponentDto;
35 import org.sonar.db.component.SnapshotDto;
36 import org.sonar.db.organization.OrganizationDto;
37 import org.sonar.scanner.protocol.output.ScannerReport;
38 import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType;
39 import org.sonar.scanner.protocol.output.ScannerReport.Component.FileStatus;
40 import org.sonar.server.computation.task.projectanalysis.analysis.MutableAnalysisMetadataHolderRule;
41 import org.sonar.server.computation.task.projectanalysis.analysis.Project;
42 import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderRule;
43 import org.sonar.server.computation.task.projectanalysis.component.Component;
44 import org.sonar.server.computation.task.projectanalysis.component.MutableTreeRootHolderRule;
46 import static com.google.common.base.Predicates.in;
47 import static com.google.common.base.Predicates.not;
48 import static com.google.common.collect.FluentIterable.from;
49 import static java.util.Arrays.asList;
50 import static org.assertj.core.api.Assertions.assertThat;
51 import static org.sonar.db.component.ComponentTesting.newDirectory;
52 import static org.sonar.db.component.ComponentTesting.newFileDto;
53 import static org.sonar.db.component.ComponentTesting.newModuleDto;
54 import static org.sonar.db.component.ComponentTesting.newPrivateProjectDto;
55 import static org.sonar.db.component.SnapshotTesting.newAnalysis;
56 import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.DIRECTORY;
57 import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.FILE;
58 import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.MODULE;
59 import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.PROJECT;
60 import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.UNRECOGNIZED;
61 import static org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType.UNSET;
63 @RunWith(DataProviderRunner.class)
64 public class BuildComponentTreeStepTest {
66 static final int ROOT_REF = 1;
67 static final int MODULE_REF = 2;
68 static final int DIR_REF_1 = 3;
69 static final int FILE_1_REF = 4;
70 static final int FILE_2_REF = 5;
71 static final int DIR_REF_2 = 6;
72 static final int FILE_3_REF = 7;
74 static final String REPORT_PROJECT_KEY = "REPORT_PROJECT_KEY";
75 static final String REPORT_MODULE_KEY = "MODULE_KEY";
76 static final String REPORT_DIR_KEY_1 = "src/main/java/dir1";
77 static final String REPORT_FILE_KEY_1 = "src/main/java/dir1/File1.java";
78 static final String REPORT_DIR_KEY_2 = "src/main/java/dir2";
79 static final String REPORT_FILE_KEY_2 = "src/main/java/dir2/File2.java";
81 static final long ANALYSIS_DATE = 123456789L;
84 public DbTester dbTester = DbTester.create(System2.INSTANCE);
86 public BatchReportReaderRule reportReader = new BatchReportReaderRule();
88 public MutableTreeRootHolderRule treeRootHolder = new MutableTreeRootHolderRule();
90 public MutableAnalysisMetadataHolderRule analysisMetadataHolder = new MutableAnalysisMetadataHolderRule()
91 .setRootComponentRef(ROOT_REF)
92 .setAnalysisDate(ANALYSIS_DATE)
94 .setProject(new Project("U1", REPORT_PROJECT_KEY, REPORT_PROJECT_KEY));
96 private DbClient dbClient = dbTester.getDbClient();
97 private BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder);
99 @Test(expected = NullPointerException.class)
100 public void fails_if_root_component_does_not_exist_in_reportReader() {
105 public static Object[][] allComponentTypes() {
106 Object[][] res = new Object[ComponentType.values().length - 2][1];
108 for (ComponentType componentType : from(asList(ComponentType.values())).filter(not(in(asList(UNSET, UNRECOGNIZED))))) {
109 res[i][0] = componentType;
116 @UseDataProvider("allComponentTypes")
117 public void verify_ref_and_type(ComponentType componentType) {
118 int componentRef = 1;
119 reportReader.putComponent(component(componentRef, componentType));
123 Component root = treeRootHolder.getRoot();
124 assertThat(root).isNotNull();
125 assertThat(root.getType()).isEqualTo(Component.Type.valueOf(componentType.name()));
126 assertThat(root.getReportAttributes().getRef()).isEqualTo(ROOT_REF);
127 assertThat(root.getChildren()).isEmpty();
131 public void verify_tree_is_correctly_built() {
132 reportReader.putComponent(component(ROOT_REF, PROJECT, MODULE_REF));
133 reportReader.putComponent(component(MODULE_REF, MODULE, DIR_REF_1, DIR_REF_2));
134 reportReader.putComponent(component(DIR_REF_1, DIRECTORY, FILE_1_REF, FILE_2_REF));
135 reportReader.putComponent(component(FILE_1_REF, FILE));
136 reportReader.putComponent(component(FILE_2_REF, FILE));
137 reportReader.putComponent(component(DIR_REF_2, DIRECTORY, FILE_3_REF));
138 reportReader.putComponent(component(FILE_3_REF, FILE));
142 Component root = treeRootHolder.getRoot();
143 assertThat(root).isNotNull();
144 verifyComponent(root, Component.Type.PROJECT, ROOT_REF, 1);
145 Component module = root.getChildren().iterator().next();
146 verifyComponent(module, Component.Type.MODULE, MODULE_REF, 2);
147 Component dir1 = module.getChildren().get(0);
148 verifyComponent(dir1, Component.Type.DIRECTORY, DIR_REF_1, 2);
149 verifyComponent(dir1.getChildren().get(0), Component.Type.FILE, FILE_1_REF, 0);
150 verifyComponent(dir1.getChildren().get(1), Component.Type.FILE, FILE_2_REF, 0);
151 Component dir2 = module.getChildren().get(1);
152 verifyComponent(dir2, Component.Type.DIRECTORY, DIR_REF_2, 1);
153 verifyComponent(dir2.getChildren().iterator().next(), Component.Type.FILE, FILE_3_REF, 0);
157 public void compute_keys_and_uuids() {
158 reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF));
159 reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1));
160 reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF));
161 reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1));
165 verifyComponent(ROOT_REF, REPORT_PROJECT_KEY);
166 verifyComponent(MODULE_REF, REPORT_MODULE_KEY);
167 verifyComponent(DIR_REF_1, REPORT_MODULE_KEY + ":" + REPORT_DIR_KEY_1);
168 verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":" + REPORT_FILE_KEY_1);
172 public void return_existing_uuids() {
173 OrganizationDto organizationDto = dbTester.organizations().insert();
174 ComponentDto project = insertComponent(newPrivateProjectDto(organizationDto, "ABCD").setDbKey(REPORT_PROJECT_KEY));
175 ComponentDto module = insertComponent(newModuleDto("BCDE", project).setDbKey(REPORT_MODULE_KEY));
176 ComponentDto directory = newDirectory(module, "CDEF", REPORT_DIR_KEY_1);
177 insertComponent(directory.setDbKey(REPORT_MODULE_KEY + ":" + REPORT_DIR_KEY_1));
178 insertComponent(newFileDto(module, directory, "DEFG").setDbKey(REPORT_MODULE_KEY + ":" + REPORT_FILE_KEY_1));
180 reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF));
181 reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1));
182 reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF));
183 reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1));
187 verifyComponent(ROOT_REF, REPORT_PROJECT_KEY, "ABCD");
188 verifyComponent(MODULE_REF, REPORT_MODULE_KEY, "BCDE");
189 verifyComponent(DIR_REF_1, REPORT_MODULE_KEY + ":" + REPORT_DIR_KEY_1, "CDEF");
190 verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":" + REPORT_FILE_KEY_1, "DEFG");
194 // public void use_branch_to_generate_keys() {
195 // MutableAnalysisMetadataHolder analysisMetadataHolder = new AnalysisMetadataHolderImpl()
196 // .setRootComponentRef(ROOT_REF)
197 // .setAnalysisDate(ANALYSIS_DATE)
198 // .setBranch("origin/master");
200 // BuildComponentTreeStep underTest = new BuildComponentTreeStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder);
202 // reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF));
203 // reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1));
204 // reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF));
205 // reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1));
207 // underTest.execute();
209 // verifyComponent(ROOT_REF, REPORT_PROJECT_KEY + ":origin/master");
210 // verifyComponent(MODULE_REF, REPORT_MODULE_KEY + ":origin/master");
211 // verifyComponent(DIR_REF_1, REPORT_MODULE_KEY + ":origin/master:" + REPORT_DIR_KEY_1);
212 // verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":origin/master:" + REPORT_FILE_KEY_1);
216 public void compute_keys_and_uuids_on_project_having_module_and_directory() {
217 reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF, DIR_REF_2));
218 reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1));
219 reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF));
220 reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1));
221 reportReader.putComponent(componentWithPath(DIR_REF_2, DIRECTORY, REPORT_DIR_KEY_2, FILE_2_REF));
222 reportReader.putComponent(componentWithPath(FILE_2_REF, FILE, REPORT_FILE_KEY_2));
226 verifyComponent(ROOT_REF, REPORT_PROJECT_KEY);
227 verifyComponent(MODULE_REF, REPORT_MODULE_KEY);
228 verifyComponent(DIR_REF_1, REPORT_MODULE_KEY + ":" + REPORT_DIR_KEY_1);
229 verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":" + REPORT_FILE_KEY_1);
230 verifyComponent(DIR_REF_2, REPORT_PROJECT_KEY + ":" + REPORT_DIR_KEY_2);
231 verifyComponent(FILE_2_REF, REPORT_PROJECT_KEY + ":" + REPORT_FILE_KEY_2);
235 public void compute_keys_and_uuids_on_multi_modules() {
236 reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF));
237 reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, 100));
238 reportReader.putComponent(componentWithKey(100, MODULE, "SUB_MODULE_KEY", DIR_REF_1));
239 reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF));
240 reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1));
244 verifyComponent(ROOT_REF, REPORT_PROJECT_KEY);
245 verifyComponent(MODULE_REF, REPORT_MODULE_KEY);
246 verifyComponent(100, "SUB_MODULE_KEY");
247 verifyComponent(DIR_REF_1, "SUB_MODULE_KEY" + ":" + REPORT_DIR_KEY_1);
248 verifyComponent(FILE_1_REF, "SUB_MODULE_KEY" + ":" + REPORT_FILE_KEY_1);
252 public void return_existing_uuids_when_components_were_removed() {
253 OrganizationDto organizationDto = dbTester.organizations().insert();
254 ComponentDto project = insertComponent(newPrivateProjectDto(organizationDto, "ABCD").setDbKey(REPORT_PROJECT_KEY));
255 ComponentDto removedModule = insertComponent(newModuleDto("BCDE", project).setDbKey(REPORT_MODULE_KEY).setEnabled(false));
256 ComponentDto removedDirectory = insertComponent(newDirectory(removedModule, "CDEF", REPORT_DIR_KEY_1).setDbKey(REPORT_MODULE_KEY + ":" + REPORT_DIR_KEY_1).setEnabled(false));
257 insertComponent(newFileDto(removedModule, removedDirectory, "DEFG").setDbKey(REPORT_MODULE_KEY + ":" + REPORT_FILE_KEY_1).setEnabled(false));
259 reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY, MODULE_REF));
260 reportReader.putComponent(componentWithKey(MODULE_REF, MODULE, REPORT_MODULE_KEY, DIR_REF_1));
261 reportReader.putComponent(componentWithPath(DIR_REF_1, DIRECTORY, REPORT_DIR_KEY_1, FILE_1_REF));
262 reportReader.putComponent(componentWithPath(FILE_1_REF, FILE, REPORT_FILE_KEY_1));
266 verifyComponent(ROOT_REF, REPORT_PROJECT_KEY, "ABCD");
268 // No new UUID is generated on removed components
269 verifyComponent(MODULE_REF, REPORT_MODULE_KEY, "BCDE");
270 verifyComponent(DIR_REF_1, REPORT_MODULE_KEY + ":" + REPORT_DIR_KEY_1, "CDEF");
271 verifyComponent(FILE_1_REF, REPORT_MODULE_KEY + ":" + REPORT_FILE_KEY_1, "DEFG");
275 public void set_no_base_project_snapshot_when_no_snapshot() throws Exception {
276 reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY));
279 assertThat(analysisMetadataHolder.isFirstAnalysis()).isTrue();
283 public void set_no_base_project_snapshot_when_no_last_snapshot() throws Exception {
284 OrganizationDto organizationDto = dbTester.organizations().insert();
285 ComponentDto project = insertComponent(newPrivateProjectDto(organizationDto, "ABCD").setDbKey(REPORT_PROJECT_KEY));
286 insertSnapshot(newAnalysis(project).setLast(false));
288 reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY));
291 assertThat(analysisMetadataHolder.isFirstAnalysis()).isTrue();
295 public void set_base_project_snapshot_when_last_snapshot_exist() throws Exception {
296 OrganizationDto organizationDto = dbTester.organizations().insert();
297 ComponentDto project = insertComponent(newPrivateProjectDto(organizationDto, "ABCD").setDbKey(REPORT_PROJECT_KEY));
298 insertSnapshot(newAnalysis(project).setLast(true));
300 reportReader.putComponent(componentWithKey(ROOT_REF, PROJECT, REPORT_PROJECT_KEY));
303 assertThat(analysisMetadataHolder.isFirstAnalysis()).isFalse();
306 private void verifyComponent(Component component, Component.Type type, int componentRef, int size) {
307 assertThat(component.getType()).isEqualTo(type);
308 assertThat(component.getReportAttributes().getRef()).isEqualTo(componentRef);
309 assertThat(component.getChildren()).hasSize(size);
312 private void verifyComponent(int ref, String key) {
313 verifyComponent(ref, key, null);
316 private void verifyComponent(int ref, String key, @Nullable String uuid) {
317 Map<Integer, Component> componentsByRef = indexAllComponentsInTreeByRef(treeRootHolder.getRoot());
318 Component component = componentsByRef.get(ref);
319 assertThat(component.getKey()).isEqualTo(key);
321 assertThat(component.getUuid()).isEqualTo(uuid);
323 assertThat(component.getUuid()).isNotNull();
327 private static ScannerReport.Component component(int componentRef, ComponentType componentType, int... children) {
328 return component(componentRef, componentType, null, null, children);
331 private static ScannerReport.Component componentWithKey(int componentRef, ComponentType componentType, String key, int... children) {
332 return component(componentRef, componentType, key, null, children);
335 private static ScannerReport.Component componentWithPath(int componentRef, ComponentType componentType, String path, int... children) {
336 return component(componentRef, componentType, null, path, children);
339 private static ScannerReport.Component component(int componentRef, ComponentType componentType, @Nullable String key, @Nullable String path, int... children) {
340 ScannerReport.Component.Builder builder = ScannerReport.Component.newBuilder()
341 .setType(componentType)
342 .setRef(componentRef)
343 .setStatus(FileStatus.UNAVAILABLE)
349 builder.setPath(path);
351 for (int child : children) {
352 builder.addChildRef(child);
354 return builder.build();
357 private static Map<Integer, Component> indexAllComponentsInTreeByRef(Component root) {
358 Map<Integer, Component> componentsByRef = new HashMap<>();
359 feedComponentByRef(root, componentsByRef);
360 return componentsByRef;
363 private static void feedComponentByRef(Component component, Map<Integer, Component> map) {
364 map.put(component.getReportAttributes().getRef(), component);
365 for (Component child : component.getChildren()) {
366 feedComponentByRef(child, map);
370 private ComponentDto insertComponent(ComponentDto component) {
371 dbClient.componentDao().insert(dbTester.getSession(), component);
372 dbTester.getSession().commit();
376 private SnapshotDto insertSnapshot(SnapshotDto snapshot) {
377 dbClient.snapshotDao().insert(dbTester.getSession(), snapshot);
378 dbTester.getSession().commit();