]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-12127 don't run new migrations when upgrading from 7.0
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Wed, 26 Jun 2019 13:57:04 +0000 (15:57 +0200)
committerSonarTech <sonartech@sonarsource.com>
Fri, 28 Jun 2019 18:21:12 +0000 (20:21 +0200)
server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/MigrationConfigurationModule.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/MigrationHistoryImpl.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/MigrationHistoryMeddler.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/history/MigrationHistoryImplTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/history/MigrationHistoryMeddlerTest.java [new file with mode: 0644]

index e35c0192c82bc21700e5da7c236c189669659781..3f923deac85caac52a30f28333059348af9adb73 100644 (file)
@@ -122,7 +122,7 @@ public class ComputeEngineContainerImplTest {
       );
       assertThat(picoContainer.getParent().getParent().getComponentAdapters()).hasSize(
         CONTAINER_ITSELF
-          + 23 // MigrationConfigurationModule
+          + 24 // MigrationConfigurationModule
           + 17 // level 2
       );
       assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize(
index b11239533fe0b3e56c10d9d96ab9a7a4c3e26a70..081b4db7f84e909540c41b4c81ac6d49d8312c84 100644 (file)
@@ -21,6 +21,7 @@ package org.sonar.server.platform.db.migration;
 
 import org.sonar.core.platform.Module;
 import org.sonar.server.platform.db.migration.history.MigrationHistoryImpl;
+import org.sonar.server.platform.db.migration.history.MigrationHistoryMeddler;
 import org.sonar.server.platform.db.migration.step.MigrationStepRegistryImpl;
 import org.sonar.server.platform.db.migration.step.MigrationStepsProvider;
 import org.sonar.server.platform.db.migration.version.v56.DbVersion56;
@@ -75,6 +76,7 @@ public class MigrationConfigurationModule extends Module {
       new MigrationStepsProvider(),
 
       // history
-      MigrationHistoryImpl.class);
+      MigrationHistoryImpl.class,
+      MigrationHistoryMeddler.class);
   }
 }
