You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ProjectReactorBuilderTest.java 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2019 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.scanner.scan;
  21. import com.google.common.collect.Maps;
  22. import java.io.File;
  23. import java.io.FileInputStream;
  24. import java.io.IOException;
  25. import java.net.URL;
  26. import java.util.HashMap;
  27. import java.util.List;
  28. import java.util.Map;
  29. import java.util.Properties;
  30. import org.apache.commons.io.FileUtils;
  31. import org.apache.commons.lang.StringUtils;
  32. import org.junit.Rule;
  33. import org.junit.Test;
  34. import org.junit.rules.ExpectedException;
  35. import org.sonar.api.batch.bootstrap.ProjectDefinition;
  36. import org.sonar.api.batch.bootstrap.ProjectReactor;
  37. import org.sonar.api.notifications.AnalysisWarnings;
  38. import org.sonar.api.utils.MessageException;
  39. import org.sonar.api.utils.log.LogTester;
  40. import org.sonar.scanner.bootstrap.RawScannerProperties;
  41. import org.sonar.scanner.bootstrap.ProcessedScannerProperties;
  42. import static org.assertj.core.api.Assertions.assertThat;
  43. import static org.mockito.Mockito.mock;
  44. public class ProjectReactorBuilderTest {
  45. @Rule
  46. public ExpectedException thrown = ExpectedException.none();
  47. @Rule
  48. public LogTester logTester = new LogTester();
  49. @Test
  50. public void shouldDefineSimpleProject() {
  51. ProjectDefinition projectDefinition = loadProjectDefinition("simple-project");
  52. assertThat(projectDefinition.getKey()).isEqualTo("com.foo.project");
  53. assertThat(projectDefinition.getName()).isEqualTo("Foo Project");
  54. assertThat(projectDefinition.getVersion()).isEqualTo("1.0-SNAPSHOT");
  55. assertThat(projectDefinition.getDescription()).isEqualTo("Description of Foo Project");
  56. assertThat(projectDefinition.sources()).contains("sources");
  57. }
  58. @Test
  59. public void should_fail_if_sources_are_missing_in_leaf_module() {
  60. thrown.expect(MessageException.class);
  61. thrown.expectMessage("The folder 'unexisting-source-dir' does not exist for 'com.foo.project' (base directory = "
  62. + getResource(this.getClass(), "simple-project-with-unexisting-source-dir") + ")");
  63. loadProjectDefinition("simple-project-with-unexisting-source-dir");
  64. }
  65. @Test
  66. public void should_not_fail_if_sources_are_missing_in_intermediate_module() {
  67. loadProjectDefinition("multi-module-pom-in-root");
  68. }
  69. @Test
  70. public void shouldNotFailIfBlankSourceDirectory() {
  71. loadProjectDefinition("simple-project-with-blank-source-dir");
  72. }
  73. @Test
  74. public void modulesDuplicateIds() {
  75. thrown.expect(MessageException.class);
  76. thrown.expectMessage("Two modules have the same id: 'module1'. Each module must have a unique id.");
  77. loadProjectDefinition("multi-module-duplicate-id");
  78. }
  79. @Test
  80. public void sonarModuleIdIsForbidden() {
  81. thrown.expect(MessageException.class);
  82. thrown.expectMessage("'sonar' is not a valid module id. Please check property 'sonar.modules'.");
  83. loadProjectDefinition("multi-module-sonar-module");
  84. }
  85. @Test
  86. public void modulesRepeatedIds() {
  87. ProjectDefinition rootProject = loadProjectDefinition("multi-module-repeated-id");
  88. List<ProjectDefinition> modules = rootProject.getSubProjects();
  89. assertThat(modules.size()).isEqualTo(1);
  90. // Module 1
  91. ProjectDefinition module1 = modules.get(0);
  92. assertThat(module1.getKey()).isEqualTo("com.foo.project:module1");
  93. assertThat(module1.getName()).isEqualTo("Foo Module 1");
  94. // Module 1 -> Module 1
  95. ProjectDefinition module1_module1 = module1.getSubProjects().get(0);
  96. assertThat(module1_module1.getKey()).isEqualTo("com.foo.project:module1:module1");
  97. assertThat(module1_module1.getName()).isEqualTo("Foo Sub Module 1");
  98. }
  99. @Test
  100. public void shouldDefineMultiModuleProjectWithDefinitionsAllInRootProject() throws IOException {
  101. execMultiModule("multi-module-definitions-all-in-root");
  102. }
  103. @Test
  104. public void shouldDefineMultiModuleProjectWithPomFileAtRootLevel() throws IOException {
  105. ProjectDefinition project = execMultiModule("multi-module-pom-in-root");
  106. assertThat(project.sources()).containsExactlyInAnyOrder("pom.xml", "sources");
  107. }
  108. public ProjectDefinition execMultiModule(String key) throws IOException {
  109. ProjectDefinition rootProject = loadProjectDefinition(key);
  110. // CHECK ROOT
  111. assertThat(rootProject.getKey()).isEqualTo("com.foo.project");
  112. assertThat(rootProject.getName()).isEqualTo("Foo Project");
  113. assertThat(rootProject.getVersion()).isEqualTo("1.0-SNAPSHOT");
  114. assertThat(rootProject.getDescription()).isEqualTo("Description of Foo Project");
  115. assertThat(rootProject.sources().contains("sources")).isTrue();
  116. assertThat(rootProject.tests().contains("tests")).isTrue();
  117. // and module properties must have been cleaned
  118. assertThat(rootProject.properties().get("module1.sonar.projectKey")).isNull();
  119. assertThat(rootProject.properties().get("module2.sonar.projectKey")).isNull();
  120. // Check baseDir and workDir
  121. assertThat(rootProject.getBaseDir().getCanonicalFile()).isEqualTo(getResource(this.getClass(), key));
  122. assertThat(rootProject.getWorkDir().getCanonicalFile()).isEqualTo(new File(getResource(this.getClass(), key), ".sonar"));
  123. // CHECK MODULES
  124. List<ProjectDefinition> modules = rootProject.getSubProjects();
  125. assertThat(modules.size()).isEqualTo(2);
  126. // Module 1
  127. ProjectDefinition module1 = modules.get(0);
  128. assertThat(module1.getBaseDir().getCanonicalFile()).isEqualTo(getResource(this.getClass(), key + "/module1"));
  129. assertThat(module1.getKey()).isEqualTo("com.foo.project:module1");
  130. assertThat(module1.getName()).isEqualTo("module1");
  131. assertThat(module1.getVersion()).isEqualTo("1.0-SNAPSHOT");
  132. // Description should not be inherited from parent if not set
  133. assertThat(module1.getDescription()).isNull();
  134. assertThat(module1.sources()).contains("sources");
  135. assertThat(module1.tests()).contains("tests");
  136. // and module properties must have been cleaned
  137. assertThat(module1.properties().get("module1.sonar.projectKey")).isNull();
  138. assertThat(module1.properties().get("module2.sonar.projectKey")).isNull();
  139. // Check baseDir and workDir
  140. assertThat(module1.getBaseDir().getCanonicalFile()).isEqualTo(getResource(this.getClass(), key + "/module1"));
  141. assertThat(module1.getWorkDir().getCanonicalFile()).isEqualTo(new File(getResource(this.getClass(), key), ".sonar/com.foo.project_module1"));
  142. // Module 2
  143. ProjectDefinition module2 = modules.get(1);
  144. assertThat(module2.getBaseDir().getCanonicalFile()).isEqualTo(getResource(this.getClass(), key + "/module2"));
  145. assertThat(module2.getKey()).isEqualTo("com.foo.project:com.foo.project.module2");
  146. assertThat(module2.getName()).isEqualTo("Foo Module 2");
  147. assertThat(module2.getVersion()).isEqualTo("1.0-SNAPSHOT");
  148. assertThat(module2.getDescription()).isEqualTo("Description of Module 2");
  149. assertThat(module2.sources()).contains("src");
  150. assertThat(module2.tests()).contains("tests");
  151. // and module properties must have been cleaned
  152. assertThat(module2.properties().get("module1.sonar.projectKey")).isNull();
  153. assertThat(module2.properties().get("module2.sonar.projectKey")).isNull();
  154. // Check baseDir and workDir
  155. assertThat(module2.getBaseDir().getCanonicalFile()).isEqualTo(getResource(this.getClass(), key + "/module2"));
  156. assertThat(module2.getWorkDir().getCanonicalFile()).isEqualTo(
  157. new File(getResource(this.getClass(), key), ".sonar/com.foo.project_com.foo.project.module2"));
  158. return rootProject;
  159. }
  160. // SONAR-4876
  161. @Test
  162. public void shouldDefineMultiModuleProjectWithModuleKey() {
  163. ProjectDefinition rootProject = loadProjectDefinition("multi-module-definitions-moduleKey");
  164. // CHECK ROOT
  165. // module properties must have been cleaned
  166. assertThat(rootProject.properties().get("module1.sonar.moduleKey")).isNull();
  167. assertThat(rootProject.properties().get("module2.sonar.moduleKey")).isNull();
  168. // CHECK MODULES
  169. List<ProjectDefinition> modules = rootProject.getSubProjects();
  170. assertThat(modules.size()).isEqualTo(2);
  171. // Module 2
  172. ProjectDefinition module2 = modules.get(1);
  173. assertThat(module2.getKey()).isEqualTo("com.foo.project.module2");
  174. }
  175. // SONARPLUGINS-2421
  176. @Test
  177. public void shouldDefineMultiLanguageProjectWithDefinitionsAllInRootProject() throws IOException {
  178. ProjectDefinition rootProject = loadProjectDefinition("multi-language-definitions-all-in-root");
  179. // CHECK ROOT
  180. assertThat(rootProject.getKey()).isEqualTo("example");
  181. assertThat(rootProject.getName()).isEqualTo("Example");
  182. assertThat(rootProject.getVersion()).isEqualTo("1.0");
  183. // CHECK MODULES
  184. List<ProjectDefinition> modules = rootProject.getSubProjects();
  185. assertThat(modules.size()).isEqualTo(2);
  186. // Module 1
  187. ProjectDefinition module1 = modules.get(0);
  188. assertThat(module1.getBaseDir().getCanonicalFile()).isEqualTo(getResource(this.getClass(), "multi-language-definitions-all-in-root"));
  189. assertThat(module1.sources()).contains("src/main/java");
  190. // and module properties must have been cleaned
  191. assertThat(module1.getWorkDir().getCanonicalFile())
  192. .isEqualTo(new File(getResource(this.getClass(), "multi-language-definitions-all-in-root"), ".sonar/example_java-module"));
  193. // Module 2
  194. ProjectDefinition module2 = modules.get(1);
  195. assertThat(module2.getBaseDir().getCanonicalFile()).isEqualTo(getResource(this.getClass(), "multi-language-definitions-all-in-root"));
  196. assertThat(module2.sources()).contains("src/main/groovy");
  197. // and module properties must have been cleaned
  198. assertThat(module2.getWorkDir().getCanonicalFile())
  199. .isEqualTo(new File(getResource(this.getClass(), "multi-language-definitions-all-in-root"), ".sonar/example_groovy-module"));
  200. }
  201. @Test
  202. public void shouldDefineMultiModuleProjectWithBaseDir() {
  203. ProjectDefinition rootProject = loadProjectDefinition("multi-module-with-basedir");
  204. List<ProjectDefinition> modules = rootProject.getSubProjects();
  205. assertThat(modules.size()).isEqualTo(1);
  206. assertThat(modules.get(0).getKey()).isEqualTo("com.foo.project:com.foo.project.module1");
  207. }
  208. @Test
  209. public void shouldFailIfUnexistingModuleBaseDir() {
  210. thrown.expect(MessageException.class);
  211. thrown.expectMessage("The base directory of the module 'module1' does not exist: "
  212. + getResource(this.getClass(), "multi-module-with-unexisting-basedir").getAbsolutePath() + File.separator + "module1");
  213. loadProjectDefinition("multi-module-with-unexisting-basedir");
  214. }
  215. @Test
  216. public void shouldFailIfUnexistingSourceFolderInheritedInMultimodule() {
  217. thrown.expect(MessageException.class);
  218. thrown.expectMessage("The folder 'unexisting-source-dir' does not exist for 'com.foo.project:module1' (base directory = "
  219. + getResource(this.getClass(), "multi-module-with-unexisting-source-dir").getAbsolutePath() + File.separator + "module1)");
  220. loadProjectDefinition("multi-module-with-unexisting-source-dir");
  221. }
  222. @Test
  223. public void shouldFailIfExplicitUnexistingTestFolder() {
  224. thrown.expect(MessageException.class);
  225. thrown.expectMessage("The folder 'tests' does not exist for 'com.foo.project' (base directory = "
  226. + getResource(this.getClass(), "simple-project-with-unexisting-test-dir").getAbsolutePath());
  227. loadProjectDefinition("simple-project-with-unexisting-test-dir");
  228. }
  229. @Test
  230. public void shouldFailIfExplicitUnexistingTestFolderOnModule() {
  231. thrown.expect(MessageException.class);
  232. thrown.expectMessage("The folder 'tests' does not exist for 'module1' (base directory = "
  233. + getResource(this.getClass(), "multi-module-with-explicit-unexisting-test-dir").getAbsolutePath() + File.separator + "module1)");
  234. loadProjectDefinition("multi-module-with-explicit-unexisting-test-dir");
  235. }
  236. @Test
  237. public void multiModuleProperties() {
  238. ProjectDefinition projectDefinition = loadProjectDefinition("big-multi-module-definitions-all-in-root");
  239. assertThat(projectDefinition.properties().get("module11.property")).isNull();
  240. ProjectDefinition module1 = null;
  241. ProjectDefinition module2 = null;
  242. for (ProjectDefinition prj : projectDefinition.getSubProjects()) {
  243. if (prj.getKey().equals("com.foo.project:module1")) {
  244. module1 = prj;
  245. } else if (prj.getKey().equals("com.foo.project:module2")) {
  246. module2 = prj;
  247. }
  248. }
  249. assertThat(module1.properties().get("module11.property")).isNull();
  250. assertThat(module1.properties().get("property")).isNull();
  251. assertThat(module2.properties().get("module11.property")).isNull();
  252. assertThat(module2.properties().get("property")).isNull();
  253. ProjectDefinition module11 = null;
  254. ProjectDefinition module12 = null;
  255. for (ProjectDefinition prj : module1.getSubProjects()) {
  256. if (prj.getKey().equals("com.foo.project:module1:module11")) {
  257. module11 = prj;
  258. } else if (prj.getKey().equals("com.foo.project:module1:module12")) {
  259. module12 = prj;
  260. }
  261. }
  262. assertThat(module11.properties().get("module1.module11.property")).isNull();
  263. assertThat(module11.properties().get("module11.property")).isNull();
  264. assertThat(module11.properties().get("property")).isEqualTo("My module11 property");
  265. assertThat(module12.properties().get("module11.property")).isNull();
  266. assertThat(module12.properties().get("property")).isNull();
  267. }
  268. @Test
  269. public void shouldFailIfMandatoryPropertiesAreNotPresent() {
  270. Map<String, String> props = new HashMap<>();
  271. props.put("foo1", "bla");
  272. props.put("foo4", "bla");
  273. thrown.expect(MessageException.class);
  274. thrown.expectMessage("You must define the following mandatory properties for 'Unknown': foo2, foo3");
  275. ProjectReactorBuilder.checkMandatoryProperties(props, new String[] {"foo1", "foo2", "foo3"});
  276. }
  277. @Test
  278. public void shouldFailIfMandatoryPropertiesAreNotPresentButWithProjectKey() {
  279. Map<String, String> props = new HashMap<>();
  280. props.put("foo1", "bla");
  281. props.put("sonar.projectKey", "my-project");
  282. thrown.expect(MessageException.class);
  283. thrown.expectMessage("You must define the following mandatory properties for 'my-project': foo2, foo3");
  284. ProjectReactorBuilder.checkMandatoryProperties(props, new String[] {"foo1", "foo2", "foo3"});
  285. }
  286. @Test
  287. public void shouldNotFailIfMandatoryPropertiesArePresent() {
  288. Map<String, String> props = new HashMap<>();
  289. props.put("foo1", "bla");
  290. props.put("foo4", "bla");
  291. ProjectReactorBuilder.checkMandatoryProperties(props, new String[] {"foo1"});
  292. // No exception should be thrown
  293. }
  294. @Test
  295. public void shouldGetRelativeFile() {
  296. assertThat(ProjectReactorBuilder.resolvePath(getResource(this.getClass(), "/"), "shouldGetFile/foo.properties"))
  297. .isEqualTo(getResource(this.getClass(), "shouldGetFile/foo.properties"));
  298. }
  299. @Test
  300. public void shouldGetAbsoluteFile() {
  301. File file = getResource(this.getClass(), "shouldGetFile/foo.properties");
  302. assertThat(ProjectReactorBuilder.resolvePath(getResource(this.getClass(), "/"), file.getAbsolutePath()))
  303. .isEqualTo(file);
  304. }
  305. @Test
  306. public void shouldMergeParentProperties() {
  307. // Use a random value to avoid VM optimization that would create constant String and make s1 and s2 the same object
  308. int i = (int) Math.random() * 10;
  309. String s1 = "value" + i;
  310. String s2 = "value" + i;
  311. Map<String, String> parentProps = new HashMap<>();
  312. parentProps.put("toBeMergeProps", "fooParent");
  313. parentProps.put("existingChildProp", "barParent");
  314. parentProps.put("duplicatedProp", s1);
  315. parentProps.put("sonar.projectDescription", "Desc from Parent");
  316. Map<String, String> childProps = new HashMap<>();
  317. childProps.put("existingChildProp", "barChild");
  318. childProps.put("otherProp", "tutuChild");
  319. childProps.put("duplicatedProp", s2);
  320. ProjectReactorBuilder.mergeParentProperties(childProps, parentProps);
  321. assertThat(childProps).hasSize(4);
  322. assertThat(childProps.get("toBeMergeProps")).isEqualTo("fooParent");
  323. assertThat(childProps.get("existingChildProp")).isEqualTo("barChild");
  324. assertThat(childProps.get("otherProp")).isEqualTo("tutuChild");
  325. assertThat(childProps.get("sonar.projectDescription")).isNull();
  326. assertThat(childProps.get("duplicatedProp")).isSameAs(parentProps.get("duplicatedProp"));
  327. }
  328. @Test
  329. public void shouldInitRootWorkDir() {
  330. ProjectReactorBuilder builder = new ProjectReactorBuilder(new ProcessedScannerProperties(
  331. new RawScannerProperties(Maps.newHashMap()), new EmptyExternalProjectKeyAndOrganization()),
  332. mock(AnalysisWarnings.class));
  333. File baseDir = new File("target/tmp/baseDir");
  334. File workDir = builder.initRootProjectWorkDir(baseDir, Maps.newHashMap());
  335. assertThat(workDir).isEqualTo(new File(baseDir, ".sonar"));
  336. }
  337. @Test
  338. public void shouldInitWorkDirWithCustomRelativeFolder() {
  339. Map<String, String> props = Maps.newHashMap();
  340. props.put("sonar.working.directory", ".foo");
  341. ProjectReactorBuilder builder = new ProjectReactorBuilder(new ProcessedScannerProperties(
  342. new RawScannerProperties(props),
  343. new EmptyExternalProjectKeyAndOrganization()),
  344. mock(AnalysisWarnings.class));
  345. File baseDir = new File("target/tmp/baseDir");
  346. File workDir = builder.initRootProjectWorkDir(baseDir, props);
  347. assertThat(workDir).isEqualTo(new File(baseDir, ".foo"));
  348. }
  349. @Test
  350. public void shouldInitRootWorkDirWithCustomAbsoluteFolder() {
  351. Map<String, String> props = Maps.newHashMap();
  352. props.put("sonar.working.directory", new File("src").getAbsolutePath());
  353. ProjectReactorBuilder builder = new ProjectReactorBuilder(new ProcessedScannerProperties(
  354. new RawScannerProperties(props), new EmptyExternalProjectKeyAndOrganization()),
  355. mock(AnalysisWarnings.class));
  356. File baseDir = new File("target/tmp/baseDir");
  357. File workDir = builder.initRootProjectWorkDir(baseDir, props);
  358. assertThat(workDir).isEqualTo(new File("src").getAbsoluteFile());
  359. }
  360. @Test
  361. public void shouldFailIf2ModulesWithSameKey() {
  362. Map<String, String> props = new HashMap<>();
  363. props.put("sonar.projectKey", "root");
  364. ProjectDefinition root = ProjectDefinition.create().setProperties(props);
  365. Map<String, String> props1 = new HashMap<>();
  366. props1.put("sonar.projectKey", "mod1");
  367. root.addSubProject(ProjectDefinition.create().setProperties(props1));
  368. // Check uniqueness of a new module: OK
  369. Map<String, String> props2 = new HashMap<>();
  370. props2.put("sonar.projectKey", "mod2");
  371. ProjectDefinition mod2 = ProjectDefinition.create().setProperties(props2);
  372. ProjectReactorBuilder.checkUniquenessOfChildKey(mod2, root);
  373. // Now, add it and check again
  374. root.addSubProject(mod2);
  375. thrown.expect(MessageException.class);
  376. thrown.expectMessage("Project 'root' can't have 2 modules with the following key: mod2");
  377. ProjectReactorBuilder.checkUniquenessOfChildKey(mod2, root);
  378. }
  379. @Test
  380. public void shouldAcceptNoProjectName() {
  381. ProjectDefinition rootProject = loadProjectDefinition("simple-project-with-missing-project-name");
  382. assertThat(rootProject.getOriginalName()).isNull();
  383. assertThat(rootProject.getName()).isEqualTo("com.foo.project");
  384. }
  385. @Test
  386. public void shouldSetModuleKeyIfNotPresent() {
  387. Map<String, String> props = new HashMap<>();
  388. props.put("sonar.projectVersion", "1.0");
  389. // should be set
  390. ProjectReactorBuilder.setModuleKeyAndNameIfNotDefined(props, "foo", "parent");
  391. assertThat(props.get("sonar.moduleKey")).isEqualTo("parent:foo");
  392. assertThat(props.get("sonar.projectName")).isEqualTo("foo");
  393. // but not this 2nd time
  394. ProjectReactorBuilder.setModuleKeyAndNameIfNotDefined(props, "bar", "parent");
  395. assertThat(props.get("sonar.moduleKey")).isEqualTo("parent:foo");
  396. assertThat(props.get("sonar.projectName")).isEqualTo("foo");
  397. }
  398. private ProjectDefinition loadProjectDefinition(String projectFolder) {
  399. Map<String, String> props = loadProps(projectFolder);
  400. ProcessedScannerProperties bootstrapProps = new ProcessedScannerProperties(
  401. new RawScannerProperties(props),
  402. new EmptyExternalProjectKeyAndOrganization());
  403. ProjectReactor projectReactor = new ProjectReactorBuilder(bootstrapProps, mock(AnalysisWarnings.class)).execute();
  404. return projectReactor.getRoot();
  405. }
  406. protected static Properties toProperties(File propertyFile) {
  407. Properties propsFromFile = new Properties();
  408. try (FileInputStream fileInputStream = new FileInputStream(propertyFile)) {
  409. propsFromFile.load(fileInputStream);
  410. } catch (IOException e) {
  411. throw new IllegalStateException("Impossible to read the property file: " + propertyFile.getAbsolutePath(), e);
  412. }
  413. // Trim properties
  414. for (String propKey : propsFromFile.stringPropertyNames()) {
  415. propsFromFile.setProperty(propKey, StringUtils.trim(propsFromFile.getProperty(propKey)));
  416. }
  417. return propsFromFile;
  418. }
  419. private Map<String, String> loadProps(String projectFolder) {
  420. Map<String, String> props = Maps.newHashMap();
  421. Properties runnerProps = toProperties(getResource(this.getClass(), projectFolder + "/sonar-project.properties"));
  422. for (final String name : runnerProps.stringPropertyNames()) {
  423. props.put(name, runnerProps.getProperty(name));
  424. }
  425. props.put("sonar.projectBaseDir", getResource(this.getClass(), projectFolder).getAbsolutePath());
  426. return props;
  427. }
  428. public Map<String, String> toMap(Properties props) {
  429. Map<String, String> result = new HashMap<>();
  430. for (Map.Entry<Object, Object> entry : props.entrySet()) {
  431. result.put(entry.getKey().toString(), entry.getValue().toString());
  432. }
  433. return result;
  434. }
  435. @Test
  436. public void shouldGetList() {
  437. Map<String, String> props = new HashMap<>();
  438. props.put("prop", " foo ,, bar , toto,tutu");
  439. assertThat(ProjectReactorBuilder.getListFromProperty(props, "prop")).containsOnly("foo", "bar", "toto", "tutu");
  440. }
  441. @Test
  442. public void shouldGetListWithComma() {
  443. Map<String, String> props = new HashMap<>();
  444. props.put("prop", "\"foo,bar\", toto,tutu");
  445. assertThat(ProjectReactorBuilder.getListFromProperty(props, "prop")).containsOnly("foo,bar", "toto", "tutu");
  446. }
  447. @Test
  448. public void shouldGetEmptyList() {
  449. Map<String, String> props = new HashMap<>();
  450. props.put("prop", "");
  451. assertThat(ProjectReactorBuilder.getListFromProperty(props, "prop")).isEmpty();
  452. }
  453. @Test
  454. public void shouldGetListFromFile() throws IOException {
  455. String filePath = "shouldGetList/foo.properties";
  456. Map<String, String> props = loadPropsFromFile(filePath);
  457. assertThat(ProjectReactorBuilder.getListFromProperty(props, "prop")).containsOnly("foo", "bar", "toto", "tutu");
  458. }
  459. @Test
  460. public void doNotMixPropertiesWhenModuleKeyIsPrefixOfAnother() throws IOException {
  461. ProjectDefinition rootProject = loadProjectDefinition("multi-module-definitions-same-prefix");
  462. // CHECK ROOT
  463. assertThat(rootProject.getKey()).isEqualTo("com.foo.project");
  464. assertThat(rootProject.getName()).isEqualTo("Foo Project");
  465. assertThat(rootProject.getVersion()).isEqualTo("1.0-SNAPSHOT");
  466. assertThat(rootProject.getDescription()).isEqualTo("Description of Foo Project");
  467. assertThat(rootProject.sources().contains("sources")).isTrue();
  468. assertThat(rootProject.tests().contains("tests")).isTrue();
  469. // Module properties must have been cleaned
  470. assertThat(rootProject.properties().get("module1.sonar.projectKey")).isNull();
  471. assertThat(rootProject.properties().get("module2.sonar.projectKey")).isNull();
  472. // Check baseDir and workDir
  473. assertThat(rootProject.getBaseDir().getCanonicalFile())
  474. .isEqualTo(getResource(this.getClass(), "multi-module-definitions-same-prefix"));
  475. assertThat(rootProject.getWorkDir().getCanonicalFile())
  476. .isEqualTo(new File(getResource(this.getClass(), "multi-module-definitions-same-prefix"), ".sonar"));
  477. // CHECK MODULES
  478. List<ProjectDefinition> modules = rootProject.getSubProjects();
  479. assertThat(modules.size()).isEqualTo(2);
  480. // Module 1
  481. ProjectDefinition module1 = modules.get(0);
  482. assertThat(module1.getBaseDir().getCanonicalFile()).isEqualTo(getResource(this.getClass(), "multi-module-definitions-same-prefix/module1"));
  483. assertThat(module1.getKey()).isEqualTo("com.foo.project:module1");
  484. assertThat(module1.getName()).isEqualTo("module1");
  485. assertThat(module1.getVersion()).isEqualTo("1.0-SNAPSHOT");
  486. // Description should not be inherited from parent if not set
  487. assertThat(module1.getDescription()).isNull();
  488. assertThat(module1.sources()).contains("sources");
  489. assertThat(module1.tests()).contains("tests");
  490. // and module properties must have been cleaned
  491. assertThat(module1.properties().get("module1.sonar.projectKey")).isNull();
  492. assertThat(module1.properties().get("module2.sonar.projectKey")).isNull();
  493. // Check baseDir and workDir
  494. assertThat(module1.getBaseDir().getCanonicalFile())
  495. .isEqualTo(getResource(this.getClass(), "multi-module-definitions-same-prefix/module1"));
  496. assertThat(module1.getWorkDir().getCanonicalFile())
  497. .isEqualTo(new File(getResource(this.getClass(), "multi-module-definitions-same-prefix"), ".sonar/com.foo.project_module1"));
  498. // Module 1 Feature
  499. ProjectDefinition module1Feature = modules.get(1);
  500. assertThat(module1Feature.getBaseDir().getCanonicalFile()).isEqualTo(getResource(this.getClass(), "multi-module-definitions-same-prefix/module1.feature"));
  501. assertThat(module1Feature.getKey()).isEqualTo("com.foo.project:com.foo.project.module1.feature");
  502. assertThat(module1Feature.getName()).isEqualTo("Foo Module 1 Feature");
  503. assertThat(module1Feature.getVersion()).isEqualTo("1.0-SNAPSHOT");
  504. assertThat(module1Feature.getDescription()).isEqualTo("Description of Module 1 Feature");
  505. assertThat(module1Feature.sources()).contains("src");
  506. assertThat(module1Feature.tests()).contains("tests");
  507. // and module properties must have been cleaned
  508. assertThat(module1Feature.properties().get("module1.sonar.projectKey")).isNull();
  509. assertThat(module1Feature.properties().get("module2.sonar.projectKey")).isNull();
  510. // Check baseDir and workDir
  511. assertThat(module1Feature.getBaseDir().getCanonicalFile())
  512. .isEqualTo(getResource(this.getClass(), "multi-module-definitions-same-prefix/module1.feature"));
  513. assertThat(module1Feature.getWorkDir().getCanonicalFile())
  514. .isEqualTo(new File(getResource(this.getClass(), "multi-module-definitions-same-prefix"), ".sonar/com.foo.project_com.foo.project.module1.feature"));
  515. }
  516. private Map<String, String> loadPropsFromFile(String filePath) throws IOException {
  517. Properties props = new Properties();
  518. try (FileInputStream fileInputStream = new FileInputStream(getResource(this.getClass(), filePath))) {
  519. props.load(fileInputStream);
  520. }
  521. Map<String, String> result = new HashMap<>();
  522. for (Map.Entry<Object, Object> entry : props.entrySet()) {
  523. result.put(entry.getKey().toString(), entry.getValue().toString());
  524. }
  525. return result;
  526. }
  527. /**
  528. * Search for a test resource in the classpath. For example getResource("org/sonar/MyClass/foo.txt");
  529. *
  530. * @param path the starting slash is optional
  531. * @return the resource. Null if resource not found
  532. */
  533. public static File getResource(String path) {
  534. String resourcePath = path;
  535. if (!resourcePath.startsWith("/")) {
  536. resourcePath = "/" + resourcePath;
  537. }
  538. URL url = ProjectReactorBuilderTest.class.getResource(resourcePath);
  539. if (url != null) {
  540. return FileUtils.toFile(url);
  541. }
  542. return null;
  543. }
  544. /**
  545. * Search for a resource in the classpath. For example calling the method getResource(getClass(), "myTestName/foo.txt") from
  546. * the class org.sonar.Foo loads the file $basedir/src/test/resources/org/sonar/Foo/myTestName/foo.txt
  547. *
  548. * @return the resource. Null if resource not found
  549. */
  550. public static File getResource(Class baseClass, String path) {
  551. String resourcePath = StringUtils.replaceChars(baseClass.getCanonicalName(), '.', '/');
  552. if (!path.startsWith("/")) {
  553. resourcePath += "/";
  554. }
  555. resourcePath += path;
  556. return getResource(resourcePath);
  557. }
  558. }