Skip to content

Commit

Permalink
SONAR-6665 Fix StackOverflow error when analyzing project with severa…
Browse files Browse the repository at this point in the history
…l modules having same key
  • Loading branch information
henryju committed Sep 25, 2015
1 parent 6571831 commit 2e24cfd
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 77 deletions.

This file was deleted.

This file was deleted.

This file was deleted.

21 changes: 3 additions & 18 deletions it/it-tests/src/test/java/batch/suite/ProjectBuilderTest.java
Expand Up @@ -5,18 +5,15 @@
*/ */
package batch.suite; package batch.suite;


import static org.assertj.core.api.Assertions.assertThat;

import com.sonar.orchestrator.build.BuildFailureException;

import com.sonar.orchestrator.build.SonarRunner;
import util.ItUtils;
import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.Orchestrator;
import com.sonar.orchestrator.build.MavenBuild; import com.sonar.orchestrator.build.MavenBuild;
import org.junit.ClassRule; import org.junit.ClassRule;
import org.junit.Test; import org.junit.Test;
import org.sonar.wsclient.services.Resource; import org.sonar.wsclient.services.Resource;
import org.sonar.wsclient.services.ResourceQuery; import org.sonar.wsclient.services.ResourceQuery;
import util.ItUtils;

import static org.assertj.core.api.Assertions.assertThat;


