]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6589 Fix badly module uuid persistence
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 27 May 2015 14:03:36 +0000 (16:03 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Wed, 27 May 2015 14:03:48 +0000 (16:03 +0200)
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistComponentsStep.java
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistComponentsStepTest.java

index f73c4c0c3570afa1414c528b3d944209e386c4ee..d1a37aa657909f626e9fb2bb5dd77bb408456705 100644 (file)
@@ -20,7 +20,7 @@
 
 package org.sonar.server.computation.step;
 
-import java.util.HashMap;
+import com.google.common.collect.Maps;
 import java.util.List;
 import java.util.Map;
 import org.apache.commons.io.FilenameUtils;
@@ -32,10 +32,10 @@ import org.sonar.batch.protocol.output.BatchReport;
 import org.sonar.batch.protocol.output.BatchReportReader;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.persistence.DbSession;
+import org.sonar.core.util.NonNullInputFunction;
 import org.sonar.server.computation.ComputationContext;
 import org.sonar.server.computation.component.Component;
 import org.sonar.server.computation.component.DbComponentsRefCache;
-import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
 import org.sonar.server.db.DbClient;
 
 public class PersistComponentsStep implements ComputationStep {
@@ -52,176 +52,206 @@ public class PersistComponentsStep implements ComputationStep {
   public void execute(ComputationContext context) {
     DbSession session = dbClient.openSession(false);
     try {
-      new ComponentDepthTraversalTypeAwareVisitor(session, context).visit(context.getRoot());
+      Component root = context.getRoot();
+      List<ComponentDto> components = dbClient.componentDao().selectComponentsFromProjectKey(session, root.getKey());
+      Map<String, ComponentDto> componentDtosByKey = componentDtosByKey(components);
+      ComponentContext componentContext = new ComponentContext(context.getReportReader(), session, componentDtosByKey);
+
+      ComponentDto projectDto = processProject(root, componentContext.reportReader.readComponent(root.getRef()), componentContext);
+      processChildren(componentContext, root, projectDto, projectDto);
       session.commit();
     } finally {
       session.close();
     }
   }
 
-  private class ComponentDepthTraversalTypeAwareVisitor extends DepthTraversalTypeAwareVisitor {
-
-    private final DbSession session;
-    private final BatchReportReader reportReader;
-    private final Map<String, ComponentDto> componentDtosByKey;
-
-    private Long projectId;
-    private ComponentDto lastModule;
+  private void recursivelyProcessComponent(ComponentContext componentContext, Component component, ComponentDto parentModule, ComponentDto project) {
+    BatchReportReader reportReader = componentContext.reportReader;
+    BatchReport.Component reportComponent = reportReader.readComponent(component.getRef());
+
+    switch (component.getType()) {
+      case MODULE:
+        ComponentDto moduleDto = processModule(component, reportComponent, componentContext, parentModule, project.getId());
+        processChildren(componentContext, component, moduleDto, project);
+        break;
+      case DIRECTORY:
+        processDirectory(component, reportComponent, componentContext, parentModule, project.getId());
+        processChildren(componentContext, component, parentModule, project);
+        break;
+      case FILE:
+        processFile(component, reportComponent, componentContext, parentModule, project.getId());
+        processChildren(componentContext, component, parentModule, project);
+        break;
+      default:
+        throw new IllegalStateException(String.format("Unsupported component type '%s'", component.getType()));
+    }
+  }
 
-    public ComponentDepthTraversalTypeAwareVisitor(DbSession session, ComputationContext context) {
-      super(Component.Type.FILE, Order.PRE_ORDER);
-      this.session = session;
-      this.reportReader = context.getReportReader();
-      this.componentDtosByKey = new HashMap<>();
+  private void processChildren(ComponentContext componentContext, Component component, ComponentDto parentModule, ComponentDto project) {
+    for (Component child : component.getChildren()) {
+      recursivelyProcessComponent(componentContext, child, parentModule, project);
     }
+  }
 
-    @Override
-    public void visitProject(Component project) {
-      List<ComponentDto> components = dbClient.componentDao().selectComponentsFromProjectKey(session, project.getKey());
-      for (ComponentDto componentDto : components) {
-        componentDtosByKey.put(componentDto.getKey(), componentDto);
-      }
+  public ComponentDto processProject(Component project, BatchReport.Component reportComponent, ComponentContext componentContext) {
+    ComponentDto componentDto = createComponentDto(reportComponent, project);
 
-      BatchReport.Component reportComponent = reportReader.readComponent(project.getRef());
-      ComponentDto componentDto = createComponentDto(reportComponent, project);
+    componentDto.setScope(Scopes.PROJECT);
+    componentDto.setQualifier(Qualifiers.PROJECT);
+    componentDto.setName(reportComponent.getName());
+    componentDto.setLongName(componentDto.name());
+    if (reportComponent.hasDescription()) {
+      componentDto.setDescription(reportComponent.getDescription());
+    }
+    componentDto.setProjectUuid(componentDto.uuid());
+    componentDto.setModuleUuidPath(ComponentDto.MODULE_UUID_PATH_SEP + componentDto.uuid() + ComponentDto.MODULE_UUID_PATH_SEP);
 
-      componentDto.setScope(Scopes.PROJECT);
-      componentDto.setQualifier(Qualifiers.PROJECT);
-      componentDto.setName(reportComponent.getName());
-      componentDto.setLongName(componentDto.name());
-      if (reportComponent.hasDescription()) {
-        componentDto.setDescription(reportComponent.getDescription());
-      }
-      componentDto.setProjectUuid(componentDto.uuid());
-      componentDto.setModuleUuidPath(ComponentDto.MODULE_UUID_PATH_SEP + componentDto.uuid() + ComponentDto.MODULE_UUID_PATH_SEP);
+    return persistComponent(project.getRef(), componentDto, componentContext);
+  }
 
-      persistComponent(project.getRef(), componentDto);
+  public ComponentDto processModule(Component module, BatchReport.Component reportComponent, ComponentContext componentContext, ComponentDto lastModule, long projectId) {
+    ComponentDto componentDto = createComponentDto(reportComponent, module);
 
-      lastModule = componentDto;
-      projectId = componentDto.getId();
+    componentDto.setScope(Scopes.PROJECT);
+    componentDto.setQualifier(Qualifiers.MODULE);
+    componentDto.setName(reportComponent.getName());
+    componentDto.setLongName(componentDto.name());
+    if (reportComponent.hasPath()) {
+      componentDto.setPath(reportComponent.getPath());
     }
+    if (reportComponent.hasDescription()) {
+      componentDto.setDescription(reportComponent.getDescription());
+    }
+    componentDto.setParentProjectId(projectId);
+    componentDto.setProjectUuid(lastModule.projectUuid());
+    componentDto.setModuleUuid(lastModule.uuid());
+    componentDto.setModuleUuidPath((lastModule.moduleUuidPath() + componentDto.uuid() + ComponentDto.MODULE_UUID_PATH_SEP));
 
-    @Override
-    public void visitModule(Component module) {
-      BatchReport.Component reportComponent = reportReader.readComponent(module.getRef());
-      ComponentDto componentDto = createComponentDto(reportComponent, module);
-
-      componentDto.setScope(Scopes.PROJECT);
-      componentDto.setQualifier(Qualifiers.MODULE);
-      componentDto.setName(reportComponent.getName());
-      componentDto.setLongName(componentDto.name());
-      if (reportComponent.hasDescription()) {
-        componentDto.setDescription(reportComponent.getDescription());
-      }
-      componentDto.setParentProjectId(projectId);
-      componentDto.setProjectUuid(lastModule.projectUuid());
-      componentDto.setModuleUuid(lastModule.uuid());
-      componentDto.setModuleUuidPath((lastModule.moduleUuidPath() + componentDto.uuid() + ComponentDto.MODULE_UUID_PATH_SEP));
+    return persistComponent(module.getRef(), componentDto, componentContext);
+  }
 
-      persistComponent(module.getRef(), componentDto);
+  public void processDirectory(Component directory, BatchReport.Component reportComponent, ComponentContext componentContext, ComponentDto lastModule, long projectId) {
+    ComponentDto componentDto = createComponentDto(reportComponent, directory);
 
-      lastModule = componentDto;
+    componentDto.setScope(Scopes.DIRECTORY);
+    componentDto.setQualifier(Qualifiers.DIRECTORY);
+    componentDto.setName(reportComponent.getPath());
+    componentDto.setLongName(reportComponent.getPath());
+    if (reportComponent.hasPath()) {
+      componentDto.setPath(reportComponent.getPath());
     }
 
-    @Override
-    public void visitDirectory(Component directory) {
-      BatchReport.Component reportComponent = reportReader.readComponent(directory.getRef());
-      ComponentDto componentDto = createComponentDto(reportComponent, directory);
+    componentDto.setParentProjectId(lastModule.getId());
+    componentDto.setProjectUuid(lastModule.projectUuid());
+    componentDto.setModuleUuid(lastModule.uuid());
+    componentDto.setModuleUuidPath(lastModule.moduleUuidPath());
 
-      componentDto.setScope(Scopes.DIRECTORY);
-      componentDto.setQualifier(Qualifiers.DIRECTORY);
-      componentDto.setName(reportComponent.getPath());
-      componentDto.setLongName(reportComponent.getPath());
-      if (reportComponent.hasPath()) {
-        componentDto.setPath(reportComponent.getPath());
-      }
+    persistComponent(directory.getRef(), componentDto, componentContext);
+  }
 
-      componentDto.setParentProjectId(lastModule.getId());
-      componentDto.setProjectUuid(lastModule.projectUuid());
-      componentDto.setModuleUuid(lastModule.uuid());
-      componentDto.setModuleUuidPath(lastModule.moduleUuidPath());
+  public void processFile(Component file, BatchReport.Component reportComponent, ComponentContext componentContext, ComponentDto lastModule, long projectId) {
+    ComponentDto componentDto = createComponentDto(reportComponent, file);
 
-      persistComponent(directory.getRef(), componentDto);
+    componentDto.setScope(Scopes.FILE);
+    componentDto.setQualifier(getFileQualifier(reportComponent));
+    componentDto.setName(FilenameUtils.getName(reportComponent.getPath()));
+    componentDto.setLongName(reportComponent.getPath());
+    if (reportComponent.hasPath()) {
+      componentDto.setPath(reportComponent.getPath());
+    }
+    if (reportComponent.hasLanguage()) {
+      componentDto.setLanguage(reportComponent.getLanguage());
     }
 
-    @Override
-    public void visitFile(Component file) {
-      BatchReport.Component reportComponent = reportReader.readComponent(file.getRef());
-      ComponentDto componentDto = createComponentDto(reportComponent, file);
-
-      componentDto.setScope(Scopes.FILE);
-      componentDto.setQualifier(getFileQualifier(reportComponent));
-      componentDto.setName(FilenameUtils.getName(reportComponent.getPath()));
-      componentDto.setLongName(reportComponent.getPath());
-      if (reportComponent.hasPath()) {
-        componentDto.setPath(reportComponent.getPath());
-      }
-      if (reportComponent.hasLanguage()) {
-        componentDto.setLanguage(reportComponent.getLanguage());
-      }
+    componentDto.setParentProjectId(lastModule.getId());
+    componentDto.setProjectUuid(lastModule.projectUuid());
+    componentDto.setModuleUuid(lastModule.uuid());
+    componentDto.setModuleUuidPath(lastModule.moduleUuidPath());
 
-      componentDto.setParentProjectId(lastModule.getId());
-      componentDto.setProjectUuid(lastModule.projectUuid());
-      componentDto.setModuleUuid(lastModule.uuid());
-      componentDto.setModuleUuidPath(lastModule.moduleUuidPath());
+    persistComponent(file.getRef(), componentDto, componentContext);
+  }
 
-      persistComponent(file.getRef(), componentDto);
-    }
+  private ComponentDto createComponentDto(BatchReport.Component reportComponent, Component component) {
+    String componentKey = component.getKey();
+    String componentUuid = component.getUuid();
 
-    private ComponentDto createComponentDto(BatchReport.Component reportComponent, Component component) {
-      String componentKey = component.getKey();
-      String componentUuid = component.getUuid();
+    ComponentDto componentDto = new ComponentDto();
+    componentDto.setUuid(componentUuid);
+    componentDto.setKey(componentKey);
+    componentDto.setDeprecatedKey(componentKey);
+    componentDto.setEnabled(true);
+    return componentDto;
+  }
 
-      ComponentDto componentDto = new ComponentDto();
-      componentDto.setUuid(componentUuid);
-      componentDto.setKey(componentKey);
-      componentDto.setDeprecatedKey(componentKey);
-      componentDto.setEnabled(true);
+  private ComponentDto persistComponent(int componentRef, ComponentDto componentDto, ComponentContext componentContext) {
+    ComponentDto existingComponent = componentContext.componentDtosByKey.get(componentDto.getKey());
+    if (existingComponent == null) {
+      dbClient.componentDao().insert(componentContext.dbSession, componentDto);
+      dbComponentsRefCache.addComponent(componentRef, new DbComponentsRefCache.DbComponent(componentDto.getId(), componentDto.getKey(), componentDto.uuid()));
       return componentDto;
-    }
-
-    private void persistComponent(int componentRef, ComponentDto componentDto) {
-      ComponentDto existingComponent = componentDtosByKey.get(componentDto.getKey());
-      if (existingComponent == null) {
-        dbClient.componentDao().insert(session, componentDto);
-      } else {
-        componentDto.setId(existingComponent.getId());
-        componentDto.setParentProjectId(existingComponent.parentProjectId());
-        if (updateComponent(existingComponent, componentDto)) {
-          dbClient.componentDao().update(session, componentDto);
-        }
+    } else {
+      if (updateComponent(existingComponent, componentDto)) {
+        dbClient.componentDao().update(componentContext.dbSession, existingComponent);
       }
-      dbComponentsRefCache.addComponent(componentRef, new DbComponentsRefCache.DbComponent(componentDto.getId(), componentDto.getKey(), componentDto.uuid()));
+      dbComponentsRefCache.addComponent(componentRef, new DbComponentsRefCache.DbComponent(existingComponent.getId(), existingComponent.getKey(), existingComponent.uuid()));
+      return existingComponent;
     }
+  }
 
-    private boolean updateComponent(ComponentDto existingComponent, ComponentDto newComponent) {
-      boolean isUpdated = false;
-      if (Scopes.PROJECT.equals(existingComponent.scope())) {
-        if (!newComponent.name().equals(existingComponent.name())) {
-          isUpdated = true;
-        }
-        if (!StringUtils.equals(existingComponent.description(), newComponent.description())) {
-          isUpdated = true;
-        }
-      }
-
-      if (!StringUtils.equals(existingComponent.moduleUuid(), newComponent.moduleUuid())) {
-        isUpdated = true;
-      }
-      if (!existingComponent.moduleUuidPath().equals(newComponent.moduleUuidPath())) {
-        isUpdated = true;
-      }
-      if (!ObjectUtils.equals(existingComponent.parentProjectId(), newComponent.parentProjectId())) {
-        isUpdated = true;
-      }
-      return isUpdated;
+  private static boolean updateComponent(ComponentDto existingComponent, ComponentDto newComponent) {
+    boolean isUpdated = false;
+    if (!StringUtils.equals(existingComponent.name(), newComponent.name())) {
+      existingComponent.setName(newComponent.name());
+      isUpdated = true;
+    }
+    if (!StringUtils.equals(existingComponent.description(), newComponent.description())) {
+      existingComponent.setDescription(newComponent.description());
+      isUpdated = true;
+    }
+    if (!StringUtils.equals(existingComponent.path(), newComponent.path())) {
+      existingComponent.setPath(newComponent.path());
+      isUpdated = true;
     }
+    if (!StringUtils.equals(existingComponent.moduleUuid(), newComponent.moduleUuid())) {
+      existingComponent.setModuleUuid(newComponent.moduleUuid());
+      isUpdated = true;
+    }
+    if (!existingComponent.moduleUuidPath().equals(newComponent.moduleUuidPath())) {
+      existingComponent.setModuleUuidPath(newComponent.moduleUuidPath());
+      isUpdated = true;
+    }
+    if (!ObjectUtils.equals(existingComponent.parentProjectId(), newComponent.parentProjectId())) {
+      existingComponent.setParentProjectId(newComponent.parentProjectId());
+      isUpdated = true;
+    }
+    return isUpdated;
   }
 
   private static String getFileQualifier(BatchReport.Component reportComponent) {
     return reportComponent.getIsTest() ? Qualifiers.UNIT_TEST_FILE : Qualifiers.FILE;
   }
 
+  private Map<String, ComponentDto> componentDtosByKey(List<ComponentDto> components) {
+    return Maps.uniqueIndex(components, new NonNullInputFunction<ComponentDto, String>() {
+      @Override
+      public String doApply(ComponentDto input) {
+        return input.key();
+      }
+    });
+  }
+
+  private static class ComponentContext {
+    private final BatchReportReader reportReader;
+    private final Map<String, ComponentDto> componentDtosByKey;
+    private final DbSession dbSession;
+
+    public ComponentContext(BatchReportReader reportReader, DbSession dbSession, Map<String, ComponentDto> componentDtosByKey) {
+      this.reportReader = reportReader;
+      this.componentDtosByKey = componentDtosByKey;
+      this.dbSession = dbSession;
+    }
+  }
+
   @Override
   public String getDescription() {
     return "Feed components cache";
index e63df67eb77680941e9e0463cfde7008301cdc79..415918e0986195a7ec8ea09d446b13530fe1a69f 100644 (file)
@@ -20,6 +20,7 @@
 
 package org.sonar.server.computation.step;
 
+import java.io.File;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.ClassRule;
@@ -46,8 +47,6 @@ import org.sonar.server.computation.language.LanguageRepository;
 import org.sonar.server.db.DbClient;
 import org.sonar.test.DbTests;
 
-import java.io.File;
-
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.mockito.Mockito.mock;
 
@@ -118,6 +117,7 @@ public class PersistComponentsStepTest extends BaseStepTest {
       .setRef(2)
       .setType(Constants.ComponentType.MODULE)
       .setKey("MODULE_KEY")
+      .setPath("module")
       .setName("Module")
       .setDescription("Module description")
       .addChildRef(3)
@@ -148,6 +148,7 @@ public class PersistComponentsStepTest extends BaseStepTest {
     assertThat(project).isNotNull();
     assertThat(project.name()).isEqualTo("Project");
     assertThat(project.description()).isEqualTo("Project description");
+    assertThat(project.path()).isNull();
     assertThat(project.uuid()).isEqualTo("ABCD");
     assertThat(project.moduleUuid()).isNull();
     assertThat(project.moduleUuidPath()).isEqualTo("." + project.uuid() + ".");
@@ -160,6 +161,7 @@ public class PersistComponentsStepTest extends BaseStepTest {
     assertThat(module).isNotNull();
     assertThat(module.name()).isEqualTo("Module");
     assertThat(module.description()).isEqualTo("Module description");
+    assertThat(module.path()).isEqualTo("module");
     assertThat(module.uuid()).isEqualTo("BCDE");
     assertThat(module.moduleUuid()).isEqualTo(project.uuid());
     assertThat(module.moduleUuidPath()).isEqualTo(project.moduleUuidPath() + module.uuid() + ".");
@@ -171,6 +173,7 @@ public class PersistComponentsStepTest extends BaseStepTest {
     ComponentDto directory = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:src/main/java/dir");
     assertThat(directory).isNotNull();
     assertThat(directory.name()).isEqualTo("src/main/java/dir");
+    assertThat(directory.description()).isNull();
     assertThat(directory.path()).isEqualTo("src/main/java/dir");
     assertThat(directory.uuid()).isEqualTo("CDEF");
     assertThat(directory.moduleUuid()).isEqualTo(module.uuid());
@@ -183,6 +186,7 @@ public class PersistComponentsStepTest extends BaseStepTest {
     ComponentDto file = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:src/main/java/dir/Foo.java");
     assertThat(file).isNotNull();
     assertThat(file.name()).isEqualTo("Foo.java");
+    assertThat(file.description()).isNull();
     assertThat(file.path()).isEqualTo("src/main/java/dir/Foo.java");
     assertThat(file.language()).isEqualTo("java");
     assertThat(file.uuid()).isEqualTo("DEFG");
@@ -435,6 +439,76 @@ public class PersistComponentsStepTest extends BaseStepTest {
     assertThat(directory.parentProjectId()).isEqualTo(subModule2.getId());
   }
 
+  @Test
+  public void persist_multi_modules() throws Exception {
+    File reportDir = temp.newFolder();
+    BatchReportWriter writer = new BatchReportWriter(reportDir);
+    writer.writeMetadata(BatchReport.Metadata.newBuilder()
+      .setRootComponentRef(1)
+      .build());
+
+    writer.writeComponent(BatchReport.Component.newBuilder()
+      .setRef(1)
+      .setType(Constants.ComponentType.PROJECT)
+      .setKey(PROJECT_KEY)
+      .setName("Project")
+      .addChildRef(2)
+      .addChildRef(4)
+      .build());
+    writer.writeComponent(BatchReport.Component.newBuilder()
+      .setRef(2)
+      .setType(Constants.ComponentType.MODULE)
+      .setKey("MODULE_A")
+      .setName("Module A")
+      .addChildRef(3)
+      .build());
+    writer.writeComponent(BatchReport.Component.newBuilder()
+      .setRef(3)
+      .setType(Constants.ComponentType.MODULE)
+      .setKey("SUB_MODULE_A")
+      .setName("Sub Module A")
+      .build());
+    writer.writeComponent(BatchReport.Component.newBuilder()
+      .setRef(4)
+      .setType(Constants.ComponentType.MODULE)
+      .setKey("MODULE_B")
+      .setName("Module B")
+      .build());
+
+    DumbComponent root = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
+      new DumbComponent(Component.Type.MODULE, 2, "BCDE", "MODULE_A",
+        new DumbComponent(Component.Type.MODULE, 3, "DEFG", "SUB_MODULE_A")),
+      new DumbComponent(Component.Type.MODULE, 4, "CDEF", "MODULE_B"));
+    sut.execute(new ComputationContext(new BatchReportReader(reportDir), PROJECT_KEY, projectSettings,
+      dbClient, ComponentTreeBuilders.from(root), languageRepository));
+
+    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
+
+    ComponentDto project = dbClient.componentDao().selectNullableByKey(session, PROJECT_KEY);
+    assertThat(project).isNotNull();
+    assertThat(project.moduleUuid()).isNull();
+    assertThat(project.moduleUuidPath()).isEqualTo("." + project.uuid() + ".");
+    assertThat(project.parentProjectId()).isNull();
+
+    ComponentDto moduleA = dbClient.componentDao().selectNullableByKey(session, "MODULE_A");
+    assertThat(moduleA).isNotNull();
+    assertThat(moduleA.moduleUuid()).isEqualTo(project.uuid());
+    assertThat(moduleA.moduleUuidPath()).isEqualTo(project.moduleUuidPath() + moduleA.uuid() + ".");
+    assertThat(moduleA.parentProjectId()).isEqualTo(project.getId());
+
+    ComponentDto subModuleA = dbClient.componentDao().selectNullableByKey(session, "SUB_MODULE_A");
+    assertThat(subModuleA).isNotNull();
+    assertThat(subModuleA.moduleUuid()).isEqualTo(moduleA.uuid());
+    assertThat(subModuleA.moduleUuidPath()).isEqualTo(moduleA.moduleUuidPath() + subModuleA.uuid() + ".");
+    assertThat(subModuleA.parentProjectId()).isEqualTo(project.getId());
+
+    ComponentDto moduleB = dbClient.componentDao().selectNullableByKey(session, "MODULE_B");
+    assertThat(moduleB).isNotNull();
+    assertThat(moduleB.moduleUuid()).isEqualTo(project.uuid());
+    assertThat(moduleB.moduleUuidPath()).isEqualTo(project.moduleUuidPath() + moduleB.uuid() + ".");
+    assertThat(moduleB.parentProjectId()).isEqualTo(project.getId());
+  }
+
   @Test
   public void nothing_to_persist() throws Exception {
     ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
@@ -529,10 +603,10 @@ public class PersistComponentsStepTest extends BaseStepTest {
   }
 
   @Test
-  public void update_name_and_description() throws Exception {
+  public void update_module_name() throws Exception {
     ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
     dbClient.componentDao().insert(session, project);
-    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module");
+    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module").setPath("path");
     dbClient.componentDao().insert(session, module);
     session.commit();
 
@@ -547,7 +621,6 @@ public class PersistComponentsStepTest extends BaseStepTest {
       .setType(Constants.ComponentType.PROJECT)
       .setKey(PROJECT_KEY)
       .setName("New project name")
-      .setDescription("New project description")
       .addChildRef(2)
       .build());
     writer.writeComponent(BatchReport.Component.newBuilder()
@@ -555,7 +628,7 @@ public class PersistComponentsStepTest extends BaseStepTest {
       .setType(Constants.ComponentType.MODULE)
       .setKey("MODULE_KEY")
       .setName("New module name")
-      .setDescription("New module description")
+      .setPath("New path")
       .build());
 
     DumbComponent root = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
@@ -565,13 +638,91 @@ public class PersistComponentsStepTest extends BaseStepTest {
 
     ComponentDto projectReloaded = dbClient.componentDao().selectNullableByKey(session, PROJECT_KEY);
     assertThat(projectReloaded.name()).isEqualTo("New project name");
-    assertThat(projectReloaded.description()).isEqualTo("New project description");
 
     ComponentDto moduleReloaded = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY");
     assertThat(moduleReloaded.name()).isEqualTo("New module name");
+  }
+
+  @Test
+  public void update_module_description() throws Exception {
+    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project").setDescription("Project description");
+    dbClient.componentDao().insert(session, project);
+    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module");
+    dbClient.componentDao().insert(session, module);
+    session.commit();
+
+    File reportDir = temp.newFolder();
+    BatchReportWriter writer = new BatchReportWriter(reportDir);
+    writer.writeMetadata(BatchReport.Metadata.newBuilder()
+      .setRootComponentRef(1)
+      .build());
+
+    writer.writeComponent(BatchReport.Component.newBuilder()
+      .setRef(1)
+      .setType(Constants.ComponentType.PROJECT)
+      .setKey(PROJECT_KEY)
+      .setName("Project")
+      .setDescription("New project description")
+      .addChildRef(2)
+      .build());
+    writer.writeComponent(BatchReport.Component.newBuilder()
+      .setRef(2)
+      .setType(Constants.ComponentType.MODULE)
+      .setKey("MODULE_KEY")
+      .setName("Module")
+      .setDescription("New module description")
+      .build());
+
+    DumbComponent root = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
+      new DumbComponent(Component.Type.MODULE, 2, "BCDE", "MODULE_KEY"));
+    sut.execute(new ComputationContext(new BatchReportReader(reportDir), PROJECT_KEY, projectSettings,
+      dbClient, ComponentTreeBuilders.from(root), languageRepository));
+
+    ComponentDto projectReloaded = dbClient.componentDao().selectNullableByKey(session, PROJECT_KEY);
+    assertThat(projectReloaded.description()).isEqualTo("New project description");
+
+    ComponentDto moduleReloaded = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY");
     assertThat(moduleReloaded.description()).isEqualTo("New module description");
   }
 
+  @Test
+  public void update_module_path() throws Exception {
+    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
+    dbClient.componentDao().insert(session, project);
+    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module").setPath("path");
+    dbClient.componentDao().insert(session, module);
+    session.commit();
+
+    File reportDir = temp.newFolder();
+    BatchReportWriter writer = new BatchReportWriter(reportDir);
+    writer.writeMetadata(BatchReport.Metadata.newBuilder()
+      .setRootComponentRef(1)
+      .build());
+
+    writer.writeComponent(BatchReport.Component.newBuilder()
+      .setRef(1)
+      .setType(Constants.ComponentType.PROJECT)
+      .setKey(PROJECT_KEY)
+      .setName("Project")
+      .addChildRef(2)
+      .build());
+    writer.writeComponent(BatchReport.Component.newBuilder()
+      .setRef(2)
+      .setType(Constants.ComponentType.MODULE)
+      .setKey("MODULE_KEY")
+      .setName("Module")
+      .setPath("New path")
+      .build());
+
+    DumbComponent root = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
+      new DumbComponent(Component.Type.MODULE, 2, "BCDE", "MODULE_KEY"));
+    sut.execute(new ComputationContext(new BatchReportReader(reportDir), PROJECT_KEY, projectSettings,
+      dbClient, ComponentTreeBuilders.from(root), languageRepository));
+
+    ComponentDto moduleReloaded = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY");
+    assertThat(moduleReloaded.path()).isEqualTo("New path");
+  }
+
   @Test
   public void update_module_uuid_when_moving_a_module() throws Exception {
     ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");