diff options
author | Aleksandra Bozhinoska <aleksandra.bozhinoska@sonarsource.com> | 2025-02-25 13:53:27 +0100 |
---|---|---|
committer | Lukasz Jarocki <lukasz.jarocki@sonarsource.com> | 2025-02-28 09:57:48 +0100 |
commit | 28fe0fe355dd799b52c8741282a355d584d23253 (patch) | |
tree | a023a65b8fbd906fc69e8cf37f3f8ffeb547dfb5 /server | |
parent | 86670bc803d6bedaa7703da7f7e0aa072cf6977d (diff) | |
download | sonarqube-28fe0fe355dd799b52c8741282a355d584d23253.tar.gz sonarqube-28fe0fe355dd799b52c8741282a355d584d23253.zip |
SONAR-24358 Make measures migration reentrant
Diffstat (limited to 'server')
3 files changed, 113 insertions, 2 deletions
diff --git a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigrateBranchesLiveMeasuresToMeasuresIT.java b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigrateBranchesLiveMeasuresToMeasuresIT.java index 6418fdeddc4..308aa8495e2 100644 --- a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigrateBranchesLiveMeasuresToMeasuresIT.java +++ b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigrateBranchesLiveMeasuresToMeasuresIT.java @@ -167,6 +167,43 @@ class MigrateBranchesLiveMeasuresToMeasuresIT { } @Test + void should_duplicate_measures_on_reentry_when_index_does_not_exist() throws SQLException { + String nclocMetricUuid = insertMetric("ncloc", "INT"); + + String branch1 = "branch_1"; + insertNotMigratedBranch(branch1); + String component1 = uuidFactory.create(); + insertMeasure(branch1, component1, nclocMetricUuid, Map.of("value", 120)); + + insertMigratedMeasure(branch1, component1); + assertThat(db.countRowsOfTable("measures")).isEqualTo(1); + + underTest.execute(); + + assertThat(db.countRowsOfTable("measures")).isEqualTo(2); + } + + @Test + void should_remove_migrated_measures_on_reentry_when_index_exists() throws SQLException { + String nclocMetricUuid = insertMetric("ncloc", "INT"); + + String branch1 = "branch_1"; + insertNotMigratedBranch(branch1); + String component1 = uuidFactory.create(); + insertMeasure(branch1, component1, nclocMetricUuid, Map.of("value", 120)); + + insertMigratedMeasure(branch1, component1); + assertThat(db.countRowsOfTable("measures")).isEqualTo(1); + + var createIndexMigration = new CreateIndexOnMeasuresTable(db.database()); + createIndexMigration.execute(); + + underTest.execute(); + + assertThat(db.countRowsOfTable("measures")).isEqualTo(1); + } + + @Test void should_not_migrate_measures_planned_for_deletion() throws SQLException { String nclocMetricUuid = insertMetric("ncloc", "INT"); Set<String> deletedMetricUuid = DeleteSoftwareQualityRatingFromProjectMeasures.SOFTWARE_QUALITY_METRICS_TO_DELETE.stream().map(e -> insertMetric(e, "INT")) @@ -381,4 +418,14 @@ class MigrateBranchesLiveMeasuresToMeasuresIT { "updated_at", 12L); } + private void insertMigratedMeasure(String branch, String componentUuid) { + db.executeInsert("measures", + "component_uuid", componentUuid, + "branch_uuid", branch, + "json_value", "{\"any\":\"thing\"}", + "json_value_hash", "1234", + "created_at", 12, + "updated_at", 12); + } + } diff --git a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigratePortfoliosLiveMeasuresToMeasuresIT.java b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigratePortfoliosLiveMeasuresToMeasuresIT.java index f0a197af534..79dd5abe808 100644 --- a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigratePortfoliosLiveMeasuresToMeasuresIT.java +++ b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v108/MigratePortfoliosLiveMeasuresToMeasuresIT.java @@ -186,6 +186,43 @@ class MigratePortfoliosLiveMeasuresToMeasuresIT { .containsOnly(tuple(component1, portfolio1, "{\"ncloc\":120.0}", -1557106439558598045L)); } + @Test + void should_duplicate_measures_on_reentry_when_index_does_not_exist() throws SQLException { + String nclocMetricUuid = insertMetric("ncloc", "INT"); + + String portfolio1 = "portfolio_1"; + insertNotMigratedPortfolio(portfolio1); + String component1 = uuidFactory.create(); + insertMeasure(portfolio1, component1, nclocMetricUuid, Map.of("value", 120)); + + insertMigratedMeasure(portfolio1, component1); + assertThat(db.countRowsOfTable("measures")).isEqualTo(1); + + underTest.execute(); + + assertThat(db.countRowsOfTable("measures")).isEqualTo(2); + } + + @Test + void should_remove_migrated_measures_on_reentry_when_index_exists() throws SQLException { + String nclocMetricUuid = insertMetric("ncloc", "INT"); + + String portfolio1 = "portfolio_1"; + insertNotMigratedPortfolio(portfolio1); + String component1 = uuidFactory.create(); + insertMeasure(portfolio1, component1, nclocMetricUuid, Map.of("value", 120)); + + insertMigratedMeasure(portfolio1, component1); + assertThat(db.countRowsOfTable("measures")).isEqualTo(1); + + var createIndexMigration = new CreateIndexOnMeasuresTable(db.database()); + createIndexMigration.execute(); + + underTest.execute(); + + assertThat(db.countRowsOfTable("measures")).isEqualTo(1); + } + private void assertPortfolioMigrated(String portfolio) { List<Map<String, Object>> result = db.select(format("select %s as \"MIGRATED\" from portfolios where uuid = '%s'", MEASURES_MIGRATED_COLUMN, portfolio)); assertThat(result) @@ -239,4 +276,14 @@ class MigratePortfoliosLiveMeasuresToMeasuresIT { "created_at", 12L, "updated_at", 12L); } + + private void insertMigratedMeasure(String branch, String componentUuid) { + db.executeInsert("measures", + "component_uuid", componentUuid, + "branch_uuid", branch, + "json_value", "{\"any\":\"thing\"}", + "json_value_hash", "1234", + "created_at", 12, + "updated_at", 12); + } } diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/AbstractMigrateLiveMeasuresToMeasures.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/AbstractMigrateLiveMeasuresToMeasures.java index e1cac143632..71d0e173080 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/AbstractMigrateLiveMeasuresToMeasures.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v108/AbstractMigrateLiveMeasuresToMeasures.java @@ -45,6 +45,8 @@ import org.sonar.server.platform.db.migration.step.Upsert; import static java.lang.String.format; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.sonar.server.platform.db.migration.version.v108.CreateIndexOnMeasuresTable.INDEX_NAME; +import static org.sonar.server.platform.db.migration.version.v108.CreateMeasuresTable.MEASURES_TABLE_NAME; public abstract class AbstractMigrateLiveMeasuresToMeasures extends DataChange { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractMigrateLiveMeasuresToMeasures.class); @@ -52,6 +54,11 @@ public abstract class AbstractMigrateLiveMeasuresToMeasures extends DataChange { private static final Set<String> TEXT_VALUE_TYPES = Set.of("STRING", "LEVEL", "DATA", "DISTRIB"); private static final Gson GSON = new Gson(); + private static final String CLEANUP_QUERY = """ + DELETE FROM measures + WHERE branch_uuid = ? + """; + private static final String SELECT_QUERY = """ SELECT lm.component_uuid, m.name, @@ -108,11 +115,14 @@ public abstract class AbstractMigrateLiveMeasuresToMeasures extends DataChange { @Override protected void execute(Context context) throws SQLException { + boolean measuresIndexExists; try (Connection c = getDatabase().getDataSource().getConnection()) { // the table is later deleted, this check ensures the migration re-entrance if (!DatabaseUtils.tableExists("live_measures", c)) { return; } + + measuresIndexExists = DatabaseUtils.indexExistsIgnoreCase(MEASURES_TABLE_NAME, INDEX_NAME, c); } List<String> uuids = context.prepareSelect(getSelectUuidQuery()) @@ -129,7 +139,7 @@ public abstract class AbstractMigrateLiveMeasuresToMeasures extends DataChange { for (String uuid : uuids) { try { - migrateItem(uuid, context, selectQuery); + migrateItem(uuid, context, selectQuery, measuresIndexExists); } catch (Exception e) { LOGGER.error(format("Migration of %s %s failed", item, uuid)); throw e; @@ -152,9 +162,16 @@ public abstract class AbstractMigrateLiveMeasuresToMeasures extends DataChange { }; } - private void migrateItem(String uuid, Context context, String selectQuery) throws SQLException { + private void migrateItem(String uuid, Context context, String selectQuery, boolean measuresIndexExists) throws SQLException { LOGGER.debug("Migrating {} {}...", item, uuid); + if (measuresIndexExists) { + context.prepareUpsert(CLEANUP_QUERY) + .setString(1, uuid) + .execute() + .commit(); + } + Map<String, Object> measureValues = new HashMap<>(); AtomicReference<String> componentUuid = new AtomicReference<>(null); |