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 static org.mockito.Mockito.mock;
23 import static org.mockito.Mockito.when;
25 import java.util.Date;
27 import org.junit.Rule;
28 import org.junit.Test;
29 import org.junit.rules.ExpectedException;
30 import org.sonar.api.utils.DateUtils;
31 import org.sonar.api.utils.MessageException;
32 import org.sonar.api.utils.System2;
33 import org.sonar.db.DbClient;
34 import org.sonar.db.DbTester;
35 import org.sonar.db.component.ComponentDto;
36 import org.sonar.db.component.ComponentTesting;
37 import org.sonar.db.component.SnapshotTesting;
38 import org.sonar.db.organization.OrganizationDto;
39 import org.sonar.scanner.protocol.output.ScannerReport;
40 import org.sonar.scanner.protocol.output.ScannerReport.Component.ComponentType;
41 import org.sonar.server.computation.task.projectanalysis.analysis.Analysis;
42 import org.sonar.server.computation.task.projectanalysis.analysis.AnalysisMetadataHolderRule;
43 import org.sonar.server.computation.task.projectanalysis.analysis.Branch;
44 import org.sonar.server.computation.task.projectanalysis.component.DefaultBranchImpl;
45 import org.sonar.server.computation.task.projectanalysis.batch.BatchReportReaderRule;
46 import org.sonar.server.computation.task.projectanalysis.component.Component;
47 import org.sonar.server.computation.task.projectanalysis.component.ReportComponent;
48 import org.sonar.server.computation.task.projectanalysis.component.TreeRootHolderRule;
49 import org.sonar.server.computation.task.projectanalysis.validation.ValidateIncremental;
51 public class ValidateProjectStepTest {
53 static long DEFAULT_ANALYSIS_TIME = 1433131200000L; // 2015-06-01
54 static final String PROJECT_KEY = "PROJECT_KEY";
55 static final String MODULE_KEY = "MODULE_KEY";
56 static final Branch DEFAULT_BRANCH = new DefaultBranchImpl();
59 public DbTester dbTester = DbTester.create(System2.INSTANCE);
62 public ExpectedException thrown = ExpectedException.none();
65 public BatchReportReaderRule reportReader = new BatchReportReaderRule();
68 public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
71 public AnalysisMetadataHolderRule analysisMetadataHolder = new AnalysisMetadataHolderRule()
72 .setAnalysisDate(new Date(DEFAULT_ANALYSIS_TIME))
73 .setIncrementalAnalysis(false)
74 .setBranch(DEFAULT_BRANCH);
76 public ValidateIncremental validateIncremental = mock(ValidateIncremental.class);
78 DbClient dbClient = dbTester.getDbClient();
80 ValidateProjectStep underTest = new ValidateProjectStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder, validateIncremental);
83 public void fail_if_root_component_is_not_a_project_in_db() {
84 reportReader.putComponent(ScannerReport.Component.newBuilder()
86 .setType(ComponentType.PROJECT)
89 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).build());
91 ComponentDto project = ComponentTesting.newView(dbTester.organizations().insert(), "ABCD").setDbKey(PROJECT_KEY);
92 dbClient.componentDao().insert(dbTester.getSession(), project);
93 dbTester.getSession().commit();
95 thrown.expect(MessageException.class);
96 thrown.expectMessage("Validation of project failed:\n" +
97 " o Component (uuid=ABCD, key=PROJECT_KEY) is not a project");
103 public void fail_on_invalid_key() {
104 String invalidProjectKey = "Project\\Key";
106 reportReader.putComponent(ScannerReport.Component.newBuilder()
108 .setType(ComponentType.PROJECT)
109 .setKey(invalidProjectKey)
112 reportReader.putComponent(ScannerReport.Component.newBuilder()
114 .setType(ComponentType.MODULE)
115 .setKey("Module$Key")
117 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(invalidProjectKey).addChildren(
118 ReportComponent.builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("Module$Key").build())
121 thrown.expect(MessageException.class);
122 thrown.expectMessage("Validation of project failed:\n" +
123 " o \"Project\\Key\" is not a valid project or module key. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit.\n" +
124 " o \"Module$Key\" is not a valid project or module key. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit");
130 public void fail_if_module_key_is_already_used_as_project_key() {
131 reportReader.putComponent(ScannerReport.Component.newBuilder()
133 .setType(ComponentType.PROJECT)
137 reportReader.putComponent(ScannerReport.Component.newBuilder()
139 .setType(ComponentType.MODULE)
143 ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), "ABCD").setDbKey(MODULE_KEY);
144 dbClient.componentDao().insert(dbTester.getSession(), project);
145 dbTester.getSession().commit();
147 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).addChildren(
148 ReportComponent.builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY).build())
151 thrown.expect(MessageException.class);
152 thrown.expectMessage("Validation of project failed:\n" +
153 " o The project \"" + MODULE_KEY + "\" is already defined in SonarQube but not as a module of project \"" + PROJECT_KEY + "\". " +
154 "If you really want to stop directly analysing project \"" + MODULE_KEY + "\", please first delete it from SonarQube and then relaunch the analysis of project \""
155 + PROJECT_KEY + "\".");
161 public void fail_if_module_key_already_exists_in_another_project() {
162 String anotherProjectKey = "ANOTHER_PROJECT_KEY";
163 reportReader.putComponent(ScannerReport.Component.newBuilder()
165 .setType(ComponentType.PROJECT)
169 reportReader.putComponent(ScannerReport.Component.newBuilder()
171 .setType(ComponentType.MODULE)
175 OrganizationDto organizationDto = dbTester.organizations().insert();
176 ComponentDto project = ComponentTesting.newPrivateProjectDto(organizationDto, "ABCD").setDbKey(PROJECT_KEY);
177 ComponentDto anotherProject = ComponentTesting.newPrivateProjectDto(organizationDto).setDbKey(anotherProjectKey);
178 dbClient.componentDao().insert(dbTester.getSession(), project, anotherProject);
179 ComponentDto module = ComponentTesting.newModuleDto("BCDE", anotherProject).setDbKey(MODULE_KEY);
180 dbClient.componentDao().insert(dbTester.getSession(), module);
181 dbTester.getSession().commit();
183 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).addChildren(
184 ReportComponent.builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY).build())
187 thrown.expect(MessageException.class);
188 thrown.expectMessage("Validation of project failed:\n" +
189 " o Module \"" + MODULE_KEY + "\" is already part of project \"" + anotherProjectKey + "\"");
195 public void fail_if_project_key_already_exists_as_module() {
196 String anotherProjectKey = "ANOTHER_PROJECT_KEY";
198 reportReader.putComponent(ScannerReport.Component.newBuilder()
200 .setType(ComponentType.PROJECT)
204 reportReader.putComponent(ScannerReport.Component.newBuilder()
206 .setType(ComponentType.MODULE)
210 ComponentDto anotherProject = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert()).setDbKey(anotherProjectKey);
211 dbClient.componentDao().insert(dbTester.getSession(), anotherProject);
212 ComponentDto module = ComponentTesting.newModuleDto("ABCD", anotherProject).setDbKey(PROJECT_KEY);
213 dbClient.componentDao().insert(dbTester.getSession(), module);
214 dbTester.getSession().commit();
216 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).addChildren(
217 ReportComponent.builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey(MODULE_KEY).build())
220 thrown.expect(MessageException.class);
221 thrown.expectMessage("Validation of project failed:\n" +
222 " o Component (uuid=ABCD, key=PROJECT_KEY) is not a project\n" +
223 " o The project \"" + PROJECT_KEY + "\" is already defined in SonarQube but as a module of project \"" + anotherProjectKey + "\". " +
224 "If you really want to stop directly analysing project \"" + anotherProjectKey + "\", please first delete it from SonarQube and then relaunch the analysis of project \""
225 + PROJECT_KEY + "\".");
231 public void not_fail_if_analysis_date_is_after_last_analysis() {
232 reportReader.putComponent(ScannerReport.Component.newBuilder()
234 .setType(ComponentType.PROJECT)
239 ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), "ABCD").setDbKey(PROJECT_KEY);
240 dbClient.componentDao().insert(dbTester.getSession(), project);
241 dbClient.snapshotDao().insert(dbTester.getSession(), SnapshotTesting.newAnalysis(project).setCreatedAt(1420088400000L)); // 2015-01-01
242 dbTester.getSession().commit();
244 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).build());
250 public void fail_if_analysis_date_is_before_last_analysis() {
251 analysisMetadataHolder.setAnalysisDate(DateUtils.parseDate("2015-01-01"));
253 reportReader.putComponent(ScannerReport.Component.newBuilder()
255 .setType(ComponentType.PROJECT)
260 ComponentDto project = ComponentTesting.newPrivateProjectDto(dbTester.organizations().insert(), "ABCD").setDbKey(PROJECT_KEY);
261 dbClient.componentDao().insert(dbTester.getSession(), project);
262 dbClient.snapshotDao().insert(dbTester.getSession(), SnapshotTesting.newAnalysis(project).setCreatedAt(1433131200000L)); // 2015-06-01
263 dbTester.getSession().commit();
265 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).build());
267 thrown.expect(MessageException.class);
268 thrown.expectMessage("Validation of project failed:");
269 thrown.expectMessage("Date of analysis cannot be older than the date of the last known analysis on this project. Value: ");
270 thrown.expectMessage("Latest analysis: ");
276 public void fail_if_incremental_plugin_not_found() {
277 ValidateProjectStep underTest = new ValidateProjectStep(dbClient, reportReader, treeRootHolder, analysisMetadataHolder, null);
279 when(validateIncremental.execute()).thenReturn(false);
280 analysisMetadataHolder.setBaseAnalysis(new Analysis.Builder().setId(1).setUuid("base").setCreatedAt(DEFAULT_ANALYSIS_TIME).build());
281 analysisMetadataHolder.setIncrementalAnalysis(true);
283 reportReader.putComponent(ScannerReport.Component.newBuilder()
285 .setType(ComponentType.PROJECT)
290 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).build());
292 thrown.expect(MessageException.class);
293 thrown.expectMessage("Validation of project failed:");
294 thrown.expectMessage("Can't process an incremental analysis of the project \"PROJECT_KEY\" because the incremental plugin is not loaded");
300 public void fail_if_incremental_validation_fails() {
301 when(validateIncremental.execute()).thenReturn(false);
302 analysisMetadataHolder.setBaseAnalysis(new Analysis.Builder().setId(1).setUuid("base").setCreatedAt(DEFAULT_ANALYSIS_TIME).build());
303 analysisMetadataHolder.setIncrementalAnalysis(true);
305 reportReader.putComponent(ScannerReport.Component.newBuilder()
307 .setType(ComponentType.PROJECT)
312 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).build());
314 thrown.expect(MessageException.class);
315 thrown.expectMessage("Validation of project failed:");
316 thrown.expectMessage("The installation of the incremental plugin is invalid");
322 public void fail_if_incremental_and_first_analysis() {
323 when(validateIncremental.execute()).thenReturn(true);
324 analysisMetadataHolder.setBaseAnalysis(null);
325 analysisMetadataHolder.setIncrementalAnalysis(true);
327 reportReader.putComponent(ScannerReport.Component.newBuilder()
329 .setType(ComponentType.PROJECT)
334 treeRootHolder.setRoot(ReportComponent.builder(Component.Type.PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).build());
336 thrown.expect(MessageException.class);
337 thrown.expectMessage("Validation of project failed:");
338 thrown.expectMessage("hasn't been analysed before and the first analysis can't be incremental. Please launch a full analysis of the project.");