diff options
author | Claire Villard <claire.villard@sonarsource.com> | 2024-09-30 15:10:25 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-10-14 20:03:02 +0000 |
commit | fdeb15ab72feed39f26ea32d2c60ffd7a1f3d8e1 (patch) | |
tree | bb60183715de789acf992d6158d39dc386e57f61 | |
parent | 27cc982706dedb1ded383f5974f985feeffe5f47 (diff) | |
download | sonarqube-fdeb15ab72feed39f26ea32d2c60ffd7a1f3d8e1.tar.gz sonarqube-fdeb15ab72feed39f26ea32d2c60ffd7a1f3d8e1.zip |
SONAR-23213 'api/system/prepare_migration' endpoint
23 files changed, 973 insertions, 1 deletions
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AbstractAddMeasuresMigratedColumnToTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AbstractAddMeasuresMigratedColumnToTable.java new file mode 100644 index 00000000000..957b06c5f0f --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AbstractAddMeasuresMigratedColumnToTable.java @@ -0,0 +1,56 @@ +/* + * 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.db.migration.adhoc; + +import java.sql.Connection; +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.db.DatabaseUtils; +import org.sonar.server.platform.db.migration.def.BooleanColumnDef; +import org.sonar.server.platform.db.migration.def.ColumnDef; +import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder; +import org.sonar.server.platform.db.migration.step.DdlChange; + +public class AbstractAddMeasuresMigratedColumnToTable extends DdlChange { + + public static final String MIGRATION_FLAG_COLUMN_NAME = "measures_migrated"; + private final String tableName; + + public AbstractAddMeasuresMigratedColumnToTable(Database db, String tableName) { + super(db); + this.tableName = tableName; + } + + @Override + public void execute(Context context) throws SQLException { + try (Connection connection = getDatabase().getDataSource().getConnection()) { + if (!DatabaseUtils.tableColumnExists(connection, tableName, MIGRATION_FLAG_COLUMN_NAME)) { + ColumnDef columnDef = BooleanColumnDef.newBooleanColumnDefBuilder() + .setColumnName(MIGRATION_FLAG_COLUMN_NAME) + .setIsNullable(false) + .setDefaultValue(false) + .build(); + context.execute(new AddColumnsBuilder(getDialect(), tableName) + .addColumn(columnDef) + .build()); + } + } + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AbstractCreateIndexOnMeasuresMigrated.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AbstractCreateIndexOnMeasuresMigrated.java new file mode 100644 index 00000000000..8a1f982c628 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AbstractCreateIndexOnMeasuresMigrated.java @@ -0,0 +1,53 @@ +/* + * 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.db.migration.adhoc; + +import java.sql.Connection; +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.db.DatabaseUtils; +import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder; +import org.sonar.server.platform.db.migration.step.DdlChange; + +public class AbstractCreateIndexOnMeasuresMigrated extends DdlChange { + + static final String COLUMN_NAME = "measures_migrated"; + private final String tableName; + private final String indexName; + + public AbstractCreateIndexOnMeasuresMigrated(Database db, String tableName, String indexName) { + super(db); + this.tableName = tableName; + this.indexName = indexName; + } + + @Override + public void execute(Context context) throws SQLException { + try (Connection connection = getDatabase().getDataSource().getConnection()) { + if (!DatabaseUtils.indexExistsIgnoreCase(tableName, indexName, connection)) { + context.execute(new CreateIndexBuilder() + .setTable(tableName) + .setName(indexName) + .addColumn(COLUMN_NAME) + .build()); + } + } + } +} 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 new file mode 100644 index 00000000000..6d45843234f --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToPortfoliosTable.java @@ -0,0 +1,31 @@ +/* + * 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.db.migration.adhoc; + +import org.sonar.db.Database; + +public class AddMeasuresMigratedColumnToPortfoliosTable extends AbstractAddMeasuresMigratedColumnToTable { + + static final String PORTFOLIOS_TABLE_NAME = "portfolios"; + + public AddMeasuresMigratedColumnToPortfoliosTable(Database db) { + super(db, PORTFOLIOS_TABLE_NAME); + } +} 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 new file mode 100644 index 00000000000..6f1475dcea8 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToProjectBranchesTable.java @@ -0,0 +1,31 @@ +/* + * 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.db.migration.adhoc; + +import org.sonar.db.Database; + +public class AddMeasuresMigratedColumnToProjectBranchesTable extends AbstractAddMeasuresMigratedColumnToTable { + + public static final String PROJECT_BRANCHES_TABLE_NAME = "project_branches"; + + public AddMeasuresMigratedColumnToProjectBranchesTable(Database db) { + super(db, PROJECT_BRANCHES_TABLE_NAME); + } +} 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 new file mode 100644 index 00000000000..414d305dbb2 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnPortfoliosMeasuresMigrated.java @@ -0,0 +1,32 @@ +/* + * 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.db.migration.adhoc; + +import org.sonar.db.Database; + +public class CreateIndexOnPortfoliosMeasuresMigrated extends AbstractCreateIndexOnMeasuresMigrated { + + static final String TABLE_NAME = "portfolios"; + static final String INDEX_NAME = "portfolios_measures_migrated"; + + public CreateIndexOnPortfoliosMeasuresMigrated(Database db) { + super(db, TABLE_NAME, INDEX_NAME); + } +} 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 new file mode 100644 index 00000000000..2a8e0510ee1 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnProjectBranchesMeasuresMigrated.java @@ -0,0 +1,32 @@ +/* + * 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.db.migration.adhoc; + +import org.sonar.db.Database; + +public class CreateIndexOnProjectBranchesMeasuresMigrated extends AbstractCreateIndexOnMeasuresMigrated { + + static final String TABLE_NAME = "project_branches"; + static final String INDEX_NAME = "pb_measures_migrated"; + + public CreateIndexOnProjectBranchesMeasuresMigrated(Database db) { + super(db, TABLE_NAME, INDEX_NAME); + } +} 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 new file mode 100644 index 00000000000..d6a0275812b --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/CreateMeasuresTable.java @@ -0,0 +1,57 @@ +/* + * 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.db.migration.adhoc; + +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.sql.CreateTableBuilder; +import org.sonar.server.platform.db.migration.step.CreateTableChange; +import org.sonar.server.platform.db.migration.step.DdlChange; + +import static org.sonar.server.platform.db.migration.def.BigIntegerColumnDef.newBigIntegerColumnDefBuilder; +import static org.sonar.server.platform.db.migration.def.ClobColumnDef.newClobColumnDefBuilder; +import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE; +import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; + +public class CreateMeasuresTable extends CreateTableChange { + static final String MEASURES_TABLE_NAME = "measures"; + static final String COLUMN_COMPONENT_UUID = "component_uuid"; + static final String COLUMN_BRANCH_UUID = "branch_uuid"; + static final String COLUMN_JSON_VALUE = "json_value"; + static final String COLUMN_JSON_VALUE_HASH = "json_value_hash"; + static final String COLUMN_CREATED_AT = "created_at"; + static final String COLUMN_UPDATED_AT = "updated_at"; + + public CreateMeasuresTable(Database db) { + super(db, MEASURES_TABLE_NAME); + } + + @Override + public void execute(DdlChange.Context context, String tableName) throws SQLException { + context.execute(new CreateTableBuilder(getDialect(), tableName) + .addColumn(newVarcharColumnDefBuilder().setColumnName(COLUMN_COMPONENT_UUID).setIsNullable(false).setLimit(UUID_SIZE).build()) + .addColumn(newVarcharColumnDefBuilder().setColumnName(COLUMN_BRANCH_UUID).setIsNullable(false).setLimit(UUID_SIZE).build()) + .addColumn(newClobColumnDefBuilder().setColumnName(COLUMN_JSON_VALUE).setIsNullable(false).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName(COLUMN_JSON_VALUE_HASH).setIsNullable(false).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName(COLUMN_CREATED_AT).setIsNullable(false).build()) + .addColumn(newBigIntegerColumnDefBuilder().setColumnName(COLUMN_UPDATED_AT).setIsNullable(false).build()) + .build()); + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/README.md b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/README.md new file mode 100644 index 00000000000..121149109d7 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/README.md @@ -0,0 +1,2 @@ +Those migrations are not meant to be executed during automatic or manual migrations. +They are meant to be executed on a specific action during the normal runtime of the server, for example on a call of some API endpoint. diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/package-info.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/package-info.java new file mode 100644 index 00000000000..03588050672 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/adhoc/package-info.java @@ -0,0 +1,23 @@ +/* + * 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. + */ +@ParametersAreNonnullByDefault +package org.sonar.server.platform.db.migration.adhoc; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToPortfoliosTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToPortfoliosTableTest.java new file mode 100644 index 00000000000..e845654376a --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToPortfoliosTableTest.java @@ -0,0 +1,50 @@ +/* + * 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.db.migration.adhoc; + +import java.sql.SQLException; +import java.sql.Types; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.db.CoreDbTester; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; +import static org.sonar.server.platform.db.migration.adhoc.AddMeasuresMigratedColumnToPortfoliosTable.MIGRATION_FLAG_COLUMN_NAME; +import static org.sonar.server.platform.db.migration.adhoc.AddMeasuresMigratedColumnToPortfoliosTable.PORTFOLIOS_TABLE_NAME; + +public class AddMeasuresMigratedColumnToPortfoliosTableTest { + + @Rule + public final CoreDbTester db = CoreDbTester.createForSchema(AddMeasuresMigratedColumnToPortfoliosTableTest.class, "schema.sql"); + private final AddMeasuresMigratedColumnToPortfoliosTable underTest = new AddMeasuresMigratedColumnToPortfoliosTable(db.database()); + + @Test + public void execute_whenColumnDoesNotExist_shouldCreateColumn() throws SQLException { + db.assertColumnDoesNotExist(PORTFOLIOS_TABLE_NAME, MIGRATION_FLAG_COLUMN_NAME); + underTest.execute(); + db.assertColumnDefinition(PORTFOLIOS_TABLE_NAME, MIGRATION_FLAG_COLUMN_NAME, Types.BOOLEAN, null, false); + } + + @Test + public void execute_whenColumnAlreadyExists_shouldNotFail() throws SQLException { + underTest.execute(); + assertThatCode(underTest::execute).doesNotThrowAnyException(); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToProjectBranchesTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToProjectBranchesTableTest.java new file mode 100644 index 00000000000..4aa369b84b8 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToProjectBranchesTableTest.java @@ -0,0 +1,50 @@ +/* + * 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.db.migration.adhoc; + +import java.sql.SQLException; +import java.sql.Types; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.db.CoreDbTester; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; +import static org.sonar.server.platform.db.migration.adhoc.AddMeasuresMigratedColumnToProjectBranchesTable.MIGRATION_FLAG_COLUMN_NAME; +import static org.sonar.server.platform.db.migration.adhoc.AddMeasuresMigratedColumnToProjectBranchesTable.PROJECT_BRANCHES_TABLE_NAME; + +public class AddMeasuresMigratedColumnToProjectBranchesTableTest { + + @Rule + public final CoreDbTester db = CoreDbTester.createForSchema(AddMeasuresMigratedColumnToProjectBranchesTableTest.class, "schema.sql"); + private final AddMeasuresMigratedColumnToProjectBranchesTable underTest = new AddMeasuresMigratedColumnToProjectBranchesTable(db.database()); + + @Test + public void execute_whenColumnDoesNotExist_shouldCreateColumn() throws SQLException { + db.assertColumnDoesNotExist(PROJECT_BRANCHES_TABLE_NAME, MIGRATION_FLAG_COLUMN_NAME); + underTest.execute(); + db.assertColumnDefinition(PROJECT_BRANCHES_TABLE_NAME, MIGRATION_FLAG_COLUMN_NAME, Types.BOOLEAN, null, false); + } + + @Test + public void execute_whenColumnAlreadyExists_shouldNotFail() throws SQLException { + underTest.execute(); + assertThatCode(underTest::execute).doesNotThrowAnyException(); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnPortfoliosMeasuresMigratedTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnPortfoliosMeasuresMigratedTest.java new file mode 100644 index 00000000000..ec6cec59bf1 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnPortfoliosMeasuresMigratedTest.java @@ -0,0 +1,53 @@ +/* + * 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.db.migration.adhoc; + +import java.sql.SQLException; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.db.CoreDbTester; + +import static org.sonar.server.platform.db.migration.adhoc.CreateIndexOnPortfoliosMeasuresMigrated.COLUMN_NAME; +import static org.sonar.server.platform.db.migration.adhoc.CreateIndexOnPortfoliosMeasuresMigrated.TABLE_NAME; + +public class CreateIndexOnPortfoliosMeasuresMigratedTest { + + private static final String INDEX_NAME = "portfolios_measures_migrated"; + @Rule + public final CoreDbTester db = CoreDbTester.createForSchema(CreateIndexOnPortfoliosMeasuresMigratedTest.class, "schema.sql"); + private final CreateIndexOnPortfoliosMeasuresMigrated underTest = new CreateIndexOnPortfoliosMeasuresMigrated(db.database()); + + @Test + public void migration_should_create_index() throws SQLException { + db.assertIndexDoesNotExist(TABLE_NAME, INDEX_NAME); + + underTest.execute(); + + db.assertIndex(TABLE_NAME, INDEX_NAME, COLUMN_NAME); + } + + @Test + public void migration_should_be_reentrant() throws SQLException { + underTest.execute(); + underTest.execute(); + + db.assertIndex(TABLE_NAME, INDEX_NAME, COLUMN_NAME); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnProjectBranchesMeasuresMigratedTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnProjectBranchesMeasuresMigratedTest.java new file mode 100644 index 00000000000..1618a973006 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnProjectBranchesMeasuresMigratedTest.java @@ -0,0 +1,54 @@ +/* + * 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.db.migration.adhoc; + +import java.sql.SQLException; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.db.CoreDbTester; + +import static org.sonar.server.platform.db.migration.adhoc.CreateIndexOnProjectBranchesMeasuresMigrated.COLUMN_NAME; +import static org.sonar.server.platform.db.migration.adhoc.CreateIndexOnProjectBranchesMeasuresMigrated.TABLE_NAME; + +public class CreateIndexOnProjectBranchesMeasuresMigratedTest { + + private static final String INDEX_NAME = "pb_measures_migrated"; + + @Rule + public final CoreDbTester db = CoreDbTester.createForSchema(CreateIndexOnProjectBranchesMeasuresMigratedTest.class, "schema.sql"); + private final CreateIndexOnProjectBranchesMeasuresMigrated underTest = new CreateIndexOnProjectBranchesMeasuresMigrated(db.database()); + + @Test + public void migration_should_create_index() throws SQLException { + db.assertIndexDoesNotExist(TABLE_NAME, INDEX_NAME); + + underTest.execute(); + + db.assertIndex(TABLE_NAME, INDEX_NAME, COLUMN_NAME); + } + + @Test + public void migration_should_be_reentrant() throws SQLException { + underTest.execute(); + underTest.execute(); + + db.assertIndex(TABLE_NAME, INDEX_NAME, COLUMN_NAME); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/CreateMeasuresTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/CreateMeasuresTableTest.java new file mode 100644 index 00000000000..ede32bd4777 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/adhoc/CreateMeasuresTableTest.java @@ -0,0 +1,70 @@ +/* + * 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.db.migration.adhoc; + +import java.sql.SQLException; +import java.sql.Types; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.db.CoreDbTester; +import org.sonar.server.platform.db.migration.step.DdlChange; + +import static org.sonar.server.platform.db.migration.adhoc.CreateMeasuresTable.COLUMN_BRANCH_UUID; +import static org.sonar.server.platform.db.migration.adhoc.CreateMeasuresTable.COLUMN_COMPONENT_UUID; +import static org.sonar.server.platform.db.migration.adhoc.CreateMeasuresTable.COLUMN_CREATED_AT; +import static org.sonar.server.platform.db.migration.adhoc.CreateMeasuresTable.COLUMN_JSON_VALUE; +import static org.sonar.server.platform.db.migration.adhoc.CreateMeasuresTable.COLUMN_JSON_VALUE_HASH; +import static org.sonar.server.platform.db.migration.adhoc.CreateMeasuresTable.COLUMN_UPDATED_AT; +import static org.sonar.server.platform.db.migration.adhoc.CreateMeasuresTable.MEASURES_TABLE_NAME; +import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE; + +public class CreateMeasuresTableTest { + + @Rule + public final CoreDbTester db = CoreDbTester.createEmpty(); + + private final DdlChange underTest = new CreateMeasuresTable(db.database()); + + @Test + public void execute_shouldCreateTable() throws SQLException { + db.assertTableDoesNotExist(MEASURES_TABLE_NAME); + + underTest.execute(); + + db.assertTableExists(MEASURES_TABLE_NAME); + db.assertNoPrimaryKey(MEASURES_TABLE_NAME); + db.assertColumnDefinition(MEASURES_TABLE_NAME, COLUMN_COMPONENT_UUID, Types.VARCHAR, UUID_SIZE, false); + db.assertColumnDefinition(MEASURES_TABLE_NAME, COLUMN_BRANCH_UUID, Types.VARCHAR, UUID_SIZE, false); + db.assertColumnDefinition(MEASURES_TABLE_NAME, COLUMN_JSON_VALUE, Types.CLOB, null, false); + db.assertColumnDefinition(MEASURES_TABLE_NAME, COLUMN_JSON_VALUE_HASH, Types.BIGINT, null, false); + db.assertColumnDefinition(MEASURES_TABLE_NAME, COLUMN_CREATED_AT, Types.BIGINT, null, false); + db.assertColumnDefinition(MEASURES_TABLE_NAME, COLUMN_UPDATED_AT, Types.BIGINT, null, false); + } + + @Test + public void execute_shouldBeReentrant() throws SQLException { + db.assertTableDoesNotExist(MEASURES_TABLE_NAME); + + underTest.execute(); + underTest.execute(); + + db.assertTableExists(MEASURES_TABLE_NAME); + } +} diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToPortfoliosTableTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToPortfoliosTableTest/schema.sql new file mode 100644 index 00000000000..7fa82246b15 --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToPortfoliosTableTest/schema.sql @@ -0,0 +1,16 @@ +CREATE TABLE "PORTFOLIOS"( + "UUID" CHARACTER VARYING(40) NOT NULL, + "KEE" CHARACTER VARYING(400) NOT NULL, + "NAME" CHARACTER VARYING(2000) NOT NULL, + "DESCRIPTION" CHARACTER VARYING(2000), + "ROOT_UUID" CHARACTER VARYING(40) NOT NULL, + "PARENT_UUID" CHARACTER VARYING(40), + "PRIVATE" BOOLEAN NOT NULL, + "SELECTION_MODE" CHARACTER VARYING(50) NOT NULL, + "SELECTION_EXPRESSION" CHARACTER VARYING(4000), + "CREATED_AT" BIGINT NOT NULL, + "UPDATED_AT" BIGINT NOT NULL, + "BRANCH_KEY" CHARACTER VARYING(255) +); +ALTER TABLE "PORTFOLIOS" ADD CONSTRAINT "PK_PORTFOLIOS" PRIMARY KEY("UUID"); +CREATE UNIQUE INDEX "UNIQ_PORTFOLIOS_KEE" ON "PORTFOLIOS"("KEE" NULLS FIRST); diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToProjectBranchesTableTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToProjectBranchesTableTest/schema.sql new file mode 100644 index 00000000000..4b20881e535 --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/adhoc/AddMeasuresMigratedColumnToProjectBranchesTableTest/schema.sql @@ -0,0 +1,15 @@ +CREATE TABLE "PROJECT_BRANCHES"( + "UUID" CHARACTER VARYING(50) NOT NULL, + "PROJECT_UUID" CHARACTER VARYING(50) NOT NULL, + "KEE" CHARACTER VARYING(255) NOT NULL, + "BRANCH_TYPE" CHARACTER VARYING(12) NOT NULL, + "MERGE_BRANCH_UUID" CHARACTER VARYING(50), + "PULL_REQUEST_BINARY" BINARY LARGE OBJECT, + "MANUAL_BASELINE_ANALYSIS_UUID" CHARACTER VARYING(40), + "CREATED_AT" BIGINT NOT NULL, + "UPDATED_AT" BIGINT NOT NULL, + "EXCLUDE_FROM_PURGE" BOOLEAN DEFAULT FALSE NOT NULL, + "NEED_ISSUE_SYNC" BOOLEAN NOT NULL +); +ALTER TABLE "PROJECT_BRANCHES" ADD CONSTRAINT "PK_PROJECT_BRANCHES" PRIMARY KEY("UUID"); +CREATE UNIQUE INDEX "UNIQ_PROJECT_BRANCHES" ON "PROJECT_BRANCHES"("BRANCH_TYPE" NULLS FIRST, "PROJECT_UUID" NULLS FIRST, "KEE" NULLS FIRST); diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnPortfoliosMeasuresMigratedTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnPortfoliosMeasuresMigratedTest/schema.sql new file mode 100644 index 00000000000..367e0454916 --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnPortfoliosMeasuresMigratedTest/schema.sql @@ -0,0 +1,17 @@ +CREATE TABLE "PORTFOLIOS"( + "UUID" CHARACTER VARYING(40) NOT NULL, + "KEE" CHARACTER VARYING(400) NOT NULL, + "NAME" CHARACTER VARYING(2000) NOT NULL, + "DESCRIPTION" CHARACTER VARYING(2000), + "ROOT_UUID" CHARACTER VARYING(40) NOT NULL, + "PARENT_UUID" CHARACTER VARYING(40), + "PRIVATE" BOOLEAN NOT NULL, + "SELECTION_MODE" CHARACTER VARYING(50) NOT NULL, + "SELECTION_EXPRESSION" CHARACTER VARYING(4000), + "CREATED_AT" BIGINT NOT NULL, + "UPDATED_AT" BIGINT NOT NULL, + "BRANCH_KEY" CHARACTER VARYING(255), + "MEASURES_MIGRATED" BOOLEAN NOT NULL DEFAULT FALSE +); +ALTER TABLE "PORTFOLIOS" ADD CONSTRAINT "PK_PORTFOLIOS" PRIMARY KEY("UUID"); +CREATE UNIQUE INDEX "UNIQ_PORTFOLIOS_KEE" ON "PORTFOLIOS"("KEE" NULLS FIRST); diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnProjectBranchesMeasuresMigratedTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnProjectBranchesMeasuresMigratedTest/schema.sql new file mode 100644 index 00000000000..5e8762a8ec7 --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/adhoc/CreateIndexOnProjectBranchesMeasuresMigratedTest/schema.sql @@ -0,0 +1,16 @@ +CREATE TABLE "PROJECT_BRANCHES"( + "UUID" CHARACTER VARYING(50) NOT NULL, + "PROJECT_UUID" CHARACTER VARYING(50) NOT NULL, + "KEE" CHARACTER VARYING(255) NOT NULL, + "BRANCH_TYPE" CHARACTER VARYING(12) NOT NULL, + "MERGE_BRANCH_UUID" CHARACTER VARYING(50), + "PULL_REQUEST_BINARY" BINARY LARGE OBJECT, + "MANUAL_BASELINE_ANALYSIS_UUID" CHARACTER VARYING(40), + "CREATED_AT" BIGINT NOT NULL, + "UPDATED_AT" BIGINT NOT NULL, + "EXCLUDE_FROM_PURGE" BOOLEAN DEFAULT FALSE NOT NULL, + "NEED_ISSUE_SYNC" BOOLEAN NOT NULL, + "MEASURES_MIGRATED" BOOLEAN NOT NULL DEFAULT FALSE +); +ALTER TABLE "PROJECT_BRANCHES" ADD CONSTRAINT "PK_PROJECT_BRANCHES" PRIMARY KEY("UUID"); +CREATE UNIQUE INDEX "UNIQ_PROJECT_BRANCHES" ON "PROJECT_BRANCHES"("BRANCH_TYPE" NULLS FIRST, "PROJECT_UUID" NULLS FIRST, "KEE" NULLS FIRST); 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 new file mode 100644 index 00000000000..a89d1eb8c1d --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/PrepareMigrationAction.java @@ -0,0 +1,118 @@ +/* + * 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; + +/** + * Implementation of the {@code prepare_migration} action for the System WebService. + */ +public class PrepareMigrationAction implements SystemWsAction { + + public static final String PARAM_ENABLE = "enable"; + public static final String SYSTEM_MEASURES_MIGRATION_ENABLED = "system.measures.migration.enabled"; + 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." + + "<br/>" + + "Sending a POST request to this URL enables the 'live_measures' table migration. " + + "It is strongly advised to <strong>make a database backup</strong> 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 e18d8946b6b..5807d697a88 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,6 +20,11 @@ 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; public class SystemWsModule extends Module { @@ -35,6 +40,13 @@ public class SystemWsModule extends Module { LivenessActionSupport.class, LivenessAction.class, + CreateMeasuresTable.class, + AddMeasuresMigratedColumnToProjectBranchesTable.class, + AddMeasuresMigratedColumnToPortfoliosTable.class, + CreateIndexOnProjectBranchesMeasuresMigrated.class, + CreateIndexOnPortfoliosMeasuresMigrated.class, + PrepareMigrationAction.class, + InfoAction.class, LogsAction.class, MigrateDbAction.class, 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 new file mode 100644 index 00000000000..902e4c6e249 --- /dev/null +++ b/server/sonar-webserver-webapi/src/main/resources/org/sonar/server/platform/ws/example-prepare_migration.json @@ -0,0 +1,3 @@ +{ + "message": "The 'live_measures' migration mode is enabled" +} 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 new file mode 100644 index 00000000000..1b6de61b1d5 --- /dev/null +++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/platform/ws/PrepareMigrationActionTest.java @@ -0,0 +1,181 @@ +/* + * 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.server.platform.ws.PrepareMigrationAction.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 0a75383e46d..1249de66c19 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(15); + assertThat(container.getAddedObjects()).hasSize(21); } } |