index a14ca6cb8508c9c3bc0f2497a521b0b6e9495267..200794806ad85c8fa1d48a01ac30a4291bb4bbd3 100644 (file)
@@ -40,15 +40,18 @@ public class MigrationHistoryImpl implements MigrationHistory {
   private static final String SCHEMA_MIGRATIONS_TABLE = "schema_migrations";
 
   private final Database database;
+  private final MigrationHistoryMeddler migrationHistoryMeddler;
 
-  public MigrationHistoryImpl(Database database) {
+  public MigrationHistoryImpl(Database database, MigrationHistoryMeddler migrationHistoryMeddler) {
     this.database = database;
+    this.migrationHistoryMeddler = migrationHistoryMeddler;
   }
 
   @Override
   public void start() {
     try (Connection connection = database.getDataSource().getConnection()) {
       checkState(DatabaseUtils.tableExists(MigrationHistoryTable.NAME, connection), "Migration history table is missing");
+      migrationHistoryMeddler.meddle(this);
     } catch (SQLException e) {
       Throwables.propagate(e);
     }
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/MigrationHistoryMeddler.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/MigrationHistoryMeddler.java
new file mode 100644 (file)
index 0000000..4fc9937
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.history;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import org.sonar.server.platform.db.migration.step.MigrationSteps;
+import org.sonar.server.platform.db.migration.step.RegisteredMigrationStep;
+
+/**
+ * Under some conditions, the migration history must be manipulated. This is the role of this class
+ * which is called by {@link MigrationHistory#start()}.
+ */
+public class MigrationHistoryMeddler {
+  private final Map<Long, Long> meddledSteps = ImmutableMap.of(
+    // SONAR-12127 several DB migration were added in 7.9 to migrate to from 6.7 to 7.0
+    // If already on 7.0, we don't want any of these DB migrations ran
+    // => we change last migration number of those 7.0 instance to the new max migration number for 7.0
+    1_923L, 1_959L);
+  private final MigrationSteps migrationSteps;
+
+  public MigrationHistoryMeddler(MigrationSteps migrationSteps) {
+    this.migrationSteps = migrationSteps;
+  }
+
+  public void meddle(MigrationHistory migrationHistory) {
+    // change last migration number on specific cases
+    migrationHistory.getLastMigrationNumber()
+      .ifPresent(migrationNumber -> {
+        Long newMigrationNumber = meddledSteps.get(migrationNumber);
+        if (newMigrationNumber != null) {
+          RegisteredMigrationStep registeredMigrationStep = migrationSteps.readFrom(newMigrationNumber).get(0);
+          migrationHistory.done(registeredMigrationStep);
+        }
+      });
+  }
+}
index 9aee9d6a1cb6886a1014b6983d0f42584db07a7e..3ac7734cc18ec55f87c96b75adbccb687aa8da45 100644 (file)
@@ -31,6 +31,8 @@ import org.sonar.server.platform.db.migration.step.MigrationStep;
 import org.sonar.server.platform.db.migration.step.RegisteredMigrationStep;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 public class MigrationHistoryImplTest {
   @Rule
@@ -38,11 +40,14 @@ public class MigrationHistoryImplTest {
   @Rule
   public ExpectedException expectedException = ExpectedException.none();
 
-  private MigrationHistoryImpl underTest = new MigrationHistoryImpl(dbTester.database());
+  private MigrationHistoryMeddler migrationHistoryMeddler = mock(MigrationHistoryMeddler.class);
+  private MigrationHistoryImpl underTest = new MigrationHistoryImpl(dbTester.database(), migrationHistoryMeddler);
 
   @Test
-  public void start_does_not_fail_if_table_history_exists() {
+  public void start_does_not_fail_if_table_history_exists_and_calls_meddler() {
     underTest.start();
+
+    verify(migrationHistoryMeddler).meddle(underTest);
   }
 
   @Test
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/history/MigrationHistoryMeddlerTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/history/MigrationHistoryMeddlerTest.java
new file mode 100644 (file)
index 0000000..09f80f8
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.history;
+
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
+import java.util.List;
+import java.util.Optional;
+import java.util.Random;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.sonar.server.platform.db.migration.step.MigrationStep;
+import org.sonar.server.platform.db.migration.step.MigrationSteps;
+import org.sonar.server.platform.db.migration.step.RegisteredMigrationStep;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(DataProviderRunner.class)
+public class MigrationHistoryMeddlerTest {
+  private static final long OLD_VERSION_70_LAST_MIGRATION_NUMBER = 1_923L;
+  private static final long NEW_VERSION_70_LAST_MIGRATION_NUMBER = 1_959L;
+
+  private MigrationSteps migrationSteps = mock(MigrationSteps.class);
+  private MigrationHistory migrationHistory = mock(MigrationHistory.class);
+  private MigrationHistoryMeddler underTest = new MigrationHistoryMeddler(migrationSteps);
+
+  @Test
+  public void no_effect_if_no_last_migration_number() {
+    when(migrationHistory.getLastMigrationNumber()).thenReturn(Optional.empty());
+
+    underTest.meddle(migrationHistory);
+
+    verify(migrationHistory).getLastMigrationNumber();
+    verifyNoMoreInteractions(migrationHistory, migrationSteps);
+  }
+
+  @Test
+  @UseDataProvider("non_old_70_last_migration_number")
+  public void no_history_meddling_if_last_migration_number_is_not_old_70_last_migration_number(long lastMigrationNumber) {
+    when(migrationHistory.getLastMigrationNumber()).thenReturn(Optional.of(lastMigrationNumber));
+
+    underTest.meddle(migrationHistory);
+
+    verify(migrationHistory).getLastMigrationNumber();
+    verifyNoMoreInteractions(migrationHistory, migrationSteps);
+  }
+
+  @Test
+  public void update_last_migration_number_if_last_migration_number_is_old_70_last_migration_number() {
+    verifyUpdateLastMigrationNumber(OLD_VERSION_70_LAST_MIGRATION_NUMBER, NEW_VERSION_70_LAST_MIGRATION_NUMBER);
+  }
+
+  public void verifyUpdateLastMigrationNumber(long oldVersion, long expectedNewVersion) {
+    when(migrationHistory.getLastMigrationNumber()).thenReturn(Optional.of(oldVersion));
+    List<RegisteredMigrationStep> stepsFromNewLastMigrationNumber = IntStream.range(0, 1 + new Random().nextInt(30))
+      .mapToObj(i -> new RegisteredMigrationStep(i, "desc_" + i, MigrationStep.class))
+      .collect(Collectors.toList());
+    when(migrationSteps.readFrom(expectedNewVersion)).thenReturn(stepsFromNewLastMigrationNumber);
+
+    underTest.meddle(migrationHistory);
+
+    verify(migrationHistory).getLastMigrationNumber();
+    verify(migrationSteps).readFrom(expectedNewVersion);
+    verify(migrationHistory).done(stepsFromNewLastMigrationNumber.get(0));
+    verifyNoMoreInteractions(migrationHistory, migrationSteps);
+  }
+
+  @DataProvider
+  public static Object[][] non_old_70_last_migration_number() {
+    return new Object[][] {
+      {1L},
+      {OLD_VERSION_70_LAST_MIGRATION_NUMBER - 1 - new Random().nextInt(12)},
+      {OLD_VERSION_70_LAST_MIGRATION_NUMBER + 1 + new Random().nextInt(12)}
+    };
+  }
+
+}