/** /**
* Test the extension point org.sonar.api.batch.bootstrap.ProjectBuilder * Test the extension point org.sonar.api.batch.bootstrap.ProjectBuilder
Expand Down Expand Up @@ -47,18 +44,6 @@ public void shouldDefineProjectFromPlugin() {
assertThat(getResource("com.sonarsource.it.projects.batch:project-builder-module-b:src/IgnoredFile.java")).isNull(); assertThat(getResource("com.sonarsource.it.projects.batch:project-builder-module-b:src/IgnoredFile.java")).isNull();
} }


@Test
// SONAR-6665
public void errorSubModuleSameName() {
SonarRunner build = SonarRunner.create(ItUtils.projectDir("batch/multi-module-repeated-names"));

try {
orchestrator.executeBuild(build);
} catch (BuildFailureException e) {
assertThat(e.getResult().getLogs()).contains("Two modules have the same id: module1");
}
}

private void checkProject() { private void checkProject() {
Resource project = getResource("com.sonarsource.it.projects.batch:project-builder"); Resource project = getResource("com.sonarsource.it.projects.batch:project-builder");


Expand Down
Expand Up @@ -117,21 +117,22 @@ public ProjectReactorBuilder(AnalysisProperties props, AnalysisMode analysisMode


public ProjectReactor execute() { public ProjectReactor execute() {
Profiler profiler = Profiler.create(LOG).startInfo("Process project properties"); Profiler profiler = Profiler.create(LOG).startInfo("Process project properties");
Map<String, Map<String, String>> propertiesByModuleId = new HashMap<>(); Map<String, Map<String, String>> propertiesByModuleIdPath = new HashMap<>();
extractPropertiesByModule(propertiesByModuleId, "", taskProps.properties()); extractPropertiesByModule(propertiesByModuleIdPath, "", "", taskProps.properties());
ProjectDefinition rootProject = defineRootProject(propertiesByModuleId.get(""), null); ProjectDefinition rootProject = defineRootProject(propertiesByModuleIdPath.get(""), null);
rootProjectWorkDir = rootProject.getWorkDir(); rootProjectWorkDir = rootProject.getWorkDir();
defineChildren(rootProject, propertiesByModuleId); defineChildren(rootProject, propertiesByModuleIdPath, "");
cleanAndCheckProjectDefinitions(rootProject); cleanAndCheckProjectDefinitions(rootProject);
// Since task properties are now empty we should add root module properties // Since task properties are now empty we should add root module properties
taskProps.properties().putAll(propertiesByModuleId.get("")); taskProps.properties().putAll(propertiesByModuleIdPath.get(""));
profiler.stopDebug(); profiler.stopDebug();
return new ProjectReactor(rootProject); return new ProjectReactor(rootProject);
} }


private static void extractPropertiesByModule(Map<String, Map<String, String>> propertiesByModuleId, String currentModuleId, Map<String, String> parentProperties) { private static void extractPropertiesByModule(Map<String, Map<String, String>> propertiesByModuleIdPath, String currentModuleId, String currentModuleIdPath,
if (propertiesByModuleId.containsKey(currentModuleId)) { Map<String, String> parentProperties) {
throw new IllegalStateException(String.format("Two modules have the same id: %s. Each module must have a unique id.", currentModuleId)); if (propertiesByModuleIdPath.containsKey(currentModuleIdPath)) {
throw new IllegalStateException(String.format("Two modules have the same id: '%s'. Each module must have a unique id.", currentModuleId));
} }


Map<String, String> currentModuleProperties = new HashMap<>(); Map<String, String> currentModuleProperties = new HashMap<>();
Expand All @@ -153,10 +154,11 @@ private static void extractPropertiesByModule(Map<String, Map<String, String>> p
Arrays.sort(moduleIds); Arrays.sort(moduleIds);
ArrayUtils.reverse(moduleIds); ArrayUtils.reverse(moduleIds);


propertiesByModuleId.put(currentModuleId, currentModuleProperties); propertiesByModuleIdPath.put(currentModuleIdPath, currentModuleProperties);


for (String moduleId : moduleIds) { for (String moduleId : moduleIds) {
extractPropertiesByModule(propertiesByModuleId, moduleId, currentModuleProperties); String subModuleIdPath = currentModuleIdPath.isEmpty() ? moduleId : (currentModuleIdPath + "." + moduleId);
extractPropertiesByModule(propertiesByModuleIdPath, moduleId, subModuleIdPath, currentModuleProperties);
} }
} }


Expand Down Expand Up @@ -232,16 +234,17 @@ private static File initModuleBuildDir(File moduleBaseDir, Map<String, String> m
return new File(moduleBaseDir, customBuildDir.getPath()); return new File(moduleBaseDir, customBuildDir.getPath());
} }


private void defineChildren(ProjectDefinition parentProject, Map<String, Map<String, String>> propertiesByModuleId) { private void defineChildren(ProjectDefinition parentProject, Map<String, Map<String, String>> propertiesByModuleIdPath, String parentModuleIdPath) {
Map<String, String> parentProps = parentProject.properties(); Map<String, String> parentProps = parentProject.properties();
if (parentProps.containsKey(PROPERTY_MODULES)) { if (parentProps.containsKey(PROPERTY_MODULES)) {
for (String moduleId : getListFromProperty(parentProps, PROPERTY_MODULES)) { for (String moduleId : getListFromProperty(parentProps, PROPERTY_MODULES)) {
Map<String, String> moduleProps = propertiesByModuleId.get(moduleId); String moduleIdPath = parentModuleIdPath.isEmpty() ? moduleId : (parentModuleIdPath + "." + moduleId);
Map<String, String> moduleProps = propertiesByModuleIdPath.get(moduleIdPath);
ProjectDefinition childProject = loadChildProject(parentProject, moduleProps, moduleId); ProjectDefinition childProject = loadChildProject(parentProject, moduleProps, moduleId);
// check the uniqueness of the child key // check the uniqueness of the child key
checkUniquenessOfChildKey(childProject, parentProject); checkUniquenessOfChildKey(childProject, parentProject);
// the child project may have children as well // the child project may have children as well
defineChildren(childProject, propertiesByModuleId); defineChildren(childProject, propertiesByModuleIdPath, moduleIdPath);
// and finally add this child project to its parent // and finally add this child project to its parent
parentProject.addSubProject(childProject); parentProject.addSubProject(childProject);
} }
Expand Down
Expand Up @@ -19,43 +19,41 @@
*/ */
package org.sonar.batch.scan; package org.sonar.batch.scan;


import org.apache.commons.lang.StringUtils;
import org.junit.Before;
import org.sonar.api.batch.AnalysisMode;
import org.sonar.batch.analysis.AnalysisProperties;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.test.TestUtils;

import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import org.apache.commons.lang.StringUtils;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.bootstrap.ProjectDefinition;
import org.sonar.api.batch.bootstrap.ProjectReactor;
import org.sonar.batch.analysis.AnalysisProperties;
import org.sonar.test.TestUtils;


import static org.mockito.Mockito.when;

import static org.mockito.Mockito.mock;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;


