From 112170c17981556868bd0aedbbb636d1acdc8588 Mon Sep 17 00:00:00 2001 From: Claire Villard Date: Thu, 3 Oct 2024 11:59:29 +0200 Subject: [PATCH] SONAR-23213 The Measures migration helper is available only on Enterprise and DataCenter editions --- ...AbstractMigrateLiveMeasuresToMeasures.java | 2 +- ...asuresMigratedColumnToPortfoliosTable.java | 2 + ...sMigratedColumnToProjectBranchesTable.java | 2 + ...eateIndexOnPortfoliosMeasuresMigrated.java | 2 + ...ndexOnProjectBranchesMeasuresMigrated.java | 2 + .../migration/adhoc/CreateMeasuresTable.java | 2 + ...MigrateBranchesLiveMeasuresToMeasures.java | 2 + ...gratePortfoliosLiveMeasuresToMeasures.java | 4 +- .../platform/ws/MigrateMeasuresAction.java | 153 ------------ .../platform/ws/PrepareMigrationAction.java | 118 --------- .../server/platform/ws/SystemWsModule.java | 18 -- .../platform/ws/example-migrate_measures.json | 8 - .../ws/example-prepare_migration.json | 3 - .../ws/MigrateMeasuresActionTest.java | 233 ------------------ .../ws/PrepareMigrationActionTest.java | 181 -------------- .../platform/ws/SystemWsModuleTest.java | 2 +- 16 files changed, 17 insertions(+), 717 deletions(-) delete mode 100644 server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/MigrateMeasuresAction.java delete mode 100644 server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/PrepareMigrationAction.java delete mode 100644 server/sonar-webserver-webapi/src/main/resources/org/sonar/server/platform/ws/example-migrate_measures.json delete mode 100644 server/sonar-webserver-webapi/src/main/resources/org/sonar/server/platform/ws/example-prepare_migration.json delete mode 100644 server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/MigrateMeasuresActionTest.java delete mode 100644 server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/PrepareMigrationActionTest.java diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AbstractMigrateLiveMeasuresToMeasures.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AbstractMigrateLiveMeasuresToMeasures.java index 5135d7aa859..bb23c793172 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AbstractMigrateLiveMeasuresToMeasures.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AbstractMigrateLiveMeasuresToMeasures.java @@ -88,7 +88,7 @@ public abstract class AbstractMigrateLiveMeasuresToMeasures extends DataChange { } // This is a special entry point for the case of a configurable migration - public final void migrate(List uuids) throws SQLException { + public void migrate(List uuids) throws SQLException { try (Connection readConnection = createDdlConnection(); Connection writeConnection = createDdlConnection()) { Context context = new Context(db, readConnection, writeConnection); diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToPortfoliosTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToPortfoliosTable.java index 6d45843234f..b626863fc72 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToPortfoliosTable.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToPortfoliosTable.java @@ -19,8 +19,10 @@ */ package org.sonar.server.platform.db.migration.adhoc; +import org.sonar.api.server.ServerSide; import org.sonar.db.Database; +@ServerSide public class AddMeasuresMigratedColumnToPortfoliosTable extends AbstractAddMeasuresMigratedColumnToTable { static final String PORTFOLIOS_TABLE_NAME = "portfolios"; diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToProjectBranchesTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToProjectBranchesTable.java index 6f1475dcea8..53608f41689 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToProjectBranchesTable.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToProjectBranchesTable.java @@ -19,8 +19,10 @@ */ package org.sonar.server.platform.db.migration.adhoc; +import org.sonar.api.server.ServerSide; import org.sonar.db.Database; +@ServerSide public class AddMeasuresMigratedColumnToProjectBranchesTable extends AbstractAddMeasuresMigratedColumnToTable { public static final String PROJECT_BRANCHES_TABLE_NAME = "project_branches"; diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnPortfoliosMeasuresMigrated.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnPortfoliosMeasuresMigrated.java index 414d305dbb2..e8305ce3b7a 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnPortfoliosMeasuresMigrated.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnPortfoliosMeasuresMigrated.java @@ -19,8 +19,10 @@ */ package org.sonar.server.platform.db.migration.adhoc; +import org.sonar.api.server.ServerSide; import org.sonar.db.Database; +@ServerSide public class CreateIndexOnPortfoliosMeasuresMigrated extends AbstractCreateIndexOnMeasuresMigrated { static final String TABLE_NAME = "portfolios"; diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnProjectBranchesMeasuresMigrated.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnProjectBranchesMeasuresMigrated.java index 2a8e0510ee1..b19b1ec82a1 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnProjectBranchesMeasuresMigrated.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnProjectBranchesMeasuresMigrated.java @@ -19,8 +19,10 @@ */ package org.sonar.server.platform.db.migration.adhoc; +import org.sonar.api.server.ServerSide; import org.sonar.db.Database; +@ServerSide public class CreateIndexOnProjectBranchesMeasuresMigrated extends AbstractCreateIndexOnMeasuresMigrated { static final String TABLE_NAME = "project_branches"; diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateMeasuresTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateMeasuresTable.java index d6a0275812b..bf5e4f19017 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateMeasuresTable.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateMeasuresTable.java @@ -20,6 +20,7 @@ package org.sonar.server.platform.db.migration.adhoc; import java.sql.SQLException; +import org.sonar.api.server.ServerSide; import org.sonar.db.Database; import org.sonar.server.platform.db.migration.sql.CreateTableBuilder; import org.sonar.server.platform.db.migration.step.CreateTableChange; @@ -30,6 +31,7 @@ import static org.sonar.server.platform.db.migration.def.ClobColumnDef.newClobCo import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE; import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; +@ServerSide public class CreateMeasuresTable extends CreateTableChange { static final String MEASURES_TABLE_NAME = "measures"; static final String COLUMN_COMPONENT_UUID = "component_uuid"; diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/MigrateBranchesLiveMeasuresToMeasures.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/MigrateBranchesLiveMeasuresToMeasures.java index 3138470dcb2..00bd163e54e 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/MigrateBranchesLiveMeasuresToMeasures.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/MigrateBranchesLiveMeasuresToMeasures.java @@ -19,9 +19,11 @@ */ package org.sonar.server.platform.db.migration.adhoc; +import org.sonar.api.server.ServerSide; import org.sonar.api.utils.System2; import org.sonar.db.Database; +@ServerSide public class MigrateBranchesLiveMeasuresToMeasures extends AbstractMigrateLiveMeasuresToMeasures { public MigrateBranchesLiveMeasuresToMeasures(Database db, System2 system2) { diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/MigratePortfoliosLiveMeasuresToMeasures.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/MigratePortfoliosLiveMeasuresToMeasures.java index 7ce171755f2..e61dba2133e 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/MigratePortfoliosLiveMeasuresToMeasures.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/MigratePortfoliosLiveMeasuresToMeasures.java @@ -19,12 +19,14 @@ */ package org.sonar.server.platform.db.migration.adhoc; +import org.sonar.api.server.ServerSide; import org.sonar.api.utils.System2; import org.sonar.db.Database; +@ServerSide public class MigratePortfoliosLiveMeasuresToMeasures extends AbstractMigrateLiveMeasuresToMeasures { - protected MigratePortfoliosLiveMeasuresToMeasures(Database db, System2 system2) { + public MigratePortfoliosLiveMeasuresToMeasures(Database db, System2 system2) { super(db, system2, "portfolios", "portfolio"); } } diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/MigrateMeasuresAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/MigrateMeasuresAction.java deleted file mode 100644 index fd7d6b35357..00000000000 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/MigrateMeasuresAction.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2024 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.ws; - -import com.google.common.io.Resources; -import java.sql.SQLException; -import java.util.List; -import org.sonar.api.server.ws.Request; -import org.sonar.api.server.ws.Response; -import org.sonar.api.server.ws.WebService; -import org.sonar.api.utils.text.JsonWriter; -import org.sonar.db.DbClient; -import org.sonar.db.DbSession; -import org.sonar.server.platform.db.migration.adhoc.MigrateBranchesLiveMeasuresToMeasures; -import org.sonar.server.platform.db.migration.adhoc.MigratePortfoliosLiveMeasuresToMeasures; -import org.sonar.server.user.UserSession; - -import static java.lang.String.format; -import static java.util.Optional.ofNullable; - -public class MigrateMeasuresAction implements SystemWsAction { - public static final String SYSTEM_MEASURES_MIGRATION_ENABLED = "system.measures.migration.enabled"; - public static final String PARAM_SIZE = "size"; - - private final UserSession userSession; - private final DbClient dbClient; - private final MigrateBranchesLiveMeasuresToMeasures branchesMigration; - private final MigratePortfoliosLiveMeasuresToMeasures portfoliosMigration; - - public MigrateMeasuresAction(UserSession userSession, DbClient dbClient, - MigrateBranchesLiveMeasuresToMeasures branchesMigration, MigratePortfoliosLiveMeasuresToMeasures portfoliosMigration) { - this.userSession = userSession; - this.dbClient = dbClient; - this.branchesMigration = branchesMigration; - this.portfoliosMigration = portfoliosMigration; - } - - @Override - public void define(WebService.NewController controller) { - WebService.NewAction action = controller.createAction("migrate_measures") - .setDescription("Prepare the migration to the next major version of SonarQube." + - "
" + - "Sending a POST request to this URL will migrate some rows from the 'live_measures' to the 'measures' table. " + - "Requires system administration permission.") - .setSince("9.9.8") - .setPost(true) - .setHandler(this) - .setInternal(true) - .setResponseExample(Resources.getResource(this.getClass(), "example-migrate_measures.json")); - - action.createParam(PARAM_SIZE) - .setDescription("The number of branches or portfolios to migrate") - .setDefaultValue(10); - } - - @Override - public void handle(Request request, Response response) throws Exception { - userSession.checkIsSystemAdministrator(); - - if (!isMigrationEnabled()) { - throw new IllegalStateException("Migration is not enabled. Please call the endpoint /api/system/prepare_migration?enable=true and retry."); - } - - int size = request.mandatoryParamAsInt(PARAM_SIZE); - if (size <= 0) { - throw new IllegalArgumentException("Size must be greater than 0"); - } - - int migratedItems = migrateBranches(size); - if (migratedItems < size) { - int remainingSize = size - migratedItems; - migratedItems += migratePortfolios(remainingSize); - } - - BranchStats statistics = getStatistics(); - try (JsonWriter json = response.newJsonWriter()) { - json.beginObject() - .prop("status", "success") - .prop("message", format("%s branches or portfolios migrated", migratedItems)) - .prop("remainingBranches", statistics.remainingBranches) - .prop("totalBranches", statistics.totalBranches) - .prop("remainingPortfolios", statistics.remainingPortfolios) - .prop("totalPortfolios", statistics.totalPortfolios) - .endObject(); - } - } - - private int migrateBranches(int size) throws SQLException { - List branchesToMigrate = getBranchesToMigrate(size); - if (!branchesToMigrate.isEmpty()) { - branchesMigration.migrate(branchesToMigrate); - } - return branchesToMigrate.size(); - } - - private List getBranchesToMigrate(int size) { - try (DbSession dbSession = dbClient.openSession(false)) { - return dbClient.branchDao().selectUuidsWithMeasuresMigratedFalse(dbSession, size); - } - } - - private int migratePortfolios(int size) throws SQLException { - List portfoliosToMigrate = getPortfoliosToMigrate(size); - if (!portfoliosToMigrate.isEmpty()) { - portfoliosMigration.migrate(portfoliosToMigrate); - } - return portfoliosToMigrate.size(); - } - - private List getPortfoliosToMigrate(int size) { - try (DbSession dbSession = dbClient.openSession(false)) { - return dbClient.portfolioDao().selectUuidsWithMeasuresMigratedFalse(dbSession, size); - } - } - - private boolean isMigrationEnabled() { - return ofNullable(dbClient.propertiesDao().selectGlobalProperty(SYSTEM_MEASURES_MIGRATION_ENABLED)) - .map(p -> Boolean.parseBoolean(p.getValue())) - .orElse(false); - } - - private BranchStats getStatistics() { - try (DbSession dbSession = dbClient.openSession(false)) { - int remainingBranches = dbClient.branchDao().countByMeasuresMigratedFalse(dbSession); - int totalBranches = dbClient.branchDao().countAll(dbSession); - int remainingPortfolios = dbClient.portfolioDao().countByMeasuresMigratedFalse(dbSession); - int totalPortfolios = dbClient.portfolioDao().selectAll(dbSession).size(); - - return new BranchStats(remainingBranches, totalBranches, remainingPortfolios, totalPortfolios); - } - } - - private record BranchStats(int remainingBranches, int totalBranches, int remainingPortfolios, int totalPortfolios) { - } - -} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/PrepareMigrationAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/PrepareMigrationAction.java deleted file mode 100644 index bfb5ccda0a2..00000000000 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/PrepareMigrationAction.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2024 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.ws; - -import com.google.common.io.Resources; -import java.sql.SQLException; -import org.sonar.api.server.ws.Request; -import org.sonar.api.server.ws.Response; -import org.sonar.api.server.ws.WebService; -import org.sonar.api.server.ws.WebService.NewAction; -import org.sonar.api.utils.text.JsonWriter; -import org.sonar.db.DbClient; -import org.sonar.db.property.PropertyDto; -import org.sonar.server.platform.db.migration.adhoc.AddMeasuresMigratedColumnToPortfoliosTable; -import org.sonar.server.platform.db.migration.adhoc.AddMeasuresMigratedColumnToProjectBranchesTable; -import org.sonar.server.platform.db.migration.adhoc.CreateIndexOnPortfoliosMeasuresMigrated; -import org.sonar.server.platform.db.migration.adhoc.CreateIndexOnProjectBranchesMeasuresMigrated; -import org.sonar.server.platform.db.migration.adhoc.CreateMeasuresTable; -import org.sonar.server.user.UserSession; - -import static java.lang.String.format; -import static org.sonar.core.config.CorePropertyDefinitions.SYSTEM_MEASURES_MIGRATION_ENABLED; - -/** - * Implementation of the {@code prepare_migration} action for the System WebService. - */ -public class PrepareMigrationAction implements SystemWsAction { - - public static final String PARAM_ENABLE = "enable"; - private final UserSession userSession; - private final DbClient dbClient; - private final CreateMeasuresTable createMeasuresTable; - private final AddMeasuresMigratedColumnToProjectBranchesTable addMeasuresMigratedColumnToProjectBranchesTable; - private final AddMeasuresMigratedColumnToPortfoliosTable addMeasuresMigratedColumnToPortfoliosTable; - private final CreateIndexOnProjectBranchesMeasuresMigrated createIndexOnProjectBranchesMeasuresMigrated; - private final CreateIndexOnPortfoliosMeasuresMigrated createIndexOnPortfoliosMeasuresMigrated; - - public PrepareMigrationAction(UserSession userSession, DbClient dbClient, CreateMeasuresTable createMeasuresTable, - AddMeasuresMigratedColumnToProjectBranchesTable addMeasuresMigratedColumnToProjectBranchesTable, - AddMeasuresMigratedColumnToPortfoliosTable addMeasuresMigratedColumnToPortfoliosTable, - CreateIndexOnProjectBranchesMeasuresMigrated createIndexOnProjectBranchesMeasuresMigrated, - CreateIndexOnPortfoliosMeasuresMigrated createIndexOnPortfoliosMeasuresMigrated) { - this.userSession = userSession; - this.dbClient = dbClient; - this.createMeasuresTable = createMeasuresTable; - this.addMeasuresMigratedColumnToProjectBranchesTable = addMeasuresMigratedColumnToProjectBranchesTable; - this.addMeasuresMigratedColumnToPortfoliosTable = addMeasuresMigratedColumnToPortfoliosTable; - this.createIndexOnProjectBranchesMeasuresMigrated = createIndexOnProjectBranchesMeasuresMigrated; - this.createIndexOnPortfoliosMeasuresMigrated = createIndexOnPortfoliosMeasuresMigrated; - } - - @Override - public void define(WebService.NewController controller) { - NewAction action = controller.createAction("prepare_migration") - .setDescription("Prepare the migration to the next major version of SonarQube." + - "
" + - "Sending a POST request to this URL enables the 'live_measures' table migration. " + - "It is strongly advised to make a database backup before invoking this WS. " + - "Requires system administration permission.") - .setSince("9.9.8") - .setPost(true) - .setHandler(this) - .setInternal(true) - .setResponseExample(Resources.getResource(this.getClass(), "example-prepare_migration.json")); - - action.createParam(PARAM_ENABLE) - .setDescription("Set to true to enable the migration mode. Set to false to disable.") - .setBooleanPossibleValues() - .setRequired(true); - } - - @Override - public void handle(Request request, Response response) throws Exception { - userSession.checkIsSystemAdministrator(); - - boolean enable = request.mandatoryParamAsBoolean(PARAM_ENABLE); - if (enable) { - updateDdl(); - } - updateProperty(enable); - - try (JsonWriter json = response.newJsonWriter()) { - json.beginObject() - .prop("message", format("The 'live_measures' migration mode is %s", enable ? "enabled" : "disabled")) - .endObject(); - } - } - - private void updateDdl() throws SQLException { - createMeasuresTable.execute(); - addMeasuresMigratedColumnToProjectBranchesTable.execute(); - addMeasuresMigratedColumnToPortfoliosTable.execute(); - createIndexOnProjectBranchesMeasuresMigrated.execute(); - createIndexOnPortfoliosMeasuresMigrated.execute(); - } - - private void updateProperty(boolean enable) { - dbClient.propertiesDao().saveProperty(new PropertyDto().setKey(SYSTEM_MEASURES_MIGRATION_ENABLED).setValue(Boolean.toString(enable))); - } - -} diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/SystemWsModule.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/SystemWsModule.java index 41c21b03174..e18d8946b6b 100644 --- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/SystemWsModule.java +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/SystemWsModule.java @@ -20,13 +20,6 @@ package org.sonar.server.platform.ws; import org.sonar.core.platform.Module; -import org.sonar.server.platform.db.migration.adhoc.AddMeasuresMigratedColumnToPortfoliosTable; -import org.sonar.server.platform.db.migration.adhoc.AddMeasuresMigratedColumnToProjectBranchesTable; -import org.sonar.server.platform.db.migration.adhoc.CreateIndexOnPortfoliosMeasuresMigrated; -import org.sonar.server.platform.db.migration.adhoc.CreateIndexOnProjectBranchesMeasuresMigrated; -import org.sonar.server.platform.db.migration.adhoc.CreateMeasuresTable; -import org.sonar.server.platform.db.migration.adhoc.MigrateBranchesLiveMeasuresToMeasures; -import org.sonar.server.platform.db.migration.adhoc.MigratePortfoliosLiveMeasuresToMeasures; public class SystemWsModule extends Module { @@ -42,17 +35,6 @@ public class SystemWsModule extends Module { LivenessActionSupport.class, LivenessAction.class, - CreateMeasuresTable.class, - AddMeasuresMigratedColumnToProjectBranchesTable.class, - AddMeasuresMigratedColumnToPortfoliosTable.class, - CreateIndexOnProjectBranchesMeasuresMigrated.class, - CreateIndexOnPortfoliosMeasuresMigrated.class, - PrepareMigrationAction.class, - - MigrateBranchesLiveMeasuresToMeasures.class, - MigratePortfoliosLiveMeasuresToMeasures.class, - MigrateMeasuresAction.class, - InfoAction.class, LogsAction.class, MigrateDbAction.class, diff --git a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/platform/ws/example-migrate_measures.json b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/platform/ws/example-migrate_measures.json deleted file mode 100644 index 60fb3154d7a..00000000000 --- a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/platform/ws/example-migrate_measures.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "status": "success", - "message": "2 branches or portfolios migrated", - "remainingBranches": 1, - "totalBranches": 3, - "remainingPortfolios": 1, - "totalPortfolios": 2 -} diff --git a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/platform/ws/example-prepare_migration.json b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/platform/ws/example-prepare_migration.json deleted file mode 100644 index 902e4c6e249..00000000000 --- a/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/platform/ws/example-prepare_migration.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "message": "The 'live_measures' migration mode is enabled" -} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/MigrateMeasuresActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/MigrateMeasuresActionTest.java deleted file mode 100644 index a4b92076fca..00000000000 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/MigrateMeasuresActionTest.java +++ /dev/null @@ -1,233 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2024 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.ws; - -import com.google.gson.Gson; -import com.tngtech.java.junit.dataprovider.DataProvider; -import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import java.sql.SQLException; -import java.util.List; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.sonar.db.Database; -import org.sonar.db.DbTester; -import org.sonar.db.component.BranchType; -import org.sonar.db.component.ComponentDto; -import org.sonar.db.portfolio.PortfolioDto; -import org.sonar.db.property.PropertyDto; -import org.sonar.server.exceptions.ForbiddenException; -import org.sonar.server.platform.db.migration.adhoc.AddMeasuresMigratedColumnToPortfoliosTable; -import org.sonar.server.platform.db.migration.adhoc.AddMeasuresMigratedColumnToProjectBranchesTable; -import org.sonar.server.platform.db.migration.adhoc.MigrateBranchesLiveMeasuresToMeasures; -import org.sonar.server.platform.db.migration.adhoc.MigratePortfoliosLiveMeasuresToMeasures; -import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.ws.TestRequest; -import org.sonar.server.ws.TestResponse; -import org.sonar.server.ws.WsActionTester; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.assertj.core.api.Assertions.assertThatIllegalStateException; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; -import static org.sonar.db.component.BranchType.BRANCH; -import static org.sonar.server.platform.ws.MigrateMeasuresAction.SYSTEM_MEASURES_MIGRATION_ENABLED; -import static org.sonar.test.JsonAssert.assertJson; - -@RunWith(DataProviderRunner.class) -public class MigrateMeasuresActionTest { - private static final Gson GSON = new Gson(); - - public static final String PARAM_SIZE = "size"; - @Rule - public UserSessionRule userSessionRule = UserSessionRule.standalone().logIn().setSystemAdministrator(); - - @Rule - public DbTester dbTester = DbTester.create(); - - private final MigrateBranchesLiveMeasuresToMeasures measuresMigration = mock(); - private final MigratePortfoliosLiveMeasuresToMeasures portfoliosMigration = mock(); - private final MigrateMeasuresAction underTest = new MigrateMeasuresAction(userSessionRule, dbTester.getDbClient(), measuresMigration, portfoliosMigration); - private final WsActionTester tester = new WsActionTester(underTest); - - @Test - public void should_throw_if_migration_is_not_enabled() { - TestRequest request = tester.newRequest(); - - assertThatIllegalStateException() - .isThrownBy(request::execute) - .withMessage("Migration is not enabled. Please call the endpoint /api/system/prepare_migration?enable=true and retry."); - } - - @Test - @DataProvider(value = {"0", "-1", "-100"}) - public void should_throws_IAE_if_size_in_invalid(int size) throws SQLException { - enableMigration(); - - TestRequest request = tester - .newRequest() - .setParam(PARAM_SIZE, Integer.toString(size)); - - assertThatIllegalArgumentException() - .isThrownBy(request::execute) - .withMessage("Size must be greater than 0"); - } - - @Test - public void verify_example() throws SQLException { - enableMigration(); - // 3 branches, 2 migrated - ComponentDto project = dbTester.components().insertPrivateProject(); - ComponentDto branch1 = dbTester.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH)); - dbTester.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH)); - dbTester.getDbClient().branchDao().updateMeasuresMigrated(dbTester.getSession(), project.branchUuid(), true); - dbTester.getDbClient().branchDao().updateMeasuresMigrated(dbTester.getSession(), branch1.branchUuid(), true); - // 2 portfolios, 1 migrated - PortfolioDto portfolio1 = dbTester.components().insertPrivatePortfolioDto("name1"); - dbTester.components().insertPrivatePortfolioDto("name2"); - dbTester.getDbClient().portfolioDao().updateMeasuresMigrated(dbTester.getSession(), portfolio1.getUuid(), true); - dbTester.getSession().commit(); - - TestResponse response = tester.newRequest() - .execute(); - - assertJson(response.getInput()).isSimilarTo(getClass().getResource("example-migrate_measures.json")); - } - - @Test - public void does_not_migrate_portfolios_if_measures_are_not_finished() throws SQLException { - enableMigration(); - // 2 branches - ComponentDto project = dbTester.components().insertPrivateProject(); - ComponentDto branch = dbTester.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH)); - dbTester.components().insertProjectBranch(project, b -> b.setBranchType(BranchType.BRANCH)); - - TestResponse response = tester.newRequest() - .setParam(PARAM_SIZE, "2") - .execute(); - - assertThat(GSON.fromJson(response.getInput(), ActionResponse.class)) - .isEqualTo(new ActionResponse("success", "2 branches or portfolios migrated", 3, 3, 0, 0)); - verify(measuresMigration).migrate(List.of(project.uuid(), branch.uuid())); - verifyNoInteractions(portfoliosMigration); - } - - @Test - public void migrate_portfolios_to_reach_the_requested_size() throws SQLException { - enableMigration(); - - // 1 branch - ComponentDto project = dbTester.components().insertPrivateProject(); - // 2 portfolios - PortfolioDto portfolio1 = dbTester.components().insertPrivatePortfolioDto("name1"); - dbTester.components().insertPrivatePortfolioDto("name2"); - - TestResponse response = tester.newRequest() - .setParam(PARAM_SIZE, "2") - .execute(); - - assertThat(GSON.fromJson(response.getInput(), ActionResponse.class)) - .isEqualTo(new ActionResponse("success", "2 branches or portfolios migrated", 1, 1, 2, 2)); - verify(measuresMigration).migrate(List.of(project.uuid())); - verify(portfoliosMigration).migrate(List.of(portfolio1.getUuid())); - } - - @Test - public void migrate_portfolios_only_if_measures_are_done() throws SQLException { - enableMigration(); - // 2 branches, all migrated - ComponentDto project = dbTester.components().insertPrivateProject(); - ComponentDto branch1 = dbTester.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH)); - dbTester.getDbClient().branchDao().updateMeasuresMigrated(dbTester.getSession(), project.branchUuid(), true); - dbTester.getDbClient().branchDao().updateMeasuresMigrated(dbTester.getSession(), branch1.branchUuid(), true); - // 2 portfolios, 1 migrated - PortfolioDto portfolio1 = dbTester.components().insertPrivatePortfolioDto("name1"); - PortfolioDto portfolio2 = dbTester.components().insertPrivatePortfolioDto("name2"); - dbTester.getDbClient().portfolioDao().updateMeasuresMigrated(dbTester.getSession(), portfolio1.getUuid(), true); - dbTester.commit(); - - TestResponse response = tester.newRequest() - .setParam(PARAM_SIZE, "2") - .execute(); - - assertThat(GSON.fromJson(response.getInput(), ActionResponse.class)) - .isEqualTo(new ActionResponse("success", "1 branches or portfolios migrated", 0, 2, 1, 2)); - verifyNoInteractions(measuresMigration); - verify(portfoliosMigration).migrate(List.of(portfolio2.getUuid())); - } - - @Test - public void does_nothing_if_migration_is_finished() throws SQLException { - enableMigration(); - // 2 branches, all migrated - ComponentDto project = dbTester.components().insertPrivateProject(); - ComponentDto branch1 = dbTester.components().insertProjectBranch(project, b -> b.setBranchType(BRANCH)); - dbTester.getDbClient().branchDao().updateMeasuresMigrated(dbTester.getSession(), project.branchUuid(), true); - dbTester.getDbClient().branchDao().updateMeasuresMigrated(dbTester.getSession(), branch1.branchUuid(), true); - // 2 portfolios, all migrated - PortfolioDto portfolio1 = dbTester.components().insertPrivatePortfolioDto("name1"); - PortfolioDto portfolio2 = dbTester.components().insertPrivatePortfolioDto("name2"); - dbTester.getDbClient().portfolioDao().updateMeasuresMigrated(dbTester.getSession(), portfolio1.getUuid(), true); - dbTester.getDbClient().portfolioDao().updateMeasuresMigrated(dbTester.getSession(), portfolio2.getUuid(), true); - dbTester.commit(); - - TestResponse response = tester.newRequest() - .setParam(PARAM_SIZE, "2") - .execute(); - - assertThat(GSON.fromJson(response.getInput(), ActionResponse.class)) - .isEqualTo(new ActionResponse("success", "0 branches or portfolios migrated", 0, 2, 0, 2)); - verifyNoInteractions(measuresMigration, portfoliosMigration); - } - - private void enableMigration() throws SQLException { - Database database = dbTester.getDbClient().getDatabase(); - new AddMeasuresMigratedColumnToProjectBranchesTable(database).execute(); - new AddMeasuresMigratedColumnToPortfoliosTable(database).execute(); - dbTester.getDbClient().propertiesDao().saveProperty(new PropertyDto().setKey(SYSTEM_MEASURES_MIGRATION_ENABLED).setValue("true")); - } - - @Test - public void throws_ForbiddenException_if_user_is_not_logged_in() { - userSessionRule.anonymous(); - - TestRequest request = tester.newRequest(); - - assertThatExceptionOfType(ForbiddenException.class) - .isThrownBy(request::execute); - } - - @Test - public void throws_ForbiddenException_if_user_is_not_system_admin() { - userSessionRule.logIn(); - - TestRequest request = tester.newRequest(); - - assertThatExceptionOfType(ForbiddenException.class) - .isThrownBy(request::execute); - } - - private record ActionResponse(String status, String message, int remainingBranches, int totalBranches, int remainingPortfolios, - int totalPortfolios) { - } -} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/PrepareMigrationActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/PrepareMigrationActionTest.java deleted file mode 100644 index 11bc6c69226..00000000000 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/PrepareMigrationActionTest.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2024 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.ws; - -import com.tngtech.java.junit.dataprovider.DataProvider; -import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import java.sql.SQLException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.sonar.db.DbTester; -import org.sonar.db.property.PropertyDto; -import org.sonar.server.exceptions.ForbiddenException; -import org.sonar.server.platform.db.migration.adhoc.AddMeasuresMigratedColumnToPortfoliosTable; -import org.sonar.server.platform.db.migration.adhoc.AddMeasuresMigratedColumnToProjectBranchesTable; -import org.sonar.server.platform.db.migration.adhoc.CreateIndexOnPortfoliosMeasuresMigrated; -import org.sonar.server.platform.db.migration.adhoc.CreateIndexOnProjectBranchesMeasuresMigrated; -import org.sonar.server.platform.db.migration.adhoc.CreateMeasuresTable; -import org.sonar.server.tester.UserSessionRule; -import org.sonar.server.ws.TestRequest; -import org.sonar.server.ws.TestResponse; -import org.sonar.server.ws.WsActionTester; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoInteractions; -import static org.sonar.core.config.CorePropertyDefinitions.SYSTEM_MEASURES_MIGRATION_ENABLED; -import static org.sonar.test.JsonAssert.assertJson; - -@RunWith(DataProviderRunner.class) -public class PrepareMigrationActionTest { - - public static final String PARAM_ENABLE = "enable"; - @Rule - public UserSessionRule userSessionRule = UserSessionRule.standalone().logIn().setSystemAdministrator(); - - @Rule - public DbTester dbTester = DbTester.create(); - - private final CreateMeasuresTable createMeasuresTable = mock(); - private final AddMeasuresMigratedColumnToProjectBranchesTable addMeasuresMigratedColumnToProjectBranchesTable = mock(); - private final AddMeasuresMigratedColumnToPortfoliosTable addMeasuresMigratedColumnToPortfoliosTable = mock(); - private final CreateIndexOnProjectBranchesMeasuresMigrated createIndexOnProjectBranchesMeasuresMigrated = mock(); - private final CreateIndexOnPortfoliosMeasuresMigrated createIndexOnPortfoliosMeasuresMigrated = mock(); - - private final PrepareMigrationAction underTest = new PrepareMigrationAction(userSessionRule, dbTester.getDbClient(), createMeasuresTable, - addMeasuresMigratedColumnToProjectBranchesTable, addMeasuresMigratedColumnToPortfoliosTable, createIndexOnProjectBranchesMeasuresMigrated, createIndexOnPortfoliosMeasuresMigrated); - private final WsActionTester tester = new WsActionTester(underTest); - - @Test - public void should_throw_if_enable_parameter_is_missing() { - TestRequest request = tester.newRequest(); - - assertThatIllegalArgumentException() - .isThrownBy(request::execute) - .withMessage("The 'enable' parameter is missing"); - } - - @Test - public void verify_example() { - TestResponse response = tester.newRequest() - .setParam(PARAM_ENABLE, "true") - .execute(); - - assertJson(response.getInput()).isSimilarTo(getClass().getResource("example-prepare_migration.json")); - } - - @Test - public void throws_ForbiddenException_if_user_is_not_logged_in() { - userSessionRule.anonymous(); - - TestRequest request = tester.newRequest(); - - assertThatExceptionOfType(ForbiddenException.class) - .isThrownBy(request::execute); - } - - @Test - public void throws_ForbiddenException_if_user_is_not_system_admin() { - userSessionRule.logIn(); - - TestRequest request = tester.newRequest(); - - assertThatExceptionOfType(ForbiddenException.class) - .isThrownBy(request::execute); - } - - @Test - @DataProvider(value = {"true", "yes"}) - public void should_enable_migration(String enableParamValue) throws SQLException { - assertThat(getPropertyValue()).isNull(); - - TestResponse response = tester.newRequest() - .setParam(PARAM_ENABLE, enableParamValue) - .execute(); - - assertThat(response.getStatus()).isEqualTo(200); - assertThat(getPropertyValue()).isTrue(); - - verify(createMeasuresTable).execute(); - verify(addMeasuresMigratedColumnToProjectBranchesTable).execute(); - verify(addMeasuresMigratedColumnToPortfoliosTable).execute(); - verify(createIndexOnProjectBranchesMeasuresMigrated).execute(); - verify(createIndexOnPortfoliosMeasuresMigrated).execute(); - - // reentrant - response = tester.newRequest() - .setParam(PARAM_ENABLE, enableParamValue) - .execute(); - - assertThat(response.getStatus()).isEqualTo(200); - assertThat(getPropertyValue()).isTrue(); - } - - @Test - public void property_is_unchanged_if_the_migrations_failed() throws SQLException { - doThrow(new SQLException("Oops")).when(createMeasuresTable).execute(); - - TestRequest request = tester.newRequest() - .setParam(PARAM_ENABLE, "true"); - - assertThatExceptionOfType(RuntimeException.class) - .isThrownBy(request::execute); - - assertThat(getPropertyValue()).isNull(); - } - - @Test - @DataProvider(value = {"false", "no"}) - public void should_disable_migration(String disableParamValue) { - dbTester.getDbClient().propertiesDao().saveProperty(new PropertyDto().setKey(SYSTEM_MEASURES_MIGRATION_ENABLED).setValue("true")); - - TestResponse response = tester.newRequest() - .setParam(PARAM_ENABLE, disableParamValue) - .execute(); - - assertThat(response.getStatus()).isEqualTo(200); - assertThat(getPropertyValue()).isFalse(); - - verifyNoInteractions(createMeasuresTable, addMeasuresMigratedColumnToPortfoliosTable, addMeasuresMigratedColumnToProjectBranchesTable, - createIndexOnProjectBranchesMeasuresMigrated, createIndexOnPortfoliosMeasuresMigrated); - - // reentrant - response = tester.newRequest() - .setParam(PARAM_ENABLE, disableParamValue) - .execute(); - - assertThat(response.getStatus()).isEqualTo(200); - assertThat(getPropertyValue()).isFalse(); - } - - private Boolean getPropertyValue() { - PropertyDto propertyDto = dbTester.getDbClient().propertiesDao().selectGlobalProperty(SYSTEM_MEASURES_MIGRATION_ENABLED); - if (propertyDto == null) { - return null; - } - return Boolean.parseBoolean(propertyDto.getValue()); - } - -} diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/SystemWsModuleTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/SystemWsModuleTest.java index 8c7a40815c2..0a75383e46d 100644 --- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/SystemWsModuleTest.java +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/SystemWsModuleTest.java @@ -29,6 +29,6 @@ public class SystemWsModuleTest { public void verify_count_of_added_components() { ListContainer container = new ListContainer(); new SystemWsModule().configure(container); - assertThat(container.getAddedObjects()).hasSize(24); + assertThat(container.getAddedObjects()).hasSize(15); } } -- 2.39.5