--- /dev/null
+/*
+ * 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);
+ }
+ });
+ }
+}
--- /dev/null
+/*
+ * 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)}
+ };
+ }
+
+}