]> source.dussan.org Git - sonarqube.git/commitdiff
PersistComponentsStep now supports Views components
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Fri, 4 Sep 2015 15:29:24 +0000 (17:29 +0200)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Tue, 8 Sep 2015 16:12:22 +0000 (18:12 +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 [deleted file]
server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportPersistComponentsStepTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsPersistComponentsStepTest.java [new file with mode: 0644]

index 6eebdf77432d8d57a10782d0ed4cfa85398d3106..65224e1f51bd9758270a3575ee60f91a553fd2a3 100644 (file)
@@ -44,6 +44,7 @@ import org.sonar.server.computation.component.PathAwareVisitorAdapter;
 import org.sonar.server.computation.component.TreeRootHolder;
 
 import static com.google.common.collect.FluentIterable.from;
+import static org.sonar.db.component.ComponentDto.MODULE_UUID_PATH_SEP;
 import static org.sonar.server.computation.component.ComponentVisitor.Order.PRE_ORDER;
 
 /**
@@ -103,18 +104,27 @@ public class PersistComponentsStep implements ComputationStep {
     private final DbSession dbSession;
 
     public PersistComponentStepsVisitor(Map<String, ComponentDto> existingComponentDtosByKey, DbSession dbSession) {
-      super(CrawlerDepthLimit.FILE, PRE_ORDER, new SimpleStackElementFactory<ComponentDtoHolder>() {
-        @Override
-        public ComponentDtoHolder createForAny(Component component) {
-          return new ComponentDtoHolder();
-        }
-
-        @Override
-        public ComponentDtoHolder createForFile(Component file) {
-          // no need to create holder for file since they are leaves of the Component tree
-          return null;
-        }
-      });
+      super(
+        CrawlerDepthLimit.LEAVES,
+        PRE_ORDER,
+        new SimpleStackElementFactory<ComponentDtoHolder>() {
+          @Override
+          public ComponentDtoHolder createForAny(Component component) {
+            return new ComponentDtoHolder();
+          }
+
+          @Override
+          public ComponentDtoHolder createForFile(Component file) {
+            // no need to create holder for file since they are always leaves of the Component tree
+            return null;
+          }
+
+          @Override
+          public ComponentDtoHolder createForProjectView(Component projectView) {
+            // no need to create holder for file since they are always leaves of the Component tree
+            return null;
+          }
+        });
       this.existingComponentDtosByKey = existingComponentDtosByKey;
       this.dbSession = dbSession;
     }
@@ -143,6 +153,24 @@ public class PersistComponentsStep implements ComputationStep {
       persistAndPopulateCache(file, dto);
     }
 
+    @Override
+    public void visitView(Component view, Path<ComponentDtoHolder> path) {
+      ComponentDto dto = createForView(view);
+      path.current().setDto(persistAndPopulateCache(view, dto));
+    }
+
+    @Override
+    public void visitSubView(Component subView, Path<ComponentDtoHolder> path) {
+      ComponentDto dto = createForSubView(subView, path);
+      path.current().setDto(persistAndPopulateCache(subView, dto));
+    }
+
+    @Override
+    public void visitProjectView(Component projectView, Path<ComponentDtoHolder> path) {
+      ComponentDto dto = createForProjectView(projectView, path);
+      persistAndPopulateCache(projectView, dto);
+    }
+
     private ComponentDto persistAndPopulateCache(Component component, ComponentDto dto) {
       ComponentDto projectDto = persistComponent(dto);
       addToCache(component, projectDto);
@@ -172,7 +200,7 @@ public class PersistComponentsStep implements ComputationStep {
     res.setLongName(res.name());
     res.setDescription(project.getReportAttributes().getDescription());
     res.setProjectUuid(res.uuid());
-    res.setModuleUuidPath(ComponentDto.MODULE_UUID_PATH_SEP + res.uuid() + ComponentDto.MODULE_UUID_PATH_SEP);
+    res.setModuleUuidPath(MODULE_UUID_PATH_SEP + res.uuid() + MODULE_UUID_PATH_SEP);
 
     return res;
   }
@@ -187,13 +215,7 @@ public class PersistComponentsStep implements ComputationStep {
     res.setPath(module.getReportAttributes().getPath());
     res.setDescription(module.getReportAttributes().getDescription());
 
-    ComponentDto projectDto = from(path.getCurrentPath()).last().get().getElement().getDto();
-    res.setParentProjectId(projectDto.getId());
-
-    ComponentDto parentModule = path.parent().getDto();
-    res.setProjectUuid(parentModule.projectUuid());
-    res.setModuleUuid(parentModule.uuid());
-    res.setModuleUuidPath(parentModule.moduleUuidPath() + res.uuid() + ComponentDto.MODULE_UUID_PATH_SEP);
+    setRootAndParentModule(res, path);
 
     return res;
   }
@@ -207,7 +229,7 @@ public class PersistComponentsStep implements ComputationStep {
     res.setLongName(directory.getReportAttributes().getPath());
     res.setPath(directory.getReportAttributes().getPath());
 
-    setParentProperties(res, path);
+    setParentModuleProperties(res, path);
 
     return res;
   }
@@ -222,7 +244,47 @@ public class PersistComponentsStep implements ComputationStep {
     res.setPath(file.getReportAttributes().getPath());
     res.setLanguage(file.getFileAttributes().getLanguageKey());
 
-    setParentProperties(res, path);
+    setParentModuleProperties(res, path);
+
+    return res;
+  }
+
+  private ComponentDto createForView(Component view) {
+    ComponentDto res = createBase(view);
+
+    res.setScope(Scopes.PROJECT);
+    res.setQualifier(Qualifiers.VIEW);
+    res.setName(view.getName());
+    res.setLongName(res.name());
+    res.setProjectUuid(res.uuid());
+    res.setModuleUuidPath(MODULE_UUID_PATH_SEP + res.uuid() + MODULE_UUID_PATH_SEP);
+
+    return res;
+  }
+
+  private ComponentDto createForSubView(Component subView, PathAwareVisitor.Path<ComponentDtoHolder> path) {
+    ComponentDto res = createBase(subView);
+
+    res.setScope(Scopes.PROJECT);
+    res.setQualifier(Qualifiers.SUBVIEW);
+    res.setName(subView.getName());
+    res.setLongName(res.name());
+
+    setRootAndParentModule(res, path);
+
+    return res;
+  }
+
+  private ComponentDto createForProjectView(Component projectView, PathAwareVisitor.Path<ComponentDtoHolder> path) {
+    ComponentDto res = createBase(projectView);
+
+    res.setScope(Scopes.FILE);
+    res.setQualifier(Qualifiers.PROJECT);
+    res.setName(projectView.getName());
+    res.setLongName(res.name());
+    res.setCopyResourceId(projectView.getProjectViewAttributes().getProjectId());
+
+    setRootAndParentModule(res, path);
 
     return res;
   }
@@ -240,7 +302,23 @@ public class PersistComponentsStep implements ComputationStep {
     return componentDto;
   }
 
-  private static void setParentProperties(ComponentDto componentDto, PathAwareVisitor.Path<ComponentDtoHolder> path) {
+  /**
+   * Applies to a node of type either MODULE, SUBVIEW, PROJECT_VIEW
+   */
+  private static void setRootAndParentModule(ComponentDto res, PathAwareVisitor.Path<ComponentDtoHolder> path) {
+    ComponentDto projectDto = from(path.getCurrentPath()).last().get().getElement().getDto();
+    res.setParentProjectId(projectDto.getId());
+    res.setProjectUuid(projectDto.uuid());
+
+    ComponentDto parentModule = path.parent().getDto();
+    res.setModuleUuid(parentModule.uuid());
+    res.setModuleUuidPath(parentModule.moduleUuidPath() + res.uuid() + MODULE_UUID_PATH_SEP);
+  }
+
+  /**
+   * Applies to a node of type either DIRECTORY or FILE
+   */
+  private static void setParentModuleProperties(ComponentDto componentDto, PathAwareVisitor.Path<ComponentDtoHolder> path) {
     ComponentDto parentModule = from(path.getCurrentPath())
       .filter(ParentModulePathElement.INSTANCE)
       .first()
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistComponentsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistComponentsStepTest.java
deleted file mode 100644 (file)
index ae4b632..0000000
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-package org.sonar.server.computation.step;
-
-import com.google.common.base.Optional;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.sonar.api.utils.DateUtils;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbTester;
-import org.sonar.db.component.ComponentDto;
-import org.sonar.db.component.ComponentTesting;
-import org.sonar.server.computation.batch.TreeRootHolderRule;
-import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.component.DbIdsRepositoryImpl;
-import org.sonar.server.computation.component.FileAttributes;
-import org.sonar.test.DbTests;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.guava.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
-import static org.sonar.server.computation.component.Component.Type.FILE;
-import static org.sonar.server.computation.component.Component.Type.PROJECT;
-import static org.sonar.server.computation.component.ReportComponent.builder;
-
-@Category(DbTests.class)
-public class PersistComponentsStepTest extends BaseStepTest {
-
-  private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
-
-  private static final String PROJECT_KEY = "PROJECT_KEY";
-
-  @Rule
-  public DbTester dbTester = DbTester.create(System2.INSTANCE);
-  @Rule
-  public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
-
-  DbIdsRepositoryImpl dbIdsRepository;
-
-  System2 system2 = mock(System2.class);
-
-  DbClient dbClient = dbTester.getDbClient();
-
-  Date now;
-
-  PersistComponentsStep underTest;
-
-  @Before
-  public void setup() throws Exception {
-    dbTester.truncateTables();
-    dbIdsRepository = new DbIdsRepositoryImpl();
-
-    now = DATE_FORMAT.parse("2015-06-02");
-    when(system2.now()).thenReturn(now.getTime());
-
-    underTest = new PersistComponentsStep(dbClient, treeRootHolder, dbIdsRepository, system2);
-  }
-
-  @Override
-  protected ComputationStep step() {
-    return underTest;
-  }
-
-  @Test
-  public void persist_components() {
-    Component file = builder(FILE, 4).setUuid("DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java")
-      .setPath("src/main/java/dir/Foo.java")
-      .setFileAttributes(new FileAttributes(false, "java"))
-      .build();
-    Component directory = builder(DIRECTORY, 3).setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir")
-      .setPath("src/main/java/dir")
-      .addChildren(file)
-      .build();
-    Component module = builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
-      .setPath("module")
-      .setName("Module")
-      .setDescription("Module description")
-      .addChildren(directory)
-      .build();
-    Component project = builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
-      .setName("Project")
-      .setDescription("Project description")
-      .addChildren(module)
-      .build();
-    treeRootHolder.setRoot(project);
-
-    underTest.execute();
-    dbTester.getSession().commit();
-
-    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
-
-    ComponentDto projectDto = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get();
-    assertThat(projectDto.name()).isEqualTo("Project");
-    assertThat(projectDto.description()).isEqualTo("Project description");
-    assertThat(projectDto.path()).isNull();
-    assertThat(projectDto.uuid()).isEqualTo("ABCD");
-    assertThat(projectDto.moduleUuid()).isNull();
-    assertThat(projectDto.moduleUuidPath()).isEqualTo("." + projectDto.uuid() + ".");
-    assertThat(projectDto.projectUuid()).isEqualTo(projectDto.uuid());
-    assertThat(projectDto.qualifier()).isEqualTo("TRK");
-    assertThat(projectDto.scope()).isEqualTo("PRJ");
-    assertThat(projectDto.parentProjectId()).isNull();
-    assertThat(projectDto.getCreatedAt()).isEqualTo(now);
-
-    ComponentDto moduleDto = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
-    assertThat(moduleDto.name()).isEqualTo("Module");
-    assertThat(moduleDto.description()).isEqualTo("Module description");
-    assertThat(moduleDto.path()).isEqualTo("module");
-    assertThat(moduleDto.uuid()).isEqualTo("BCDE");
-    assertThat(moduleDto.moduleUuid()).isEqualTo(projectDto.uuid());
-    assertThat(moduleDto.moduleUuidPath()).isEqualTo(projectDto.moduleUuidPath() + moduleDto.uuid() + ".");
-    assertThat(moduleDto.projectUuid()).isEqualTo(projectDto.uuid());
-    assertThat(moduleDto.qualifier()).isEqualTo("BRC");
-    assertThat(moduleDto.scope()).isEqualTo("PRJ");
-    assertThat(moduleDto.parentProjectId()).isEqualTo(projectDto.getId());
-    assertThat(moduleDto.getCreatedAt()).isEqualTo(now);
-
-    ComponentDto directoryDto = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get();
-    assertThat(directoryDto.name()).isEqualTo("src/main/java/dir");
-    assertThat(directoryDto.description()).isNull();
-    assertThat(directoryDto.path()).isEqualTo("src/main/java/dir");
-    assertThat(directoryDto.uuid()).isEqualTo("CDEF");
-    assertThat(directoryDto.moduleUuid()).isEqualTo(moduleDto.uuid());
-    assertThat(directoryDto.moduleUuidPath()).isEqualTo(moduleDto.moduleUuidPath());
-    assertThat(directoryDto.projectUuid()).isEqualTo(projectDto.uuid());
-    assertThat(directoryDto.qualifier()).isEqualTo("DIR");
-    assertThat(directoryDto.scope()).isEqualTo("DIR");
-    assertThat(directoryDto.parentProjectId()).isEqualTo(moduleDto.getId());
-    assertThat(directoryDto.getCreatedAt()).isEqualTo(now);
-
-    ComponentDto fileDto = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get();
-    assertThat(fileDto.name()).isEqualTo("Foo.java");
-    assertThat(fileDto.description()).isNull();
-    assertThat(fileDto.path()).isEqualTo("src/main/java/dir/Foo.java");
-    assertThat(fileDto.language()).isEqualTo("java");
-    assertThat(fileDto.uuid()).isEqualTo("DEFG");
-    assertThat(fileDto.moduleUuid()).isEqualTo(moduleDto.uuid());
-    assertThat(fileDto.moduleUuidPath()).isEqualTo(moduleDto.moduleUuidPath());
-    assertThat(fileDto.projectUuid()).isEqualTo(projectDto.uuid());
-    assertThat(fileDto.qualifier()).isEqualTo("FIL");
-    assertThat(fileDto.scope()).isEqualTo("FIL");
-    assertThat(fileDto.parentProjectId()).isEqualTo(moduleDto.getId());
-    assertThat(fileDto.getCreatedAt()).isEqualTo(now);
-
-    assertThat(dbIdsRepository.getComponentId(project)).isEqualTo(projectDto.getId());
-    assertThat(dbIdsRepository.getComponentId(module)).isEqualTo(moduleDto.getId());
-    assertThat(dbIdsRepository.getComponentId(directory)).isEqualTo(directoryDto.getId());
-    assertThat(dbIdsRepository.getComponentId(file)).isEqualTo(fileDto.getId());
-  }
-
-  @Test
-  public void persist_file_directly_attached_on_root_directory() {
-    treeRootHolder.setRoot(
-      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).setName("Project")
-        .addChildren(
-          builder(DIRECTORY, 2).setUuid("CDEF").setKey(PROJECT_KEY + ":/").setPath("/")
-            .addChildren(
-              builder(FILE, 3).setUuid("DEFG").setKey(PROJECT_KEY + ":pom.xml").setPath("pom.xml")
-                .build())
-            .build())
-        .build());
-
-    underTest.execute();
-
-    ComponentDto directory = dbClient.componentDao().selectByKey(dbTester.getSession(), "PROJECT_KEY:/").get();
-    assertThat(directory.name()).isEqualTo("/");
-    assertThat(directory.path()).isEqualTo("/");
-
-    ComponentDto file = dbClient.componentDao().selectByKey(dbTester.getSession(), "PROJECT_KEY:pom.xml").get();
-    assertThat(file.name()).isEqualTo("pom.xml");
-    assertThat(file.path()).isEqualTo("pom.xml");
-  }
-
-  @Test
-  public void persist_unit_test() {
-    treeRootHolder.setRoot(
-      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
-        .setName("Project")
-        .addChildren(
-          builder(DIRECTORY, 2).setUuid("CDEF").setKey(PROJECT_KEY + ":src/test/java/dir")
-            .setPath("src/test/java/dir")
-            .addChildren(
-              builder(FILE, 3).setUuid("DEFG").setKey(PROJECT_KEY + ":src/test/java/dir/FooTest.java")
-                .setPath("src/test/java/dir/FooTest.java")
-                .setFileAttributes(new FileAttributes(true, null))
-                .build())
-            .build())
-        .build());
-
-    underTest.execute();
-
-    ComponentDto file = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY + ":src/test/java/dir/FooTest.java").get();
-    assertThat(file.name()).isEqualTo("FooTest.java");
-    assertThat(file.path()).isEqualTo("src/test/java/dir/FooTest.java");
-    assertThat(file.qualifier()).isEqualTo("UTS");
-    assertThat(file.scope()).isEqualTo("FIL");
-  }
-
-  @Test
-  public void persist_only_new_components() {
-    // Project amd module already exists
-    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
-    dbClient.componentDao().insert(dbTester.getSession(), project);
-    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module");
-    dbClient.componentDao().insert(dbTester.getSession(), module);
-    dbTester.getSession().commit();
-
-    treeRootHolder.setRoot(
-      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
-        .setName("Project")
-        .addChildren(
-          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
-            .setName("Module")
-            .addChildren(
-              builder(DIRECTORY, 3).setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir")
-                .setPath("src/main/java/dir")
-                .addChildren(
-                  builder(FILE, 4).setUuid("DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java")
-                    .setPath("src/main/java/dir/Foo.java")
-                    .build())
-                .build())
-            .build())
-        .build());
-
-    underTest.execute();
-
-    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
-
-    ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get();
-    assertThat(projectReloaded.getId()).isEqualTo(project.getId());
-    assertThat(projectReloaded.uuid()).isEqualTo(project.uuid());
-
-    ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
-    assertThat(moduleReloaded.getId()).isEqualTo(module.getId());
-    assertThat(moduleReloaded.uuid()).isEqualTo(module.uuid());
-    assertThat(moduleReloaded.moduleUuid()).isEqualTo(module.moduleUuid());
-    assertThat(moduleReloaded.moduleUuidPath()).isEqualTo(module.moduleUuidPath());
-    assertThat(moduleReloaded.projectUuid()).isEqualTo(module.projectUuid());
-    assertThat(moduleReloaded.parentProjectId()).isEqualTo(module.parentProjectId());
-
-    ComponentDto directory = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get();
-    assertThat(directory.moduleUuid()).isEqualTo(module.uuid());
-    assertThat(directory.moduleUuidPath()).isEqualTo(module.moduleUuidPath());
-    assertThat(directory.projectUuid()).isEqualTo(project.uuid());
-    assertThat(directory.parentProjectId()).isEqualTo(module.getId());
-
-    ComponentDto file = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get();
-    assertThat(file.moduleUuid()).isEqualTo(module.uuid());
-    assertThat(file.moduleUuidPath()).isEqualTo(module.moduleUuidPath());
-    assertThat(file.projectUuid()).isEqualTo(project.uuid());
-    assertThat(file.parentProjectId()).isEqualTo(module.getId());
-  }
-
-  @Test
-  public void compute_parent_project_id() {
-    treeRootHolder.setRoot(
-      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
-        .setName("Project")
-        .addChildren(
-          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
-            .setName("Module")
-            .addChildren(
-              builder(Component.Type.MODULE, 3).setUuid("CDEF").setKey("SUB_MODULE_1_KEY")
-                .setName("Sub Module 1")
-                .addChildren(
-                  builder(Component.Type.MODULE, 4).setUuid("DEFG").setKey("SUB_MODULE_2_KEY")
-                    .setName("Sub Module 2")
-                    .addChildren(
-                      builder(DIRECTORY, 5).setUuid("EFGH").setKey("SUB_MODULE_2_KEY:src/main/java/dir")
-                        .setPath("src/main/java/dir")
-                        .build())
-                    .build())
-                .build())
-            .build())
-        .build());
-
-    underTest.execute();
-
-    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5);
-
-    Optional<ComponentDto> project = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY);
-    assertThat(project).isPresent();
-    assertThat(project.get().parentProjectId()).isNull();
-
-    Optional<ComponentDto> module = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY");
-    assertThat(module).isPresent();
-    assertThat(module.get().parentProjectId()).isEqualTo(project.get().getId());
-
-    Optional<ComponentDto> subModule1 = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_1_KEY");
-    assertThat(subModule1).isPresent();
-    assertThat(subModule1.get().parentProjectId()).isEqualTo(project.get().getId());
-
-    Optional<ComponentDto> subModule2 = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_2_KEY");
-    assertThat(subModule2).isPresent();
-    assertThat(subModule2.get().parentProjectId()).isEqualTo(project.get().getId());
-
-    Optional<ComponentDto> directory = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_2_KEY:src/main/java/dir");
-    assertThat(directory).isPresent();
-    assertThat(directory.get().parentProjectId()).isEqualTo(subModule2.get().getId());
-  }
-
-  @Test
-  public void persist_multi_modules() {
-    treeRootHolder.setRoot(
-      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
-        .setName("Project")
-        .addChildren(
-          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_A")
-            .setName("Module A")
-            .addChildren(
-              builder(Component.Type.MODULE, 3).setUuid("DEFG").setKey("SUB_MODULE_A")
-                .setName("Sub Module A")
-                .build())
-            .build(),
-          builder(Component.Type.MODULE, 4).setUuid("CDEF").setKey("MODULE_B")
-            .setName("Module B")
-            .build())
-        .build());
-
-    underTest.execute();
-
-    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
-
-    ComponentDto project = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get();
-    assertThat(project.moduleUuid()).isNull();
-    assertThat(project.moduleUuidPath()).isEqualTo("." + project.uuid() + ".");
-    assertThat(project.parentProjectId()).isNull();
-
-    ComponentDto moduleA = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_A").get();
-    assertThat(moduleA.moduleUuid()).isEqualTo(project.uuid());
-    assertThat(moduleA.moduleUuidPath()).isEqualTo(project.moduleUuidPath() + moduleA.uuid() + ".");
-    assertThat(moduleA.parentProjectId()).isEqualTo(project.getId());
-
-    ComponentDto subModuleA = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_A").get();
-    assertThat(subModuleA.moduleUuid()).isEqualTo(moduleA.uuid());
-    assertThat(subModuleA.moduleUuidPath()).isEqualTo(moduleA.moduleUuidPath() + subModuleA.uuid() + ".");
-    assertThat(subModuleA.parentProjectId()).isEqualTo(project.getId());
-
-    ComponentDto moduleB = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B").get();
-    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() {
-    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
-    dbClient.componentDao().insert(dbTester.getSession(), project);
-    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module");
-    dbClient.componentDao().insert(dbTester.getSession(), module);
-    ComponentDto directory = ComponentTesting.newDirectory(module, "src/main/java/dir").setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir");
-    ComponentDto file = ComponentTesting.newFileDto(module, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java").setKey("MODULE_KEY:src/main/java/dir/Foo.java");
-    dbClient.componentDao().insert(dbTester.getSession(), directory, file);
-    dbTester.getSession().commit();
-
-    treeRootHolder.setRoot(
-      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
-        .setName("Project")
-        .addChildren(
-          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
-            .setName("Module")
-            .addChildren(
-              builder(DIRECTORY, 3).setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir")
-                .setPath("src/main/java/dir")
-                .addChildren(
-                  builder(FILE, 4).setUuid("DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java")
-                    .setPath("src/main/java/dir/Foo.java")
-                    .build())
-                .build())
-            .build())
-        .build());
-
-    underTest.execute();
-
-    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
-    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get().getId()).isEqualTo(project.getId());
-    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get().getId()).isEqualTo(module.getId());
-    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get().getId()).isEqualTo(directory.getId());
-    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get().getId()).isEqualTo(file.getId());
-
-    ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get();
-    assertThat(projectReloaded.getId()).isEqualTo(project.getId());
-    assertThat(projectReloaded.uuid()).isEqualTo(project.uuid());
-    assertThat(projectReloaded.moduleUuid()).isEqualTo(project.moduleUuid());
-    assertThat(projectReloaded.moduleUuidPath()).isEqualTo(project.moduleUuidPath());
-    assertThat(projectReloaded.projectUuid()).isEqualTo(project.projectUuid());
-    assertThat(projectReloaded.parentProjectId()).isEqualTo(project.parentProjectId());
-
-    ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
-    assertThat(moduleReloaded.getId()).isEqualTo(module.getId());
-    assertThat(moduleReloaded.uuid()).isEqualTo(module.uuid());
-    assertThat(moduleReloaded.moduleUuid()).isEqualTo(module.moduleUuid());
-    assertThat(moduleReloaded.moduleUuidPath()).isEqualTo(module.moduleUuidPath());
-    assertThat(moduleReloaded.projectUuid()).isEqualTo(module.projectUuid());
-    assertThat(moduleReloaded.parentProjectId()).isEqualTo(module.parentProjectId());
-
-    ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get();
-    assertThat(directoryReloaded.uuid()).isEqualTo(directory.uuid());
-    assertThat(directoryReloaded.moduleUuid()).isEqualTo(directory.moduleUuid());
-    assertThat(directoryReloaded.moduleUuidPath()).isEqualTo(directory.moduleUuidPath());
-    assertThat(directoryReloaded.projectUuid()).isEqualTo(directory.projectUuid());
-    assertThat(directoryReloaded.parentProjectId()).isEqualTo(directory.parentProjectId());
-    assertThat(directoryReloaded.name()).isEqualTo(directory.name());
-    assertThat(directoryReloaded.path()).isEqualTo(directory.path());
-
-    ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get();
-    assertThat(fileReloaded.uuid()).isEqualTo(file.uuid());
-    assertThat(fileReloaded.moduleUuid()).isEqualTo(file.moduleUuid());
-    assertThat(fileReloaded.moduleUuidPath()).isEqualTo(file.moduleUuidPath());
-    assertThat(fileReloaded.projectUuid()).isEqualTo(file.projectUuid());
-    assertThat(fileReloaded.parentProjectId()).isEqualTo(file.parentProjectId());
-    assertThat(fileReloaded.name()).isEqualTo(file.name());
-    assertThat(fileReloaded.path()).isEqualTo(file.path());
-  }
-
-  @Test
-  public void update_module_name() {
-    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
-    dbClient.componentDao().insert(dbTester.getSession(), project);
-    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module").setPath("path");
-    dbClient.componentDao().insert(dbTester.getSession(), module);
-    dbTester.getSession().commit();
-
-    treeRootHolder.setRoot(
-      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
-        .setName("New project name")
-        .addChildren(
-          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
-            .setName("New module name")
-            .setPath("New path")
-            .build())
-        .build());
-
-    underTest.execute();
-
-    ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get();
-    assertThat(projectReloaded.name()).isEqualTo("New project name");
-
-    ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
-    assertThat(moduleReloaded.name()).isEqualTo("New module name");
-  }
-
-  @Test
-  public void update_module_description() {
-    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project").setDescription("Project description");
-    dbClient.componentDao().insert(dbTester.getSession(), project);
-    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module");
-    dbClient.componentDao().insert(dbTester.getSession(), module);
-    dbTester.getSession().commit();
-
-    treeRootHolder.setRoot(
-      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
-        .setName("Project")
-        .setDescription("New project description")
-        .addChildren(
-          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
-            .setName("Module")
-            .setDescription("New module description")
-            .build())
-        .build());
-
-    underTest.execute();
-
-    ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get();
-    assertThat(projectReloaded.description()).isEqualTo("New project description");
-
-    ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
-    assertThat(moduleReloaded.description()).isEqualTo("New module description");
-  }
-
-  @Test
-  public void update_module_path() {
-    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
-    dbClient.componentDao().insert(dbTester.getSession(), project);
-    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module").setPath("path");
-    dbClient.componentDao().insert(dbTester.getSession(), module);
-    dbTester.getSession().commit();
-
-    treeRootHolder.setRoot(
-      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
-        .setName("Project")
-        .addChildren(
-          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
-            .setName("Module")
-            .setPath("New path")
-            .build())
-        .build());
-
-    underTest.execute();
-
-    ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
-    assertThat(moduleReloaded.path()).isEqualTo("New path");
-  }
-
-  @Test
-  public void update_module_uuid_when_moving_a_module() {
-    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
-    dbClient.componentDao().insert(dbTester.getSession(), project);
-    ComponentDto moduleA = ComponentTesting.newModuleDto("EDCB", project).setKey("MODULE_A").setName("Module A");
-    ComponentDto moduleB = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_B").setName("Module B");
-    dbClient.componentDao().insert(dbTester.getSession(), moduleA, moduleB);
-    ComponentDto directory = ComponentTesting.newDirectory(moduleB, "src/main/java/dir").setUuid("CDEF").setKey("MODULE_B:src/main/java/dir");
-    ComponentDto file = ComponentTesting.newFileDto(moduleB, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java").setKey("MODULE_B:src/main/java/dir/Foo.java");
-    dbClient.componentDao().insert(dbTester.getSession(), directory, file);
-    dbTester.getSession().commit();
-
-    treeRootHolder.setRoot(
-      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
-        .setName("Project")
-        .addChildren(
-          builder(Component.Type.MODULE, 2).setUuid("EDCB").setKey("MODULE_A")
-            .setName("Module A")
-            .addChildren(
-              builder(Component.Type.MODULE, 3).setUuid("BCDE").setKey("MODULE_B")
-                .setName("Module B")
-                .addChildren(
-                  builder(DIRECTORY, 4).setUuid("CDEF").setKey("MODULE_B:src/main/java/dir")
-                    .setPath("src/main/java/dir")
-                    .addChildren(
-                      builder(FILE, 5).setUuid("DEFG").setKey("MODULE_B:src/main/java/dir/Foo.java")
-                        .setPath("src/main/java/dir/Foo.java")
-                        .build())
-                    .build())
-                .build())
-            .build())
-        .build());
-
-    underTest.execute();
-
-    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5);
-
-    ComponentDto moduleAreloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_A").get();
-
-    ComponentDto moduleBReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B").get();
-    assertThat(moduleBReloaded).isNotNull();
-    assertThat(moduleBReloaded.uuid()).isEqualTo(moduleB.uuid());
-    assertThat(moduleBReloaded.moduleUuid()).isEqualTo(moduleAreloaded.uuid());
-    assertThat(moduleBReloaded.moduleUuidPath()).isEqualTo(moduleAreloaded.moduleUuidPath() + moduleBReloaded.uuid() + ".");
-    assertThat(moduleBReloaded.projectUuid()).isEqualTo(project.uuid());
-    assertThat(moduleBReloaded.parentProjectId()).isEqualTo(project.getId());
-
-    ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B:src/main/java/dir").get();
-    assertThat(directoryReloaded).isNotNull();
-    assertThat(directoryReloaded.uuid()).isEqualTo(directory.uuid());
-    assertThat(directoryReloaded.moduleUuid()).isEqualTo(moduleBReloaded.uuid());
-    assertThat(directoryReloaded.moduleUuidPath()).isEqualTo(moduleBReloaded.moduleUuidPath());
-    assertThat(directoryReloaded.projectUuid()).isEqualTo(project.uuid());
-    assertThat(directoryReloaded.parentProjectId()).isEqualTo(moduleBReloaded.getId());
-
-    ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B:src/main/java/dir/Foo.java").get();
-    assertThat(fileReloaded).isNotNull();
-    assertThat(fileReloaded.uuid()).isEqualTo(file.uuid());
-    assertThat(fileReloaded.moduleUuid()).isEqualTo(moduleBReloaded.uuid());
-    assertThat(fileReloaded.moduleUuidPath()).isEqualTo(moduleBReloaded.moduleUuidPath());
-    assertThat(fileReloaded.projectUuid()).isEqualTo(project.uuid());
-    assertThat(fileReloaded.parentProjectId()).isEqualTo(moduleBReloaded.getId());
-  }
-
-  @Test
-  public void do_not_update_created_at_on_existing_component() {
-    Date oldDate = DateUtils.parseDate("2015-01-01");
-    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project").setCreatedAt(oldDate);
-    dbClient.componentDao().insert(dbTester.getSession(), project);
-    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module").setPath("path").setCreatedAt(oldDate);
-    dbClient.componentDao().insert(dbTester.getSession(), module);
-    dbTester.getSession().commit();
-
-    treeRootHolder.setRoot(
-      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
-        .setName("New project name")
-        .build());
-
-    underTest.execute();
-
-    Optional<ComponentDto> projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY);
-    assertThat(projectReloaded.get().name()).isEqualTo("New project name");
-    assertThat(projectReloaded.get().getCreatedAt()).isNotEqualTo(now);
-  }
-
-  @Test
-  public void persist_components_that_were_previously_removed() {
-    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
-    dbClient.componentDao().insert(dbTester.getSession(), project);
-    ComponentDto removedModule = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module").setEnabled(false);
-    dbClient.componentDao().insert(dbTester.getSession(), removedModule);
-    ComponentDto removedDirectory = ComponentTesting.newDirectory(removedModule, "src/main/java/dir").setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir").setEnabled(false);
-    ComponentDto removedFile = ComponentTesting.newFileDto(removedModule, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java")
-      .setKey("MODULE_KEY:src/main/java/dir/Foo.java").setEnabled(false);
-    dbClient.componentDao().insert(dbTester.getSession(), removedDirectory, removedFile);
-    dbTester.getSession().commit();
-
-    treeRootHolder.setRoot(
-      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
-        .setName("Project")
-        .addChildren(
-          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
-            .setName("Module")
-            .addChildren(
-              builder(DIRECTORY, 3).setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir")
-                .setPath("src/main/java/dir")
-                .addChildren(
-                  builder(FILE, 4).setUuid("DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java")
-                    .setPath("src/main/java/dir/Foo.java")
-                    .build())
-                .build())
-            .build())
-        .build());
-
-    underTest.execute();
-
-    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
-    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get().getId()).isEqualTo(project.getId());
-    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get().getId()).isEqualTo(removedModule.getId());
-    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get().getId()).isEqualTo(removedDirectory.getId());
-    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get().getId()).isEqualTo(removedFile.getId());
-
-    ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get();
-    assertThat(projectReloaded.getId()).isEqualTo(project.getId());
-    assertThat(projectReloaded.uuid()).isEqualTo(project.uuid());
-    assertThat(projectReloaded.moduleUuid()).isEqualTo(project.moduleUuid());
-    assertThat(projectReloaded.moduleUuidPath()).isEqualTo(project.moduleUuidPath());
-    assertThat(projectReloaded.projectUuid()).isEqualTo(project.projectUuid());
-    assertThat(projectReloaded.parentProjectId()).isEqualTo(project.parentProjectId());
-    assertThat(projectReloaded.isEnabled()).isTrue();
-
-    ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
-    assertThat(moduleReloaded.getId()).isEqualTo(removedModule.getId());
-    assertThat(moduleReloaded.uuid()).isEqualTo(removedModule.uuid());
-    assertThat(moduleReloaded.moduleUuid()).isEqualTo(removedModule.moduleUuid());
-    assertThat(moduleReloaded.moduleUuidPath()).isEqualTo(removedModule.moduleUuidPath());
-    assertThat(moduleReloaded.projectUuid()).isEqualTo(removedModule.projectUuid());
-    assertThat(moduleReloaded.parentProjectId()).isEqualTo(removedModule.parentProjectId());
-    assertThat(moduleReloaded.isEnabled()).isTrue();
-
-    ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get();
-    assertThat(directoryReloaded.getId()).isEqualTo(removedDirectory.getId());
-    assertThat(directoryReloaded.uuid()).isEqualTo(removedDirectory.uuid());
-    assertThat(directoryReloaded.moduleUuid()).isEqualTo(removedDirectory.moduleUuid());
-    assertThat(directoryReloaded.moduleUuidPath()).isEqualTo(removedDirectory.moduleUuidPath());
-    assertThat(directoryReloaded.projectUuid()).isEqualTo(removedDirectory.projectUuid());
-    assertThat(directoryReloaded.parentProjectId()).isEqualTo(removedDirectory.parentProjectId());
-    assertThat(directoryReloaded.name()).isEqualTo(removedDirectory.name());
-    assertThat(directoryReloaded.path()).isEqualTo(removedDirectory.path());
-    assertThat(directoryReloaded.isEnabled()).isTrue();
-
-    ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get();
-    assertThat(fileReloaded.getId()).isEqualTo(fileReloaded.getId());
-    assertThat(fileReloaded.uuid()).isEqualTo(removedFile.uuid());
-    assertThat(fileReloaded.moduleUuid()).isEqualTo(removedFile.moduleUuid());
-    assertThat(fileReloaded.moduleUuidPath()).isEqualTo(removedFile.moduleUuidPath());
-    assertThat(fileReloaded.projectUuid()).isEqualTo(removedFile.projectUuid());
-    assertThat(fileReloaded.parentProjectId()).isEqualTo(removedFile.parentProjectId());
-    assertThat(fileReloaded.name()).isEqualTo(removedFile.name());
-    assertThat(fileReloaded.path()).isEqualTo(removedFile.path());
-    assertThat(fileReloaded.isEnabled()).isTrue();
-  }
-
-  @Test
-  public void update_uuid_when_reactivating_removed_component() {
-    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
-    dbClient.componentDao().insert(dbTester.getSession(), project);
-    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module");
-    ComponentDto removedModule = ComponentTesting.newModuleDto("EDCD", project).setKey("REMOVED_MODULE_KEY").setName("Removed Module").setEnabled(false);
-    dbClient.componentDao().insert(dbTester.getSession(), module, removedModule);
-    ComponentDto directory = ComponentTesting.newDirectory(module, "src/main/java/dir").setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir");
-    // The file was attached to another module
-    ComponentDto removedFile = ComponentTesting.newFileDto(removedModule, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java")
-      .setKey("MODULE_KEY:src/main/java/dir/Foo.java").setEnabled(false);
-    dbClient.componentDao().insert(dbTester.getSession(), directory, removedFile);
-    dbTester.getSession().commit();
-
-    treeRootHolder.setRoot(
-      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
-        .setName("Project")
-        .addChildren(
-          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
-            .setName("Module")
-            .addChildren(
-              builder(DIRECTORY, 3).setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir")
-                .setPath("src/main/java/dir")
-                .addChildren(
-                  builder(FILE, 4).setUuid("DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java")
-                    .setPath("src/main/java/dir/Foo.java")
-                    .build())
-                .build())
-            .build())
-        .build());
-
-    underTest.execute();
-
-    // Projects contains 4 components from the report + one removed module
-    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5);
-
-    ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
-
-    ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get();
-    assertThat(fileReloaded.getId()).isEqualTo(removedFile.getId());
-    assertThat(fileReloaded.uuid()).isEqualTo(removedFile.uuid());
-    assertThat(fileReloaded.moduleUuid()).isEqualTo(moduleReloaded.uuid());
-    assertThat(fileReloaded.moduleUuidPath()).isEqualTo(moduleReloaded.moduleUuidPath());
-    assertThat(fileReloaded.projectUuid()).isEqualTo(moduleReloaded.projectUuid());
-    assertThat(fileReloaded.parentProjectId()).isEqualTo(moduleReloaded.getId());
-    assertThat(fileReloaded.name()).isEqualTo(removedFile.name());
-    assertThat(fileReloaded.path()).isEqualTo(removedFile.path());
-    assertThat(fileReloaded.isEnabled()).isTrue();
-  }
-
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportPersistComponentsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ReportPersistComponentsStepTest.java
new file mode 100644 (file)
index 0000000..8bd79c4
--- /dev/null
@@ -0,0 +1,731 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.step;
+
+import com.google.common.base.Optional;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.sonar.api.utils.DateUtils;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ComponentTesting;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.FileAttributes;
+import org.sonar.server.computation.component.MutableDbIdsRepositoryRule;
+import org.sonar.test.DbTests;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.guava.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.server.computation.component.Component.Type.DIRECTORY;
+import static org.sonar.server.computation.component.Component.Type.FILE;
+import static org.sonar.server.computation.component.Component.Type.PROJECT;
+import static org.sonar.server.computation.component.ReportComponent.builder;
+
+@Category(DbTests.class)
+public class ReportPersistComponentsStepTest extends BaseStepTest {
+
+  private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+
+  private static final String PROJECT_KEY = "PROJECT_KEY";
+
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+  @Rule
+  public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+  @Rule
+  public MutableDbIdsRepositoryRule dbIdsRepository = MutableDbIdsRepositoryRule.create(treeRootHolder);
+
+  System2 system2 = mock(System2.class);
+
+  DbClient dbClient = dbTester.getDbClient();
+
+  Date now;
+
+  PersistComponentsStep underTest;
+
+  @Before
+  public void setup() throws Exception {
+    dbTester.truncateTables();
+
+    now = DATE_FORMAT.parse("2015-06-02");
+    when(system2.now()).thenReturn(now.getTime());
+
+    underTest = new PersistComponentsStep(dbClient, treeRootHolder, dbIdsRepository, system2);
+  }
+
+  @Override
+  protected ComputationStep step() {
+    return underTest;
+  }
+
+  @Test
+  public void persist_components() {
+    Component file = builder(FILE, 4).setUuid("DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java")
+      .setPath("src/main/java/dir/Foo.java")
+      .setFileAttributes(new FileAttributes(false, "java"))
+      .build();
+    Component directory = builder(DIRECTORY, 3).setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir")
+      .setPath("src/main/java/dir")
+      .addChildren(file)
+      .build();
+    Component module = builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
+      .setPath("module")
+      .setName("Module")
+      .setDescription("Module description")
+      .addChildren(directory)
+      .build();
+    Component project = builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
+      .setName("Project")
+      .setDescription("Project description")
+      .addChildren(module)
+      .build();
+    treeRootHolder.setRoot(project);
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
+
+    ComponentDto projectDto = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get();
+    assertThat(projectDto.name()).isEqualTo("Project");
+    assertThat(projectDto.description()).isEqualTo("Project description");
+    assertThat(projectDto.path()).isNull();
+    assertThat(projectDto.uuid()).isEqualTo("ABCD");
+    assertThat(projectDto.moduleUuid()).isNull();
+    assertThat(projectDto.moduleUuidPath()).isEqualTo("." + projectDto.uuid() + ".");
+    assertThat(projectDto.projectUuid()).isEqualTo(projectDto.uuid());
+    assertThat(projectDto.qualifier()).isEqualTo("TRK");
+    assertThat(projectDto.scope()).isEqualTo("PRJ");
+    assertThat(projectDto.parentProjectId()).isNull();
+    assertThat(projectDto.getCreatedAt()).isEqualTo(now);
+
+    ComponentDto moduleDto = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
+    assertThat(moduleDto.name()).isEqualTo("Module");
+    assertThat(moduleDto.description()).isEqualTo("Module description");
+    assertThat(moduleDto.path()).isEqualTo("module");
+    assertThat(moduleDto.uuid()).isEqualTo("BCDE");
+    assertThat(moduleDto.moduleUuid()).isEqualTo(projectDto.uuid());
+    assertThat(moduleDto.moduleUuidPath()).isEqualTo(projectDto.moduleUuidPath() + moduleDto.uuid() + ".");
+    assertThat(moduleDto.projectUuid()).isEqualTo(projectDto.uuid());
+    assertThat(moduleDto.qualifier()).isEqualTo("BRC");
+    assertThat(moduleDto.scope()).isEqualTo("PRJ");
+    assertThat(moduleDto.parentProjectId()).isEqualTo(projectDto.getId());
+    assertThat(moduleDto.getCreatedAt()).isEqualTo(now);
+
+    ComponentDto directoryDto = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get();
+    assertThat(directoryDto.name()).isEqualTo("src/main/java/dir");
+    assertThat(directoryDto.description()).isNull();
+    assertThat(directoryDto.path()).isEqualTo("src/main/java/dir");
+    assertThat(directoryDto.uuid()).isEqualTo("CDEF");
+    assertThat(directoryDto.moduleUuid()).isEqualTo(moduleDto.uuid());
+    assertThat(directoryDto.moduleUuidPath()).isEqualTo(moduleDto.moduleUuidPath());
+    assertThat(directoryDto.projectUuid()).isEqualTo(projectDto.uuid());
+    assertThat(directoryDto.qualifier()).isEqualTo("DIR");
+    assertThat(directoryDto.scope()).isEqualTo("DIR");
+    assertThat(directoryDto.parentProjectId()).isEqualTo(moduleDto.getId());
+    assertThat(directoryDto.getCreatedAt()).isEqualTo(now);
+
+    ComponentDto fileDto = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get();
+    assertThat(fileDto.name()).isEqualTo("Foo.java");
+    assertThat(fileDto.description()).isNull();
+    assertThat(fileDto.path()).isEqualTo("src/main/java/dir/Foo.java");
+    assertThat(fileDto.language()).isEqualTo("java");
+    assertThat(fileDto.uuid()).isEqualTo("DEFG");
+    assertThat(fileDto.moduleUuid()).isEqualTo(moduleDto.uuid());
+    assertThat(fileDto.moduleUuidPath()).isEqualTo(moduleDto.moduleUuidPath());
+    assertThat(fileDto.projectUuid()).isEqualTo(projectDto.uuid());
+    assertThat(fileDto.qualifier()).isEqualTo("FIL");
+    assertThat(fileDto.scope()).isEqualTo("FIL");
+    assertThat(fileDto.parentProjectId()).isEqualTo(moduleDto.getId());
+    assertThat(fileDto.getCreatedAt()).isEqualTo(now);
+
+    assertThat(dbIdsRepository.getComponentId(project)).isEqualTo(projectDto.getId());
+    assertThat(dbIdsRepository.getComponentId(module)).isEqualTo(moduleDto.getId());
+    assertThat(dbIdsRepository.getComponentId(directory)).isEqualTo(directoryDto.getId());
+    assertThat(dbIdsRepository.getComponentId(file)).isEqualTo(fileDto.getId());
+  }
+
+  @Test
+  public void persist_file_directly_attached_on_root_directory() {
+    treeRootHolder.setRoot(
+      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY).setName("Project")
+        .addChildren(
+          builder(DIRECTORY, 2).setUuid("CDEF").setKey(PROJECT_KEY + ":/").setPath("/")
+            .addChildren(
+              builder(FILE, 3).setUuid("DEFG").setKey(PROJECT_KEY + ":pom.xml").setPath("pom.xml")
+                .build())
+            .build())
+        .build());
+
+    underTest.execute();
+
+    ComponentDto directory = dbClient.componentDao().selectByKey(dbTester.getSession(), "PROJECT_KEY:/").get();
+    assertThat(directory.name()).isEqualTo("/");
+    assertThat(directory.path()).isEqualTo("/");
+
+    ComponentDto file = dbClient.componentDao().selectByKey(dbTester.getSession(), "PROJECT_KEY:pom.xml").get();
+    assertThat(file.name()).isEqualTo("pom.xml");
+    assertThat(file.path()).isEqualTo("pom.xml");
+  }
+
+  @Test
+  public void persist_unit_test() {
+    treeRootHolder.setRoot(
+      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
+        .setName("Project")
+        .addChildren(
+          builder(DIRECTORY, 2).setUuid("CDEF").setKey(PROJECT_KEY + ":src/test/java/dir")
+            .setPath("src/test/java/dir")
+            .addChildren(
+              builder(FILE, 3).setUuid("DEFG").setKey(PROJECT_KEY + ":src/test/java/dir/FooTest.java")
+                .setPath("src/test/java/dir/FooTest.java")
+                .setFileAttributes(new FileAttributes(true, null))
+                .build())
+            .build())
+        .build());
+
+    underTest.execute();
+
+    ComponentDto file = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY + ":src/test/java/dir/FooTest.java").get();
+    assertThat(file.name()).isEqualTo("FooTest.java");
+    assertThat(file.path()).isEqualTo("src/test/java/dir/FooTest.java");
+    assertThat(file.qualifier()).isEqualTo("UTS");
+    assertThat(file.scope()).isEqualTo("FIL");
+  }
+
+  @Test
+  public void persist_only_new_components() {
+    // Project amd module already exists
+    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
+    dbClient.componentDao().insert(dbTester.getSession(), project);
+    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module");
+    dbClient.componentDao().insert(dbTester.getSession(), module);
+    dbTester.getSession().commit();
+
+    treeRootHolder.setRoot(
+      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
+        .setName("Project")
+        .addChildren(
+          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
+            .setName("Module")
+            .addChildren(
+              builder(DIRECTORY, 3).setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir")
+                .setPath("src/main/java/dir")
+                .addChildren(
+                  builder(FILE, 4).setUuid("DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java")
+                    .setPath("src/main/java/dir/Foo.java")
+                    .build())
+                .build())
+            .build())
+        .build());
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
+
+    ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get();
+    assertThat(projectReloaded.getId()).isEqualTo(project.getId());
+    assertThat(projectReloaded.uuid()).isEqualTo(project.uuid());
+
+    ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
+    assertThat(moduleReloaded.getId()).isEqualTo(module.getId());
+    assertThat(moduleReloaded.uuid()).isEqualTo(module.uuid());
+    assertThat(moduleReloaded.moduleUuid()).isEqualTo(module.moduleUuid());
+    assertThat(moduleReloaded.moduleUuidPath()).isEqualTo(module.moduleUuidPath());
+    assertThat(moduleReloaded.projectUuid()).isEqualTo(module.projectUuid());
+    assertThat(moduleReloaded.parentProjectId()).isEqualTo(module.parentProjectId());
+
+    ComponentDto directory = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get();
+    assertThat(directory.moduleUuid()).isEqualTo(module.uuid());
+    assertThat(directory.moduleUuidPath()).isEqualTo(module.moduleUuidPath());
+    assertThat(directory.projectUuid()).isEqualTo(project.uuid());
+    assertThat(directory.parentProjectId()).isEqualTo(module.getId());
+
+    ComponentDto file = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get();
+    assertThat(file.moduleUuid()).isEqualTo(module.uuid());
+    assertThat(file.moduleUuidPath()).isEqualTo(module.moduleUuidPath());
+    assertThat(file.projectUuid()).isEqualTo(project.uuid());
+    assertThat(file.parentProjectId()).isEqualTo(module.getId());
+  }
+
+  @Test
+  public void compute_parent_project_id() {
+    treeRootHolder.setRoot(
+      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
+        .setName("Project")
+        .addChildren(
+          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
+            .setName("Module")
+            .addChildren(
+              builder(Component.Type.MODULE, 3).setUuid("CDEF").setKey("SUB_MODULE_1_KEY")
+                .setName("Sub Module 1")
+                .addChildren(
+                  builder(Component.Type.MODULE, 4).setUuid("DEFG").setKey("SUB_MODULE_2_KEY")
+                    .setName("Sub Module 2")
+                    .addChildren(
+                      builder(DIRECTORY, 5).setUuid("EFGH").setKey("SUB_MODULE_2_KEY:src/main/java/dir")
+                        .setPath("src/main/java/dir")
+                        .build())
+                    .build())
+                .build())
+            .build())
+        .build());
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5);
+
+    Optional<ComponentDto> project = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY);
+    assertThat(project).isPresent();
+    assertThat(project.get().parentProjectId()).isNull();
+
+    Optional<ComponentDto> module = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY");
+    assertThat(module).isPresent();
+    assertThat(module.get().parentProjectId()).isEqualTo(project.get().getId());
+
+    Optional<ComponentDto> subModule1 = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_1_KEY");
+    assertThat(subModule1).isPresent();
+    assertThat(subModule1.get().parentProjectId()).isEqualTo(project.get().getId());
+
+    Optional<ComponentDto> subModule2 = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_2_KEY");
+    assertThat(subModule2).isPresent();
+    assertThat(subModule2.get().parentProjectId()).isEqualTo(project.get().getId());
+
+    Optional<ComponentDto> directory = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_2_KEY:src/main/java/dir");
+    assertThat(directory).isPresent();
+    assertThat(directory.get().parentProjectId()).isEqualTo(subModule2.get().getId());
+  }
+
+  @Test
+  public void persist_multi_modules() {
+    treeRootHolder.setRoot(
+      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
+        .setName("Project")
+        .addChildren(
+          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_A")
+            .setName("Module A")
+            .addChildren(
+              builder(Component.Type.MODULE, 3).setUuid("DEFG").setKey("SUB_MODULE_A")
+                .setName("Sub Module A")
+                .build())
+            .build(),
+          builder(Component.Type.MODULE, 4).setUuid("CDEF").setKey("MODULE_B")
+            .setName("Module B")
+            .build())
+        .build());
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
+
+    ComponentDto project = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get();
+    assertThat(project.moduleUuid()).isNull();
+    assertThat(project.moduleUuidPath()).isEqualTo("." + project.uuid() + ".");
+    assertThat(project.parentProjectId()).isNull();
+
+    ComponentDto moduleA = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_A").get();
+    assertThat(moduleA.moduleUuid()).isEqualTo(project.uuid());
+    assertThat(moduleA.moduleUuidPath()).isEqualTo(project.moduleUuidPath() + moduleA.uuid() + ".");
+    assertThat(moduleA.parentProjectId()).isEqualTo(project.getId());
+
+    ComponentDto subModuleA = dbClient.componentDao().selectByKey(dbTester.getSession(), "SUB_MODULE_A").get();
+    assertThat(subModuleA.moduleUuid()).isEqualTo(moduleA.uuid());
+    assertThat(subModuleA.moduleUuidPath()).isEqualTo(moduleA.moduleUuidPath() + subModuleA.uuid() + ".");
+    assertThat(subModuleA.parentProjectId()).isEqualTo(project.getId());
+
+    ComponentDto moduleB = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B").get();
+    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() {
+    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
+    dbClient.componentDao().insert(dbTester.getSession(), project);
+    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module");
+    dbClient.componentDao().insert(dbTester.getSession(), module);
+    ComponentDto directory = ComponentTesting.newDirectory(module, "src/main/java/dir").setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir");
+    ComponentDto file = ComponentTesting.newFileDto(module, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java").setKey("MODULE_KEY:src/main/java/dir/Foo.java");
+    dbClient.componentDao().insert(dbTester.getSession(), directory, file);
+    dbTester.getSession().commit();
+
+    treeRootHolder.setRoot(
+      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
+        .setName("Project")
+        .addChildren(
+          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
+            .setName("Module")
+            .addChildren(
+              builder(DIRECTORY, 3).setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir")
+                .setPath("src/main/java/dir")
+                .addChildren(
+                  builder(FILE, 4).setUuid("DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java")
+                    .setPath("src/main/java/dir/Foo.java")
+                    .build())
+                .build())
+            .build())
+        .build());
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
+    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get().getId()).isEqualTo(project.getId());
+    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get().getId()).isEqualTo(module.getId());
+    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get().getId()).isEqualTo(directory.getId());
+    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get().getId()).isEqualTo(file.getId());
+
+    ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get();
+    assertThat(projectReloaded.getId()).isEqualTo(project.getId());
+    assertThat(projectReloaded.uuid()).isEqualTo(project.uuid());
+    assertThat(projectReloaded.moduleUuid()).isEqualTo(project.moduleUuid());
+    assertThat(projectReloaded.moduleUuidPath()).isEqualTo(project.moduleUuidPath());
+    assertThat(projectReloaded.projectUuid()).isEqualTo(project.projectUuid());
+    assertThat(projectReloaded.parentProjectId()).isEqualTo(project.parentProjectId());
+
+    ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
+    assertThat(moduleReloaded.getId()).isEqualTo(module.getId());
+    assertThat(moduleReloaded.uuid()).isEqualTo(module.uuid());
+    assertThat(moduleReloaded.moduleUuid()).isEqualTo(module.moduleUuid());
+    assertThat(moduleReloaded.moduleUuidPath()).isEqualTo(module.moduleUuidPath());
+    assertThat(moduleReloaded.projectUuid()).isEqualTo(module.projectUuid());
+    assertThat(moduleReloaded.parentProjectId()).isEqualTo(module.parentProjectId());
+
+    ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get();
+    assertThat(directoryReloaded.uuid()).isEqualTo(directory.uuid());
+    assertThat(directoryReloaded.moduleUuid()).isEqualTo(directory.moduleUuid());
+    assertThat(directoryReloaded.moduleUuidPath()).isEqualTo(directory.moduleUuidPath());
+    assertThat(directoryReloaded.projectUuid()).isEqualTo(directory.projectUuid());
+    assertThat(directoryReloaded.parentProjectId()).isEqualTo(directory.parentProjectId());
+    assertThat(directoryReloaded.name()).isEqualTo(directory.name());
+    assertThat(directoryReloaded.path()).isEqualTo(directory.path());
+
+    ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get();
+    assertThat(fileReloaded.uuid()).isEqualTo(file.uuid());
+    assertThat(fileReloaded.moduleUuid()).isEqualTo(file.moduleUuid());
+    assertThat(fileReloaded.moduleUuidPath()).isEqualTo(file.moduleUuidPath());
+    assertThat(fileReloaded.projectUuid()).isEqualTo(file.projectUuid());
+    assertThat(fileReloaded.parentProjectId()).isEqualTo(file.parentProjectId());
+    assertThat(fileReloaded.name()).isEqualTo(file.name());
+    assertThat(fileReloaded.path()).isEqualTo(file.path());
+  }
+
+  @Test
+  public void update_module_name() {
+    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
+    dbClient.componentDao().insert(dbTester.getSession(), project);
+    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module").setPath("path");
+    dbClient.componentDao().insert(dbTester.getSession(), module);
+    dbTester.getSession().commit();
+
+    treeRootHolder.setRoot(
+      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
+        .setName("New project name")
+        .addChildren(
+          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
+            .setName("New module name")
+            .setPath("New path")
+            .build())
+        .build());
+
+    underTest.execute();
+
+    ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get();
+    assertThat(projectReloaded.name()).isEqualTo("New project name");
+
+    ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
+    assertThat(moduleReloaded.name()).isEqualTo("New module name");
+  }
+
+  @Test
+  public void update_module_description() {
+    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project").setDescription("Project description");
+    dbClient.componentDao().insert(dbTester.getSession(), project);
+    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module");
+    dbClient.componentDao().insert(dbTester.getSession(), module);
+    dbTester.getSession().commit();
+
+    treeRootHolder.setRoot(
+      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
+        .setName("Project")
+        .setDescription("New project description")
+        .addChildren(
+          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
+            .setName("Module")
+            .setDescription("New module description")
+            .build())
+        .build());
+
+    underTest.execute();
+
+    ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get();
+    assertThat(projectReloaded.description()).isEqualTo("New project description");
+
+    ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
+    assertThat(moduleReloaded.description()).isEqualTo("New module description");
+  }
+
+  @Test
+  public void update_module_path() {
+    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
+    dbClient.componentDao().insert(dbTester.getSession(), project);
+    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module").setPath("path");
+    dbClient.componentDao().insert(dbTester.getSession(), module);
+    dbTester.getSession().commit();
+
+    treeRootHolder.setRoot(
+      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
+        .setName("Project")
+        .addChildren(
+          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
+            .setName("Module")
+            .setPath("New path")
+            .build())
+        .build());
+
+    underTest.execute();
+
+    ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
+    assertThat(moduleReloaded.path()).isEqualTo("New path");
+  }
+
+  @Test
+  public void update_module_uuid_when_moving_a_module() {
+    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
+    dbClient.componentDao().insert(dbTester.getSession(), project);
+    ComponentDto moduleA = ComponentTesting.newModuleDto("EDCB", project).setKey("MODULE_A").setName("Module A");
+    ComponentDto moduleB = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_B").setName("Module B");
+    dbClient.componentDao().insert(dbTester.getSession(), moduleA, moduleB);
+    ComponentDto directory = ComponentTesting.newDirectory(moduleB, "src/main/java/dir").setUuid("CDEF").setKey("MODULE_B:src/main/java/dir");
+    ComponentDto file = ComponentTesting.newFileDto(moduleB, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java").setKey("MODULE_B:src/main/java/dir/Foo.java");
+    dbClient.componentDao().insert(dbTester.getSession(), directory, file);
+    dbTester.getSession().commit();
+
+    treeRootHolder.setRoot(
+      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
+        .setName("Project")
+        .addChildren(
+          builder(Component.Type.MODULE, 2).setUuid("EDCB").setKey("MODULE_A")
+            .setName("Module A")
+            .addChildren(
+              builder(Component.Type.MODULE, 3).setUuid("BCDE").setKey("MODULE_B")
+                .setName("Module B")
+                .addChildren(
+                  builder(DIRECTORY, 4).setUuid("CDEF").setKey("MODULE_B:src/main/java/dir")
+                    .setPath("src/main/java/dir")
+                    .addChildren(
+                      builder(FILE, 5).setUuid("DEFG").setKey("MODULE_B:src/main/java/dir/Foo.java")
+                        .setPath("src/main/java/dir/Foo.java")
+                        .build())
+                    .build())
+                .build())
+            .build())
+        .build());
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5);
+
+    ComponentDto moduleAreloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_A").get();
+
+    ComponentDto moduleBReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B").get();
+    assertThat(moduleBReloaded).isNotNull();
+    assertThat(moduleBReloaded.uuid()).isEqualTo(moduleB.uuid());
+    assertThat(moduleBReloaded.moduleUuid()).isEqualTo(moduleAreloaded.uuid());
+    assertThat(moduleBReloaded.moduleUuidPath()).isEqualTo(moduleAreloaded.moduleUuidPath() + moduleBReloaded.uuid() + ".");
+    assertThat(moduleBReloaded.projectUuid()).isEqualTo(project.uuid());
+    assertThat(moduleBReloaded.parentProjectId()).isEqualTo(project.getId());
+
+    ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B:src/main/java/dir").get();
+    assertThat(directoryReloaded).isNotNull();
+    assertThat(directoryReloaded.uuid()).isEqualTo(directory.uuid());
+    assertThat(directoryReloaded.moduleUuid()).isEqualTo(moduleBReloaded.uuid());
+    assertThat(directoryReloaded.moduleUuidPath()).isEqualTo(moduleBReloaded.moduleUuidPath());
+    assertThat(directoryReloaded.projectUuid()).isEqualTo(project.uuid());
+    assertThat(directoryReloaded.parentProjectId()).isEqualTo(moduleBReloaded.getId());
+
+    ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_B:src/main/java/dir/Foo.java").get();
+    assertThat(fileReloaded).isNotNull();
+    assertThat(fileReloaded.uuid()).isEqualTo(file.uuid());
+    assertThat(fileReloaded.moduleUuid()).isEqualTo(moduleBReloaded.uuid());
+    assertThat(fileReloaded.moduleUuidPath()).isEqualTo(moduleBReloaded.moduleUuidPath());
+    assertThat(fileReloaded.projectUuid()).isEqualTo(project.uuid());
+    assertThat(fileReloaded.parentProjectId()).isEqualTo(moduleBReloaded.getId());
+  }
+
+  @Test
+  public void do_not_update_created_at_on_existing_component() {
+    Date oldDate = DateUtils.parseDate("2015-01-01");
+    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project").setCreatedAt(oldDate);
+    dbClient.componentDao().insert(dbTester.getSession(), project);
+    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module").setPath("path").setCreatedAt(oldDate);
+    dbClient.componentDao().insert(dbTester.getSession(), module);
+    dbTester.getSession().commit();
+
+    treeRootHolder.setRoot(
+      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
+        .setName("New project name")
+        .build());
+
+    underTest.execute();
+
+    Optional<ComponentDto> projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY);
+    assertThat(projectReloaded.get().name()).isEqualTo("New project name");
+    assertThat(projectReloaded.get().getCreatedAt()).isNotEqualTo(now);
+  }
+
+  @Test
+  public void persist_components_that_were_previously_removed() {
+    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
+    dbClient.componentDao().insert(dbTester.getSession(), project);
+    ComponentDto removedModule = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module").setEnabled(false);
+    dbClient.componentDao().insert(dbTester.getSession(), removedModule);
+    ComponentDto removedDirectory = ComponentTesting.newDirectory(removedModule, "src/main/java/dir").setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir").setEnabled(false);
+    ComponentDto removedFile = ComponentTesting.newFileDto(removedModule, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java")
+      .setKey("MODULE_KEY:src/main/java/dir/Foo.java").setEnabled(false);
+    dbClient.componentDao().insert(dbTester.getSession(), removedDirectory, removedFile);
+    dbTester.getSession().commit();
+
+    treeRootHolder.setRoot(
+      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
+        .setName("Project")
+        .addChildren(
+          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
+            .setName("Module")
+            .addChildren(
+              builder(DIRECTORY, 3).setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir")
+                .setPath("src/main/java/dir")
+                .addChildren(
+                  builder(FILE, 4).setUuid("DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java")
+                    .setPath("src/main/java/dir/Foo.java")
+                    .build())
+                .build())
+            .build())
+        .build());
+
+    underTest.execute();
+
+    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
+    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get().getId()).isEqualTo(project.getId());
+    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get().getId()).isEqualTo(removedModule.getId());
+    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get().getId()).isEqualTo(removedDirectory.getId());
+    assertThat(dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get().getId()).isEqualTo(removedFile.getId());
+
+    ComponentDto projectReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), PROJECT_KEY).get();
+    assertThat(projectReloaded.getId()).isEqualTo(project.getId());
+    assertThat(projectReloaded.uuid()).isEqualTo(project.uuid());
+    assertThat(projectReloaded.moduleUuid()).isEqualTo(project.moduleUuid());
+    assertThat(projectReloaded.moduleUuidPath()).isEqualTo(project.moduleUuidPath());
+    assertThat(projectReloaded.projectUuid()).isEqualTo(project.projectUuid());
+    assertThat(projectReloaded.parentProjectId()).isEqualTo(project.parentProjectId());
+    assertThat(projectReloaded.isEnabled()).isTrue();
+
+    ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
+    assertThat(moduleReloaded.getId()).isEqualTo(removedModule.getId());
+    assertThat(moduleReloaded.uuid()).isEqualTo(removedModule.uuid());
+    assertThat(moduleReloaded.moduleUuid()).isEqualTo(removedModule.moduleUuid());
+    assertThat(moduleReloaded.moduleUuidPath()).isEqualTo(removedModule.moduleUuidPath());
+    assertThat(moduleReloaded.projectUuid()).isEqualTo(removedModule.projectUuid());
+    assertThat(moduleReloaded.parentProjectId()).isEqualTo(removedModule.parentProjectId());
+    assertThat(moduleReloaded.isEnabled()).isTrue();
+
+    ComponentDto directoryReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir").get();
+    assertThat(directoryReloaded.getId()).isEqualTo(removedDirectory.getId());
+    assertThat(directoryReloaded.uuid()).isEqualTo(removedDirectory.uuid());
+    assertThat(directoryReloaded.moduleUuid()).isEqualTo(removedDirectory.moduleUuid());
+    assertThat(directoryReloaded.moduleUuidPath()).isEqualTo(removedDirectory.moduleUuidPath());
+    assertThat(directoryReloaded.projectUuid()).isEqualTo(removedDirectory.projectUuid());
+    assertThat(directoryReloaded.parentProjectId()).isEqualTo(removedDirectory.parentProjectId());
+    assertThat(directoryReloaded.name()).isEqualTo(removedDirectory.name());
+    assertThat(directoryReloaded.path()).isEqualTo(removedDirectory.path());
+    assertThat(directoryReloaded.isEnabled()).isTrue();
+
+    ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get();
+    assertThat(fileReloaded.getId()).isEqualTo(fileReloaded.getId());
+    assertThat(fileReloaded.uuid()).isEqualTo(removedFile.uuid());
+    assertThat(fileReloaded.moduleUuid()).isEqualTo(removedFile.moduleUuid());
+    assertThat(fileReloaded.moduleUuidPath()).isEqualTo(removedFile.moduleUuidPath());
+    assertThat(fileReloaded.projectUuid()).isEqualTo(removedFile.projectUuid());
+    assertThat(fileReloaded.parentProjectId()).isEqualTo(removedFile.parentProjectId());
+    assertThat(fileReloaded.name()).isEqualTo(removedFile.name());
+    assertThat(fileReloaded.path()).isEqualTo(removedFile.path());
+    assertThat(fileReloaded.isEnabled()).isTrue();
+  }
+
+  @Test
+  public void update_uuid_when_reactivating_removed_component() {
+    ComponentDto project = ComponentTesting.newProjectDto("ABCD").setKey(PROJECT_KEY).setName("Project");
+    dbClient.componentDao().insert(dbTester.getSession(), project);
+    ComponentDto module = ComponentTesting.newModuleDto("BCDE", project).setKey("MODULE_KEY").setName("Module");
+    ComponentDto removedModule = ComponentTesting.newModuleDto("EDCD", project).setKey("REMOVED_MODULE_KEY").setName("Removed Module").setEnabled(false);
+    dbClient.componentDao().insert(dbTester.getSession(), module, removedModule);
+    ComponentDto directory = ComponentTesting.newDirectory(module, "src/main/java/dir").setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir");
+    // The file was attached to another module
+    ComponentDto removedFile = ComponentTesting.newFileDto(removedModule, "DEFG").setPath("src/main/java/dir/Foo.java").setName("Foo.java")
+      .setKey("MODULE_KEY:src/main/java/dir/Foo.java").setEnabled(false);
+    dbClient.componentDao().insert(dbTester.getSession(), directory, removedFile);
+    dbTester.getSession().commit();
+
+    treeRootHolder.setRoot(
+      builder(PROJECT, 1).setUuid("ABCD").setKey(PROJECT_KEY)
+        .setName("Project")
+        .addChildren(
+          builder(Component.Type.MODULE, 2).setUuid("BCDE").setKey("MODULE_KEY")
+            .setName("Module")
+            .addChildren(
+              builder(DIRECTORY, 3).setUuid("CDEF").setKey("MODULE_KEY:src/main/java/dir")
+                .setPath("src/main/java/dir")
+                .addChildren(
+                  builder(FILE, 4).setUuid("DEFG").setKey("MODULE_KEY:src/main/java/dir/Foo.java")
+                    .setPath("src/main/java/dir/Foo.java")
+                    .build())
+                .build())
+            .build())
+        .build());
+
+    underTest.execute();
+
+    // Projects contains 4 components from the report + one removed module
+    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5);
+
+    ComponentDto moduleReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY").get();
+
+    ComponentDto fileReloaded = dbClient.componentDao().selectByKey(dbTester.getSession(), "MODULE_KEY:src/main/java/dir/Foo.java").get();
+    assertThat(fileReloaded.getId()).isEqualTo(removedFile.getId());
+    assertThat(fileReloaded.uuid()).isEqualTo(removedFile.uuid());
+    assertThat(fileReloaded.moduleUuid()).isEqualTo(moduleReloaded.uuid());
+    assertThat(fileReloaded.moduleUuidPath()).isEqualTo(moduleReloaded.moduleUuidPath());
+    assertThat(fileReloaded.projectUuid()).isEqualTo(moduleReloaded.projectUuid());
+    assertThat(fileReloaded.parentProjectId()).isEqualTo(moduleReloaded.getId());
+    assertThat(fileReloaded.name()).isEqualTo(removedFile.name());
+    assertThat(fileReloaded.path()).isEqualTo(removedFile.path());
+    assertThat(fileReloaded.isEnabled()).isTrue();
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsPersistComponentsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ViewsPersistComponentsStepTest.java
new file mode 100644 (file)
index 0000000..ab6d41f
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+package org.sonar.server.computation.step;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.resources.Scopes;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbTester;
+import org.sonar.db.component.ComponentDto;
+import org.sonar.db.component.ComponentTesting;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.MutableDbIdsRepositoryRule;
+import org.sonar.server.computation.component.ProjectViewAttributes;
+import org.sonar.server.computation.component.ViewsComponent;
+import org.sonar.test.DbTests;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.server.computation.component.Component.Type.PROJECT_VIEW;
+import static org.sonar.server.computation.component.Component.Type.SUBVIEW;
+import static org.sonar.server.computation.component.Component.Type.VIEW;
+import static org.sonar.server.computation.component.ViewsComponent.builder;
+
+@Category(DbTests.class)
+public class ViewsPersistComponentsStepTest extends BaseStepTest {
+
+  private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+
+  private static final String VIEW_KEY = "VIEW_KEY";
+  private static final String VIEW_NAME = "VIEW_NAME";
+  private static final String VIEW_UUID = "VIEW_UUID";
+  private static final String SUBVIEW_1_KEY = "SUBVIEW_1_KEY";
+  private static final String SUBVIEW_1_NAME = "SUBVIEW_1_NAME";
+  private static final String SUBVIEW_1_UUID = "SUBVIEW_1_UUID";
+  private static final String PROJECT_VIEW_1_KEY = "PV1_KEY";
+  private static final String PROJECT_VIEW_1_NAME = "PV1_NAME";
+  private static final String PROJECT_VIEW_1_UUID = "PV1_UUID";
+  private static final long PROJECT_1_ID = 123;
+
+  @Rule
+  public DbTester dbTester = DbTester.create(System2.INSTANCE);
+  @Rule
+  public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+  @Rule
+  public MutableDbIdsRepositoryRule dbIdsRepository = MutableDbIdsRepositoryRule.create(treeRootHolder);
+
+  System2 system2 = mock(System2.class);
+
+  DbClient dbClient = dbTester.getDbClient();
+
+  Date now;
+
+  PersistComponentsStep underTest;
+
+  @Before
+  public void setup() throws Exception {
+    dbTester.truncateTables();
+
+    now = DATE_FORMAT.parse("2015-06-02");
+    when(system2.now()).thenReturn(now.getTime());
+
+    underTest = new PersistComponentsStep(dbClient, treeRootHolder, dbIdsRepository, system2);
+  }
+
+  @Override
+  protected ComputationStep step() {
+    return underTest;
+  }
+
+  @Test
+  public void persist_empty_view() {
+    treeRootHolder.setRoot(createViewBuilder().build());
+
+    underTest.execute();
+
+    assertRowsCountInTableProjects(1);
+
+    ComponentDto projectDto = getComponentFromDb(VIEW_KEY);
+    assertDtoIsView(projectDto);
+  }
+
+  @Test
+  public void persist_existing_empty_view() {
+    // most of the time view already exists since its supposed to be created when config is uploaded
+    persistComponentDto(createViewDto());
+
+    treeRootHolder.setRoot(createViewBuilder().build());
+
+    underTest.execute();
+
+    assertRowsCountInTableProjects(1);
+
+    assertDtoNotUpdated(VIEW_KEY);
+  }
+
+  @Test
+  public void persist_view_with_projectView() {
+    treeRootHolder.setRoot(
+      createViewBuilder()
+        .addChildren(createProjectView1Builder().build())
+        .build());
+
+    underTest.execute();
+
+    assertRowsCountInTableProjects(2);
+
+    ComponentDto viewDto = getComponentFromDb(VIEW_KEY);
+    assertDtoIsView(viewDto);
+
+    ComponentDto pv1Dto = getComponentFromDb(PROJECT_VIEW_1_KEY);
+    assertDtoIsProjectView1(pv1Dto, viewDto, viewDto);
+  }
+
+  @Test
+  public void persist_empty_subview() {
+    treeRootHolder.setRoot(
+      createViewBuilder()
+        .addChildren(
+          createSubView1Builder().build())
+        .build());
+
+    underTest.execute();
+
+    assertRowsCountInTableProjects(2);
+
+    ComponentDto viewDto = getComponentFromDb(VIEW_KEY);
+    assertDtoIsView(viewDto);
+
+    ComponentDto sv1Dto = getComponentFromDb(SUBVIEW_1_KEY);
+    assertDtoIsSubView1(viewDto, sv1Dto);
+  }
+
+  @Test
+  public void persist_existing_empty_subview_under_existing_view() {
+    ComponentDto viewDto = createViewDto();
+    persistComponentDto(viewDto);
+    persistComponentDto(ComponentTesting.newSubView(viewDto, SUBVIEW_1_UUID, SUBVIEW_1_KEY).setName(SUBVIEW_1_NAME));
+
+    treeRootHolder.setRoot(
+      createViewBuilder()
+        .addChildren(
+          createSubView1Builder().build())
+        .build());
+
+    underTest.execute();
+
+    assertRowsCountInTableProjects(2);
+
+    assertDtoNotUpdated(VIEW_KEY);
+    assertDtoNotUpdated(SUBVIEW_1_KEY);
+  }
+
+  @Test
+  public void persist_empty_subview_under_existing_view() {
+    persistComponentDto(createViewDto());
+
+    treeRootHolder.setRoot(
+      createViewBuilder()
+        .addChildren(
+          createSubView1Builder().build())
+        .build());
+
+    underTest.execute();
+
+    assertRowsCountInTableProjects(2);
+
+    assertDtoNotUpdated(VIEW_KEY);
+    assertDtoIsSubView1(getComponentFromDb(VIEW_KEY), getComponentFromDb(SUBVIEW_1_KEY));
+  }
+
+  @Test
+  public void persist_project_view_under_subview() {
+    treeRootHolder.setRoot(
+      createViewBuilder()
+        .addChildren(
+          createSubView1Builder()
+            .addChildren(
+              createProjectView1Builder().build())
+            .build())
+        .build());
+
+    underTest.execute();
+
+    assertRowsCountInTableProjects(3);
+
+    ComponentDto viewDto = getComponentFromDb(VIEW_KEY);
+    assertDtoIsView(viewDto);
+    ComponentDto subView1Dto = getComponentFromDb(SUBVIEW_1_KEY);
+    assertDtoIsSubView1(viewDto, subView1Dto);
+    ComponentDto pv1Dto = getComponentFromDb(PROJECT_VIEW_1_KEY);
+    assertDtoIsProjectView1(pv1Dto, viewDto, subView1Dto);
+  }
+
+  private static ViewsComponent.Builder createViewBuilder() {
+    return builder(VIEW, VIEW_KEY).setUuid(VIEW_UUID).setName(VIEW_NAME);
+  }
+
+  private ViewsComponent.Builder createSubView1Builder() {
+    return builder(SUBVIEW, SUBVIEW_1_KEY).setUuid(SUBVIEW_1_UUID).setName(SUBVIEW_1_NAME);
+  }
+
+  private static ViewsComponent.Builder createProjectView1Builder() {
+    return builder(PROJECT_VIEW, PROJECT_VIEW_1_KEY)
+      .setUuid(PROJECT_VIEW_1_UUID)
+      .setName(PROJECT_VIEW_1_NAME)
+      .setProjectViewAttributes(new ProjectViewAttributes(PROJECT_1_ID));
+  }
+
+  private void persistComponentDto(ComponentDto componentDto) {
+    dbClient.componentDao().insert(dbTester.getSession(), componentDto);
+    dbTester.getSession().commit();
+  }
+
+  private ComponentDto getComponentFromDb(String componentKey) {
+    return dbClient.componentDao().selectByKey(dbTester.getSession(), componentKey).get();
+  }
+
+  private void assertRowsCountInTableProjects(int rowCount) {
+    assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(rowCount);
+  }
+
+  private void assertDtoNotUpdated(String componentKey) {
+    assertThat(getComponentFromDb(componentKey).getCreatedAt()).isNotEqualTo(now);
+  }
+
+  private ComponentDto createViewDto() {
+    return ComponentTesting.newView(VIEW_UUID).setKey(VIEW_KEY).setName(VIEW_NAME);
+  }
+
+  /**
+   * Assertions to verify the DTO created from {@link #createViewBuilder()}
+   */
+  private void assertDtoIsView(ComponentDto projectDto) {
+    assertThat(projectDto.name()).isEqualTo(VIEW_NAME);
+    assertThat(projectDto.longName()).isEqualTo(VIEW_NAME);
+    assertThat(projectDto.description()).isNull();
+    assertThat(projectDto.path()).isNull();
+    assertThat(projectDto.uuid()).isEqualTo(VIEW_UUID);
+    assertThat(projectDto.projectUuid()).isEqualTo(projectDto.uuid());
+    assertThat(projectDto.parentProjectId()).isNull();
+    assertThat(projectDto.moduleUuid()).isNull();
+    assertThat(projectDto.moduleUuidPath()).isEqualTo("." + projectDto.uuid() + ".");
+    assertThat(projectDto.qualifier()).isEqualTo(Qualifiers.VIEW);
+    assertThat(projectDto.scope()).isEqualTo(Scopes.PROJECT);
+    assertThat(projectDto.getCopyResourceId()).isNull();
+    assertThat(projectDto.getCreatedAt()).isEqualTo(now);
+  }
+
+  /**
+   * Assertions to verify the DTO created from {@link #createProjectView1Builder()}
+   */
+  private void assertDtoIsSubView1(ComponentDto viewDto, ComponentDto sv1Dto) {
+    assertThat(sv1Dto.name()).isEqualTo(SUBVIEW_1_NAME);
+    assertThat(sv1Dto.longName()).isEqualTo(SUBVIEW_1_NAME);
+    assertThat(sv1Dto.description()).isNull();
+    assertThat(sv1Dto.path()).isNull();
+    assertThat(sv1Dto.uuid()).isEqualTo(SUBVIEW_1_UUID);
+    assertThat(sv1Dto.projectUuid()).isEqualTo(viewDto.uuid());
+    assertThat(sv1Dto.parentProjectId()).isEqualTo(viewDto.getId());
+    assertThat(sv1Dto.moduleUuid()).isEqualTo(viewDto.uuid());
+    assertThat(sv1Dto.moduleUuidPath()).isEqualTo(viewDto.moduleUuidPath() + sv1Dto.uuid() + ".");
+    assertThat(sv1Dto.qualifier()).isEqualTo(Qualifiers.SUBVIEW);
+    assertThat(sv1Dto.scope()).isEqualTo(Scopes.PROJECT);
+    assertThat(sv1Dto.getCopyResourceId()).isNull();
+    assertThat(sv1Dto.getCreatedAt()).isEqualTo(now);
+  }
+
+  private void assertDtoIsProjectView1(ComponentDto pv1Dto, ComponentDto viewDto, ComponentDto parentViewDto) {
+    assertThat(pv1Dto.name()).isEqualTo(PROJECT_VIEW_1_NAME);
+    assertThat(pv1Dto.longName()).isEqualTo(PROJECT_VIEW_1_NAME);
+    assertThat(pv1Dto.description()).isNull();
+    assertThat(pv1Dto.path()).isNull();
+    assertThat(pv1Dto.uuid()).isEqualTo(PROJECT_VIEW_1_UUID);
+    assertThat(pv1Dto.projectUuid()).isEqualTo(viewDto.uuid());
+    assertThat(pv1Dto.parentProjectId()).isEqualTo(viewDto.getId());
+    assertThat(pv1Dto.moduleUuid()).isEqualTo(parentViewDto.uuid());
+    assertThat(pv1Dto.moduleUuidPath()).isEqualTo(parentViewDto.moduleUuidPath() + pv1Dto.uuid() + ".");
+    assertThat(pv1Dto.qualifier()).isEqualTo(Qualifiers.PROJECT);
+    assertThat(pv1Dto.scope()).isEqualTo(Scopes.FILE);
+    assertThat(pv1Dto.getCopyResourceId()).isEqualTo(PROJECT_1_ID);
+    assertThat(pv1Dto.getCreatedAt()).isEqualTo(now);
+  }
+
+}