]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-14691 - Fix 4122 DB migration for repeated projects in apps
authorBelen Pruvost <belen.pruvost@sonarsource.com>
Thu, 15 Apr 2021 15:20:48 +0000 (17:20 +0200)
committersonartech <sonartech@sonarsource.com>
Fri, 16 Apr 2021 20:03:43 +0000 (20:03 +0000)
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v86/MigrateApplicationDefinitionsFromXmlToDb.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v86/MigrateApplicationDefinitionsFromXmlToDbTest.java

index e5f6fd506180e824a796a3499304551e66597a24..2dce4e79808a0960083f91cf3c07260ce6aff8cb 100644 (file)
@@ -29,6 +29,7 @@ import java.sql.SQLException;
 import java.util.AbstractMap;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -122,15 +123,15 @@ public class MigrateApplicationDefinitionsFromXmlToDb extends DataChange {
     // skip migration if:
     // - application only exists in xml and not in the db. It will be removed from the xml at later stage of the migration.
     // - application contains no projects- it's already in a valid db state
-    List<String> projects = app.getProjects();
-    if (applicationUuid == null || projects.isEmpty()) {
+    Set<String> uniqueProjects = new HashSet<>(app.getProjects());
+    if (applicationUuid == null || uniqueProjects.isEmpty()) {
       return;
     }
 
     List<String> alreadyAddedProjects = context.prepareSelect(SELECT_PROJECTS_BY_APP).setString(1, applicationUuid)
       .list(r -> r.getString(1));
 
-    String queryParam = projects.stream().map(uuid -> "'" + uuid + "'").collect(Collectors.joining(","));
+    String queryParam = uniqueProjects.stream().map(uuid -> "'" + uuid + "'").collect(Collectors.joining(","));
     Map<String, String> projectUuidsByKeys = context.prepareSelect(format(SELECT_PROJECTS_BY_KEYS, queryParam))
       .list(r -> new AbstractMap.SimpleEntry<>(r.getString(1), r.getString(2)))
       .stream()
@@ -138,7 +139,7 @@ public class MigrateApplicationDefinitionsFromXmlToDb extends DataChange {
       .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue));
 
     if (!projectUuidsByKeys.isEmpty()) {
-      insertApplicationProjects(context, app, applicationUuid, projectUuidsByKeys, now);
+      insertApplicationProjects(context, app, applicationUuid, projectUuidsByKeys, uniqueProjects, now);
     }
     if (!app.getApplicationBranches().isEmpty()) {
       insertApplicationBranchesProjects(context, app, applicationUuid, projectUuidsByKeys, now);
@@ -146,11 +147,11 @@ public class MigrateApplicationDefinitionsFromXmlToDb extends DataChange {
   }
 
   private void insertApplicationProjects(Context context, ViewXml.ViewDef app, String applicationUuid,
-    Map<String, String> projectUuidsByKeys, long createdTime) throws SQLException {
+    Map<String, String> projectUuidsByKeys, Set<String> uniqueProjects, long createdTime) throws SQLException {
     Upsert insertApplicationProjectsQuery = context.prepareUpsert("insert into " +
       "app_projects(uuid, application_uuid, project_uuid, created_at) " +
       "values (?, ?, ?, ?)");
-    for (String projectKey : app.getProjects()) {
+    for (String projectKey : uniqueProjects) {
       String applicationProjectUuid = uuidFactory.create();
       String projectUuid = projectUuidsByKeys.get(projectKey);
 
index 794a438a47f6f40946a4bc4812949c852373d212..0d083a13f6578af445e6385bc9ddd403f5792029 100644 (file)
@@ -78,6 +78,22 @@ public class MigrateApplicationDefinitionsFromXmlToDbTest {
     "    </vw>\n" +
     "</views>";
 
+  private static final String APP_WITH_DUPLICATED_PROJECTS_XML = "<views>\n" +
+    "    <vw key=\"app1-key\" def=\"false\">\n" +
+    "        <name><![CDATA[app1-key]]></name>\n" +
+    "        <desc><![CDATA[]]></desc>\n" +
+    "        <qualifier><![CDATA[APP]]></qualifier>\n" +
+    "        <p>proj1-key</p>\n" +
+    "        <p>proj1-key</p>\n" +
+    "        <branch key=\"app1-branch1\">\n" +
+    "            <p branch=\"proj1-branch-1\">proj1-key</p>\n" +
+    "        </branch>\n" +
+    "        <branch key=\"app1-branch2\">\n" +
+    "            <p branch=\"proj1-branch-2\">proj1-key</p>\n" +
+    "        </branch>\n" +
+    "    </vw>\n" +
+    "</views>";
+
   private static final String COMPLEX_XML_BEFORE = "<views>\n" +
     "    <vw key=\"app1-key\" def=\"false\">\n" +
     "        <name><![CDATA[app1-key]]></name>\n" +
@@ -433,6 +449,26 @@ public class MigrateApplicationDefinitionsFromXmlToDbTest {
         tuple(APP_2_UUID, PROJECT_2_UUID, APP_2_BRANCH_1_UUID, PROJECT_2_BRANCH_1_UUID));
   }
 
+  @Test
+  public void migrates_applications_handling_project_duplications_to_new_tables() throws SQLException {
+    setupProjectsAndApps();
+    insertViewsDefInternalProperty(APP_WITH_DUPLICATED_PROJECTS_XML);
+
+    underTest.execute();
+
+    assertThat(db.select("select uuid from projects"))
+      .extracting(r -> r.get("UUID"))
+      .containsExactlyInAnyOrder(PROJECT_1_UUID, PROJECT_2_UUID, APP_1_UUID, APP_2_UUID);
+    assertThat(db.select("select application_uuid, project_uuid from app_projects"))
+      .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"))
+      .containsExactly(tuple(APP_1_UUID, PROJECT_1_UUID));
+    assertThat(db.select("select application_uuid, project_uuid, application_branch_uuid, project_branch_uuid from app_branch_project_branch"))
+      .extracting(r -> r.get("APPLICATION_UUID"), r -> r.get("PROJECT_UUID"), r -> r.get("APPLICATION_BRANCH_UUID"), r -> r.get("PROJECT_BRANCH_UUID"))
+      .containsExactlyInAnyOrder(
+        tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_1_UUID, PROJECT_1_BRANCH_1_UUID),
+        tuple(APP_1_UUID, PROJECT_1_UUID, APP_1_BRANCH_2_UUID, PROJECT_1_BRANCH_2_UUID));
+  }
+
   @Test
   public void migration_is_resilient() throws SQLException {
     setupProjectsAndApps();