public class ProjectReactorBuilderTest { public class ProjectReactorBuilderTest {


@Rule @Rule
public ExpectedException thrown = ExpectedException.none(); public ExpectedException thrown = ExpectedException.none();


private AnalysisMode mode; private AnalysisMode mode;

@Before @Before
public void setUp() { public void setUp() {
mode = mock(AnalysisMode.class); mode = mock(AnalysisMode.class);
} }

@Test @Test
public void shouldDefineSimpleProject() { public void shouldDefineSimpleProject() {
ProjectDefinition projectDefinition = loadProjectDefinition("simple-project"); ProjectDefinition projectDefinition = loadProjectDefinition("simple-project");
Expand Down Expand Up @@ -91,10 +89,28 @@ public void shouldNotFailIfBlankSourceDirectory() {
} }


@Test @Test
public void modulesRepeatedIds() { public void modulesDuplicateIds() {
thrown.expect(IllegalStateException.class); thrown.expect(IllegalStateException.class);
thrown.expectMessage("Two modules have the same id: module1"); thrown.expectMessage("Two modules have the same id: 'module1'. Each module must have a unique id.");
loadProjectDefinition("multi-module-repeated-id");
loadProjectDefinition("multi-module-duplicate-id");
}

@Test
public void modulesRepeatedIds() {
ProjectDefinition rootProject = loadProjectDefinition("multi-module-repeated-id");

List<ProjectDefinition> modules = rootProject.getSubProjects();
assertThat(modules.size()).isEqualTo(1);
// Module 1
ProjectDefinition module1 = modules.get(0);
assertThat(module1.getKey()).isEqualTo("com.foo.project:module1");
assertThat(module1.getName()).isEqualTo("Foo Module 1");

// Module 1 -> Module 1
ProjectDefinition module1_module1 = module1.getSubProjects().get(0);
assertThat(module1_module1.getKey()).isEqualTo("com.foo.project:module1:module1");
assertThat(module1_module1.getName()).isEqualTo("Foo Sub Module 1");
} }


@Test @Test
Expand Down Expand Up @@ -460,12 +476,12 @@ public void shouldInitRootWorkDir() {


assertThat(workDir).isEqualTo(new File(baseDir, ".sonar")); assertThat(workDir).isEqualTo(new File(baseDir, ".sonar"));
} }

@Test @Test
public void nonAssociatedMode() { public void nonAssociatedMode() {
when(mode.isIssues()).thenReturn(true); when(mode.isIssues()).thenReturn(true);
ProjectDefinition project = loadProjectDefinition("multi-module-with-basedir-not-associated"); ProjectDefinition project = loadProjectDefinition("multi-module-with-basedir-not-associated");

assertThat(project.getKey()).isEqualTo("project"); assertThat(project.getKey()).isEqualTo("project");
} }


Expand Down Expand Up @@ -537,10 +553,10 @@ public void shouldSetModuleKeyIfNotPresent() {
private ProjectDefinition loadProjectDefinition(String projectFolder) { private ProjectDefinition loadProjectDefinition(String projectFolder) {
Map<String, String> props = loadProps(projectFolder); Map<String, String> props = loadProps(projectFolder);
AnalysisProperties bootstrapProps = new AnalysisProperties(props, null); AnalysisProperties bootstrapProps = new AnalysisProperties(props, null);
ProjectReactor projectReactor = new ProjectReactorBuilder(bootstrapProps,mode).execute(); ProjectReactor projectReactor = new ProjectReactorBuilder(bootstrapProps, mode).execute();
return projectReactor.getRoot(); return projectReactor.getRoot();
} }

protected static Properties toProperties(File propertyFile) { protected static Properties toProperties(File propertyFile) {
Properties propsFromFile = new Properties(); Properties propsFromFile = new Properties();
try (FileInputStream fileInputStream = new FileInputStream(propertyFile)) { try (FileInputStream fileInputStream = new FileInputStream(propertyFile)) {
Expand Down
@@ -0,0 +1,12 @@
sonar.projectKey=com.foo.project
sonar.projectName=Foo Project
sonar.projectVersion=1.0-SNAPSHOT
sonar.projectDescription=Description of Foo Project

sonar.sources=sources
sonar.tests=tests
sonar.binaries=target/classes

sonar.modules=module1,module1

module1.sonar.sources=src
Expand Up @@ -10,10 +10,8 @@ sonar.binaries=target/classes
sonar.modules=module1 sonar.modules=module1


module1.sonar.projectBaseDir=modules/module1 module1.sonar.projectBaseDir=modules/module1
module1.sonar.projectKey=com.foo.project.module1
module1.sonar.projectName=Foo Module 1 module1.sonar.projectName=Foo Module 1
module1.sonar.modules=module1 module1.sonar.modules=module1


module1.module1.sonar.projectBaseDir=module1 module1.module1.sonar.projectBaseDir=module1
module1.module1.sonar.projectKey=com.foo.project.module1.module1
module1.module1.sonar.projectName=Foo Sub Module 1 module1.module1.sonar.projectName=Foo Sub Module 1

0 comments on commit 2e24cfd

Please sign in to comment.