diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2016-12-07 15:04:10 +0100 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2016-12-14 12:11:51 +0100 |
commit | 080a0fb172ad6178fef529480b5ace5d0a66f06a (patch) | |
tree | df39d41d1557e16955bf99621b2e5dc5d407a880 /server | |
parent | 460eee7ce980e719ee1de7873b8fd22bf40f3532 (diff) | |
download | sonarqube-080a0fb172ad6178fef529480b5ace5d0a66f06a.tar.gz sonarqube-080a0fb172ad6178fef529480b5ace5d0a66f06a.zip |
SONAR-8445 handle creation of table SCHEMA_MIGRATIONS in Java
Diffstat (limited to 'server')
8 files changed, 274 insertions, 4 deletions
diff --git a/server/sonar-db-migration/pom.xml b/server/sonar-db-migration/pom.xml index 9ece9a01e95..21f004d69eb 100644 --- a/server/sonar-db-migration/pom.xml +++ b/server/sonar-db-migration/pom.xml @@ -14,8 +14,43 @@ <description>Create SonarQube schema</description> <dependencies> + <dependency> + <groupId>org.sonarsource.sonarqube</groupId> + <artifactId>sonar-core</artifactId> + </dependency> + <dependency> + <groupId>org.sonarsource.sonarqube</groupId> + <artifactId>sonar-db</artifactId> + </dependency> + <dependency> + <groupId>com.google.code.findbugs</groupId> + <artifactId>jsr305</artifactId> + <scope>provided</scope> + </dependency> <!-- tests --> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>sonar-testing-harness</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>sonar-db</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.dbunit</groupId> + <artifactId>dbunit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <scope>test</scope> + </dependency> </dependencies> diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/MigrationHistoryTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/MigrationHistoryTable.java new file mode 100644 index 00000000000..a74fd0866fb --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/MigrationHistoryTable.java @@ -0,0 +1,48 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.db.migration.history; + +import org.sonar.api.Startable; + +/** + * This class is responsible for ensuring at startup that the persistence of migration history is possible. + * <p> + * Therefor, it will create the migration history table if it does not exist yet, update it if necessary and fail + * if any of the two previous operations fails. + * </p> + * <p> + * This class is intended to be present only in the WebServer and only the web server is the startup leader. + * </p> + */ +public interface MigrationHistoryTable extends Startable { + String NAME = "schema_migrations"; + + /** + * Ensures that the history of db migrations can be persisted to database: + * <ul> + * <li>underlying table {@code SCHEMA_MIGRATIONS} is created if it does not exist</li> + * <li>underlying table {@code SCHEMA_MIGRATIONS} is updated if needed</li> + * </ul> + * + * @throws IllegalStateException if we can not ensure that table {@code SCHEMA_MIGRATIONS} can be accessed correctly + */ + @Override + void start(); +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/MigrationHistoryTableImpl.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/MigrationHistoryTableImpl.java new file mode 100644 index 00000000000..68043682b38 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/MigrationHistoryTableImpl.java @@ -0,0 +1,80 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.db.migration.history; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.List; +import org.sonar.api.utils.log.Loggers; +import org.sonar.db.DatabaseUtils; +import org.sonar.db.DbClient; +import org.sonar.db.version.CreateTableBuilder; +import org.sonar.db.version.VarcharColumnDef; + +public class MigrationHistoryTableImpl implements MigrationHistoryTable { + private static final String VERSION_COLUMN_NAME = "version"; + + private final DbClient dbClient; + + public MigrationHistoryTableImpl(DbClient dbClient) { + this.dbClient = dbClient; + } + + @Override + public void start() { + try (Connection connection = createDdlConnection(dbClient)) { + if (!DatabaseUtils.tableExists(NAME, connection)) { + createTable(connection); + } + } catch (SQLException e) { + throw new IllegalStateException("Failed to create table " + NAME, e); + } + } + + private void createTable(Connection connection) throws SQLException { + List<String> sqls = new CreateTableBuilder(dbClient.getDatabase().getDialect(), NAME) + .addColumn(VarcharColumnDef.newVarcharColumnDefBuilder().setColumnName(VERSION_COLUMN_NAME).setIsNullable(false).setLimit(255).build()) + .build(); + + Loggers.get(MigrationHistoryTableImpl.class).info("Creating table " + NAME); + for (String sql : sqls) { + execute(connection, sql); + } + } + + private static Connection createDdlConnection(DbClient dbClient) throws SQLException { + Connection res = dbClient.getDatabase().getDataSource().getConnection(); + res.setAutoCommit(false); + return res; + } + + private static void execute(Connection connection, String sql) throws SQLException { + try (Statement stmt = connection.createStatement()) { + stmt.execute(sql); + connection.commit(); + } + } + + @Override + public void stop() { + // nothing to do + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/package-info.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/package-info.java new file mode 100644 index 00000000000..894d41a5e42 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/history/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact 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.history; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/history/MigrationHistoryTableImplTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/history/MigrationHistoryTableImplTest.java new file mode 100644 index 00000000000..958728c17f3 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/history/MigrationHistoryTableImplTest.java @@ -0,0 +1,77 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.server.platform.db.migration.history; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Types; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.db.DbSession; +import org.sonar.db.DbTester; + +import static org.assertj.core.api.Assertions.assertThat; + +public class MigrationHistoryTableImplTest { + private static final String TABLE_SCHEMA_MIGRATIONS = "schema_migrations"; + + @Rule + public DbTester dbTester = DbTester.createForSchema(System2.INSTANCE, MigrationHistoryTableImplTest.class, "empty.sql"); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private MigrationHistoryTableImpl underTest = new MigrationHistoryTableImpl(dbTester.getDbClient()); + + @Test + public void start_creates_table_on_empty_schema() { + underTest.start(); + + verifyTable(); + } + + @Test + public void start_does_not_fail_if_table_exists() throws SQLException { + executeDdl("create table " + TABLE_SCHEMA_MIGRATIONS + " (version varchar(255) not null)"); + verifyTable(); + + underTest.start(); + + verifyTable(); + } + + private void executeDdl(String sql) throws SQLException { + try (DbSession dbSession = dbTester.getDbClient().openSession(false); + Connection connection = dbSession.getConnection()) { + connection.setAutoCommit(false); + try (Statement statement = connection.createStatement()) { + statement.execute(sql); + connection.commit(); + } + } + } + + private void verifyTable() { + assertThat(dbTester.countRowsOfTable(TABLE_SCHEMA_MIGRATIONS)).isEqualTo(0); + dbTester.assertColumnDefinition(TABLE_SCHEMA_MIGRATIONS, "version", Types.VARCHAR, 255, false); + } +} diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/history/MigrationHistoryTableImplTest/empty.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/history/MigrationHistoryTableImplTest/empty.sql new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/history/MigrationHistoryTableImplTest/empty.sql diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/db/migrations/DatabaseMigrator.java b/server/sonar-server/src/main/java/org/sonar/server/platform/db/migrations/DatabaseMigrator.java index 39a9bbcfe58..1435468e39a 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/db/migrations/DatabaseMigrator.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/db/migrations/DatabaseMigrator.java @@ -113,6 +113,6 @@ public class DatabaseMigrator implements Startable { @VisibleForTesting protected void createSchema(Connection connection, String dialectId) { - DdlUtils.createSchema(connection, dialectId); + DdlUtils.createSchema(connection, dialectId, false); } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java index b3786b8dc7d..c4356cec0d6 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel2.java @@ -29,6 +29,7 @@ import org.sonar.db.version.MigrationStepModule; import org.sonar.server.platform.DefaultServerUpgradeStatus; import org.sonar.server.platform.StartupMetadataProvider; import org.sonar.server.platform.db.CheckDatabaseCharsetAtStartup; +import org.sonar.server.platform.db.migration.history.MigrationHistoryTableImpl; import org.sonar.server.platform.db.migrations.DatabaseMigrator; import org.sonar.server.platform.db.migrations.PlatformDatabaseMigration; import org.sonar.server.platform.db.migrations.PlatformDatabaseMigrationExecutorServiceImpl; @@ -67,11 +68,16 @@ public class PlatformLevel2 extends PlatformLevel { // depends on plugins RailsAppsDeployer.class, DefaultI18n.class, - RuleI18nManager.class, + RuleI18nManager.class); - // DB migration + // Full Java DB Migration framework and configuration + addIfStartupLeader(MigrationHistoryTableImpl.class); + // platform DB migration (TODO remove call to Ruby's Active Record and use DbMigrationEngine instead) + add( PlatformDatabaseMigrationExecutorServiceImpl.class, - PlatformDatabaseMigration.class, + PlatformDatabaseMigration.class); + // Ruby DB Migration + add( DatabaseMigrator.class, MigrationStepModule.class); |