]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-9326 ensure ISSUES.PROJECT_UUID is consistent with component 2122/head
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 29 May 2017 15:31:39 +0000 (17:31 +0200)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 1 Jun 2017 13:18:14 +0000 (15:18 +0200)
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/DbVersion65.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/EnsureIssueProjectUuidConsistencyOnIssues.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v65/DbVersion65Test.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v65/EnsureIssueProjectUuidConsistencyOnIssuesTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v65/EnsureIssueProjectUuidConsistencyOnIssuesTest/issues_and_projects.sql [new file with mode: 0644]

index a4261fd13fa7075658155d1a3fba6d91d86065cb..b5dcb1b5cb98b27f492ed2d52157f424320c5a91 100644 (file)
@@ -33,6 +33,7 @@ public class DbVersion65 implements DbVersion {
       .add(1703, "Populate EVENTS.COMPONENT_UUID", PopulateEventsComponentUuid.class)
       .add(1704, "Drop index EVENTS_COMPONENT_UUID", DropIndexEventsComponentUuid.class)
       .add(1705, "Make EVENTS.COMPONENT_UUID not nullable", MakeEventsComponentUuidNotNullable.class)
-      .add(1706, "Recreate index EVENTS_COMPONENT_UUID", RecreateIndexEventsComponentUuid.class);
+      .add(1706, "Recreate index EVENTS_COMPONENT_UUID", RecreateIndexEventsComponentUuid.class)
+      .add(1707, "Ensure ISSUE.PROJECT_UUID is consistent", EnsureIssueProjectUuidConsistencyOnIssues.class);
   }
 }
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/EnsureIssueProjectUuidConsistencyOnIssues.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v65/EnsureIssueProjectUuidConsistencyOnIssues.java
new file mode 100644 (file)
index 0000000..b40f091
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.platform.db.migration.version.v65;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
+
+public class EnsureIssueProjectUuidConsistencyOnIssues extends DataChange {
+  public EnsureIssueProjectUuidConsistencyOnIssues(Database db) {
+    super(db);
+  }
+
+  @Override
+  protected void execute(Context context) throws SQLException {
+    MassUpdate massUpdate = context.prepareMassUpdate();
+    massUpdate.select("select" +
+      " i.id, p.project_uuid" +
+      " from issues i" +
+      " inner join projects p on" +
+      "   p.uuid = i.component_uuid" +
+      "   and i.project_uuid <> p.project_uuid");
+    massUpdate.update("update issues set project_uuid = ? where id = ?");
+    massUpdate.rowPluralName("issues with inconsistent project_uuid");
+    massUpdate.execute(EnsureIssueProjectUuidConsistencyOnIssues::handle);
+  }
+
+  private static boolean handle(Select.Row row, SqlStatement update) throws SQLException {
+    long issueId = row.getLong(1);
+    String projectUuid = row.getString(2);
+
+    update.setString(1, projectUuid);
+    update.setLong(2, issueId);
+
+    return true;
+  }
+}
index 1ff63d12cb9d69c9bbd08bd58f9df2e787f8c878..f63f9942ec01ac97266b57eb7f09ceb5930d42ac 100644 (file)
@@ -35,6 +35,6 @@ public class DbVersion65Test {
 
   @Test
   public void verify_migration_count() {
-    verifyMigrationCount(underTest, 7);
+    verifyMigrationCount(underTest, 8);
   }
 }
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v65/EnsureIssueProjectUuidConsistencyOnIssuesTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v65/EnsureIssueProjectUuidConsistencyOnIssuesTest.java
new file mode 100644 (file)
index 0000000..6096ff2
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program 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.
+ *
+ * This program 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.platform.db.migration.version.v65;
+
+import java.sql.SQLException;
+import java.util.Random;
+import javax.annotation.Nullable;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class EnsureIssueProjectUuidConsistencyOnIssuesTest {
+  @Rule
+  public CoreDbTester db = CoreDbTester.createForSchema(EnsureIssueProjectUuidConsistencyOnIssuesTest.class, "issues_and_projects.sql");
+
+  private final Random random = new Random();
+  private EnsureIssueProjectUuidConsistencyOnIssues underTest = new EnsureIssueProjectUuidConsistencyOnIssues(db.database());
+
+  @Test
+  public void execute_has_no_effect_if_tables_are_empty() throws SQLException {
+    underTest.execute();
+  }
+
+  @Test
+  public void execute_fixes_project_uuid_of_issue_when_inconsistent_with_PROJECTS_PROJECT_UUID() throws SQLException {
+    String projectUuid = randomAlphabetic(5);
+    String componentUuid = insertComponent(projectUuid);
+    String inconsistentIssueKey = insertIssue(componentUuid, randomAlphabetic(9));
+    String consistentIssueKey = insertIssue(componentUuid, projectUuid);
+
+    underTest.execute();
+
+    assertThat(getProjectUuid(inconsistentIssueKey)).isEqualTo(projectUuid);
+    assertThat(getProjectUuid(consistentIssueKey)).isEqualTo(projectUuid);
+  }
+
+  @Test
+  public void execute_ignores_issues_which_component_does_not_exist() throws SQLException {
+    String projectUuid = randomAlphabetic(3);
+    String issueKey = insertIssue(randomAlphabetic(8), projectUuid);
+
+    underTest.execute();
+
+    assertThat(getProjectUuid(issueKey)).isEqualTo(projectUuid);
+  }
+
+  @Test
+  public void execute_ignores_issues_which_null_project_uuid() throws SQLException {
+    String issueKey = insertIssue(randomAlphabetic(8), null);
+
+    underTest.execute();
+
+    assertThat(getProjectUuid(issueKey)).isNull();
+  }
+
+  @Test
+  public void execute_ignores_issues_which_null_component_uuid() throws SQLException {
+    String projectUuid = randomAlphabetic(5);
+    String issueKey = insertIssue(null, projectUuid);
+
+    underTest.execute();
+
+    assertThat(getProjectUuid(issueKey)).isEqualTo(projectUuid);
+  }
+
+  private String getProjectUuid(String issueKey) {
+    return (String) db.selectFirst("select project_uuid as \"PROJECT_UUID\" from issues where kee = '" + issueKey + "'")
+      .get("PROJECT_UUID");
+  }
+
+  private String insertIssue(@Nullable String componentUuid, @Nullable String projectUuid) {
+    String issueKey = randomAlphabetic(3);
+    db.executeInsert(
+      "ISSUES",
+      "KEE", issueKey,
+      "COMPONENT_UUID", componentUuid,
+      "PROJECT_UUID", projectUuid,
+      "MANUAL_SEVERITY", String.valueOf(random.nextBoolean()));
+    return issueKey;
+  }
+
+  private String insertComponent(String projectUuid) {
+    String uuid = randomAlphabetic(5);
+    db.executeInsert(
+      "PROJECTS",
+      "ORGANIZATION_UUID", randomAlphabetic(5),
+      "UUID", uuid,
+      "UUID_PATH", "path_" + uuid,
+      "ROOT_UUID", "root_uuid_" + uuid,
+      "PROJECT_UUID", projectUuid,
+      "PRIVATE", String.valueOf(random.nextBoolean()),
+      "ENABLED", String.valueOf(random.nextBoolean()));
+    return uuid;
+  }
+}
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v65/EnsureIssueProjectUuidConsistencyOnIssuesTest/issues_and_projects.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v65/EnsureIssueProjectUuidConsistencyOnIssuesTest/issues_and_projects.sql
new file mode 100644 (file)
index 0000000..6722d72
--- /dev/null
@@ -0,0 +1,83 @@
+CREATE TABLE "ISSUES" (
+  "ID" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "KEE" VARCHAR(50) UNIQUE NOT NULL,
+  "COMPONENT_UUID" VARCHAR(50),
+  "PROJECT_UUID" VARCHAR(50),
+  "RULE_ID" INTEGER,
+  "SEVERITY" VARCHAR(10),
+  "MANUAL_SEVERITY" BOOLEAN NOT NULL,
+  "MESSAGE" VARCHAR(4000),
+  "LINE" INTEGER,
+  "GAP" DOUBLE,
+  "EFFORT" INTEGER,
+  "STATUS" VARCHAR(20),
+  "RESOLUTION" VARCHAR(20),
+  "CHECKSUM" VARCHAR(1000),
+  "REPORTER" VARCHAR(255),
+  "ASSIGNEE" VARCHAR(255),
+  "AUTHOR_LOGIN" VARCHAR(255),
+  "ACTION_PLAN_KEY" VARCHAR(50) NULL,
+  "ISSUE_ATTRIBUTES" VARCHAR(4000),
+  "TAGS" VARCHAR(4000),
+  "ISSUE_CREATION_DATE" BIGINT,
+  "ISSUE_CLOSE_DATE" BIGINT,
+  "ISSUE_UPDATE_DATE" BIGINT,
+  "CREATED_AT" BIGINT,
+  "UPDATED_AT" BIGINT,
+  "LOCATIONS" BLOB,
+  "ISSUE_TYPE" TINYINT
+);
+CREATE UNIQUE INDEX "ISSUES_KEE" ON "ISSUES" ("KEE");
+CREATE INDEX "ISSUES_COMPONENT_UUID" ON "ISSUES" ("COMPONENT_UUID");
+CREATE INDEX "ISSUES_PROJECT_UUID" ON "ISSUES" ("PROJECT_UUID");
+CREATE INDEX "ISSUES_RULE_ID" ON "ISSUES" ("RULE_ID");
+CREATE INDEX "ISSUES_RESOLUTION" ON "ISSUES" ("RESOLUTION");
+CREATE INDEX "ISSUES_ASSIGNEE" ON "ISSUES" ("ASSIGNEE");
+CREATE INDEX "ISSUES_CREATION_DATE" ON "ISSUES" ("ISSUE_CREATION_DATE");
+CREATE INDEX "ISSUES_UPDATED_AT" ON "ISSUES" ("UPDATED_AT");
+
+CREATE TABLE "PROJECTS" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "ORGANIZATION_UUID" VARCHAR(40) NOT NULL,
+  "KEE" VARCHAR(400),
+  "UUID" VARCHAR(50) NOT NULL,
+  "UUID_PATH" VARCHAR(1500) NOT NULL,
+  "ROOT_UUID" VARCHAR(50) NOT NULL,
+  "PROJECT_UUID" VARCHAR(50) NOT NULL,
+  "MODULE_UUID" VARCHAR(50),
+  "MODULE_UUID_PATH" VARCHAR(1500),
+  "NAME" VARCHAR(2000),
+  "DESCRIPTION" VARCHAR(2000),
+  "PRIVATE" BOOLEAN NOT NULL,
+  "TAGS" VARCHAR(500),
+  "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE,
+  "SCOPE" VARCHAR(3),
+  "QUALIFIER" VARCHAR(10),
+  "DEPRECATED_KEE" VARCHAR(400),
+  "PATH" VARCHAR(2000),
+  "LANGUAGE" VARCHAR(20),
+  "COPY_COMPONENT_UUID" VARCHAR(50),
+  "LONG_NAME" VARCHAR(2000),
+  "DEVELOPER_UUID" VARCHAR(50),
+  "CREATED_AT" TIMESTAMP,
+  "AUTHORIZATION_UPDATED_AT" BIGINT,
+  "B_CHANGED" BOOLEAN,
+  "B_COPY_COMPONENT_UUID" VARCHAR(50),
+  "B_DESCRIPTION" VARCHAR(2000),
+  "B_ENABLED" BOOLEAN,
+  "B_UUID_PATH" VARCHAR(1500),
+  "B_LANGUAGE" VARCHAR(20),
+  "B_LONG_NAME" VARCHAR(500),
+  "B_MODULE_UUID" VARCHAR(50),
+  "B_MODULE_UUID_PATH" VARCHAR(1500),
+  "B_NAME" VARCHAR(500),
+  "B_PATH" VARCHAR(2000),
+  "B_QUALIFIER" VARCHAR(10)
+);
+CREATE INDEX "PROJECTS_ORGANIZATION" ON "PROJECTS" ("ORGANIZATION_UUID");
+CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE");
+CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID");
+CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID");
+CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID");
+CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID");
+CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER");