diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2017-02-15 18:18:27 +0100 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2017-02-17 13:31:49 +0100 |
commit | 9824b94f16109305b4847a611379029695823427 (patch) | |
tree | 85b339103ce4c56df78e3e26f21117da7fb04976 /server/sonar-server | |
parent | 0d3be9943570cf5bfb7fbb72fdfe5a6fcb2798c0 (diff) | |
download | sonarqube-9824b94f16109305b4847a611379029695823427.tar.gz sonarqube-9824b94f16109305b4847a611379029695823427.zip |
split sonar-db into server/sonar-db-core and server/sonar-db-dao
Diffstat (limited to 'server/sonar-server')
4 files changed, 260 insertions, 16 deletions
diff --git a/server/sonar-server/pom.xml b/server/sonar-server/pom.xml index ce99f0d7e93..69f66f0a1c7 100644 --- a/server/sonar-server/pom.xml +++ b/server/sonar-server/pom.xml @@ -61,7 +61,7 @@ </dependency> <dependency> <groupId>${project.groupId}</groupId> - <artifactId>sonar-db</artifactId> + <artifactId>sonar-db-dao</artifactId> </dependency> <dependency> <groupId>${project.groupId}</groupId> @@ -188,19 +188,8 @@ <!-- unit tests --> <dependency> <groupId>${project.groupId}</groupId> - <artifactId>sonar-db</artifactId> - <version>${project.version}</version> - <type>test-jar</type> - <scope>test</scope> - </dependency> - <dependency> - <groupId>${project.groupId}</groupId> - <artifactId>sonar-testing-harness</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.dbunit</groupId> - <artifactId>dbunit</artifactId> + <artifactId>sonar-db-testing</artifactId> + <type>pom</type> <scope>test</scope> </dependency> <dependency> diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java index 0be862b3473..5431c1148c9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java +++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/ProjectMeasuresQueryFactory.java @@ -31,12 +31,12 @@ import javax.annotation.Nullable; import org.sonar.api.measures.Metric.Level; import org.sonar.core.util.stream.Collectors; import org.sonar.server.measure.index.ProjectMeasuresQuery; -import org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion; -import org.sonar.server.measure.index.ProjectMeasuresQuery.Operator; import static com.google.common.base.Preconditions.checkArgument; import static java.util.Locale.ENGLISH; import static org.sonar.api.measures.CoreMetrics.ALERT_STATUS_KEY; +import static org.sonar.server.measure.index.ProjectMeasuresQuery.MetricCriterion; +import static org.sonar.server.measure.index.ProjectMeasuresQuery.Operator; class ProjectMeasuresQueryFactory { private static final Splitter CRITERIA_SPLITTER = Splitter.on(Pattern.compile("and", Pattern.CASE_INSENSITIVE)); diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/db/migration/AutoDbMigration.java b/server/sonar-server/src/main/java/org/sonar/server/platform/db/migration/AutoDbMigration.java new file mode 100644 index 00000000000..40f297bfeea --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/db/migration/AutoDbMigration.java @@ -0,0 +1,110 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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; + +import com.google.common.annotations.VisibleForTesting; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import org.apache.commons.dbutils.DbUtils; +import org.apache.ibatis.session.SqlSession; +import org.picocontainer.Startable; +import org.sonar.api.platform.ServerUpgradeStatus; +import org.sonar.api.utils.log.Loggers; +import org.sonar.db.DbClient; +import org.sonar.db.DdlUtils; +import org.sonar.db.dialect.Dialect; +import org.sonar.db.dialect.H2; +import org.sonar.server.platform.db.migration.engine.MigrationEngine; + +/** + * FIXME fix this class to remove use of DdlUtils.createSchema + */ +public class AutoDbMigration implements Startable { + private final ServerUpgradeStatus serverUpgradeStatus; + private final DbClient dbClient; + private final MigrationEngine migrationEngine; + + public AutoDbMigration(ServerUpgradeStatus serverUpgradeStatus, DbClient dbClient, MigrationEngine migrationEngine) { + this.serverUpgradeStatus = serverUpgradeStatus; + this.dbClient = dbClient; + this.migrationEngine = migrationEngine; + } + + @Override + public void start() { + if (!serverUpgradeStatus.isFreshInstall()) { + return; + } + + Loggers.get(getClass()).info("Automatically perform DB migration on fresh install"); + Dialect dialect = dbClient.getDatabase().getDialect(); + if (H2.ID.equals(dialect.getId())) { + installH2(); + } else { + migrationEngine.execute(); + } + } + + @VisibleForTesting + void installH2() { + Connection connection = null; + try (SqlSession session = dbClient.openSession(false)) { + connection = session.getConnection(); + createH2Schema(connection, dbClient.getDatabase().getDialect().getId()); + } finally { + DbUtils.closeQuietly(connection); + } + } + + @VisibleForTesting + protected void createH2Schema(Connection connection, String dialectId) { + DdlUtils.createSchema(connection, dialectId, false); + hackFixForProjectMeasureTreeQueries(connection); + } + + /** + * see SONAR-8586 + */ + private static void hackFixForProjectMeasureTreeQueries(Connection connection) { + int metricId = 1; + try (PreparedStatement preparedStatement = connection.prepareStatement("insert into PROJECT_MEASURES (METRIC_ID,COMPONENT_UUID,ANALYSIS_UUID) values (?,?,?);")) { + for (int i = 1; i < 1000; i++) { + preparedStatement.setInt(1, metricId); + preparedStatement.setString(2, "foo_" + i); + preparedStatement.setString(3, "bar_" + i); + preparedStatement.addBatch(); + if (i % 250 == 0) { + preparedStatement.executeBatch(); + connection.commit(); + } + } + preparedStatement.executeBatch(); + connection.commit(); + } catch (SQLException e) { + throw new RuntimeException("Failed to insert fake rows into table PROJECT_MEASURES", e); + } + } + + @Override + public void stop() { + // nothing to do + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/db/migration/AutoDbMigrationTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/db/migration/AutoDbMigrationTest.java new file mode 100644 index 00000000000..b8e24b0cf32 --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/db/migration/AutoDbMigrationTest.java @@ -0,0 +1,145 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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; + +import java.sql.Connection; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; +import org.sonar.api.platform.ServerUpgradeStatus; +import org.sonar.api.utils.log.LogTester; +import org.sonar.api.utils.log.LoggerLevel; +import org.sonar.db.DbClient; +import org.sonar.db.DbSession; +import org.sonar.db.dialect.Dialect; +import org.sonar.db.dialect.H2; +import org.sonar.db.dialect.MsSql; +import org.sonar.db.dialect.MySql; +import org.sonar.db.dialect.Oracle; +import org.sonar.db.dialect.PostgreSql; +import org.sonar.server.platform.db.migration.engine.MigrationEngine; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + +public class AutoDbMigrationTest { + @Rule + public ExpectedException thrown = ExpectedException.none(); + @Rule + public LogTester logTester = new LogTester(); + + private DbClient dbClient = mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS); + private ServerUpgradeStatus serverUpgradeStatus = mock(ServerUpgradeStatus.class); + private MigrationEngine migrationEngine = mock(MigrationEngine.class); + private AutoDbMigration underTest = new AutoDbMigration(serverUpgradeStatus, dbClient, migrationEngine); + + private AutoDbMigration noRealH2Creation = spy(new AutoDbMigration(serverUpgradeStatus, dbClient, migrationEngine) { + @Override + protected void createH2Schema(Connection connection, String dialectId) { + // do nothing + } + }); + + @Test + public void start_creates_schema_on_h2_if_fresh_install() { + mockDialect(new H2()); + mockDbClientOpenSession(); + mockFreshInstall(true); + + noRealH2Creation.start(); + + verify(noRealH2Creation).installH2(); + verifyInfoLog(); + } + + @Test + public void start_runs_MigrationEngine_on_mysql_if_fresh_install() { + start_runs_MigrationEngine_for_dialect_if_fresh_install(new MySql()); + } + + @Test + public void start_runs_MigrationEngine_on_postgre_if_fresh_install() { + start_runs_MigrationEngine_for_dialect_if_fresh_install(new PostgreSql()); + } + + @Test + public void start_runs_MigrationEngine_on_Oracle_if_fresh_install() { + start_runs_MigrationEngine_for_dialect_if_fresh_install(new Oracle()); + } + + @Test + public void start_runs_MigrationEngine_on_MsSQL_if_fresh_install() { + start_runs_MigrationEngine_for_dialect_if_fresh_install(new MsSql()); + } + + private void start_runs_MigrationEngine_for_dialect_if_fresh_install(Dialect dialect) { + mockDialect(dialect); + mockFreshInstall(true); + + underTest.start(); + + verify(migrationEngine).execute(); + verifyInfoLog(); + } + + @Test + public void start_does_nothing_if_not_fresh_install() { + mockFreshInstall(false); + + noRealH2Creation.start(); + + verify(noRealH2Creation).start(); + verifyNoMoreInteractions(noRealH2Creation); + verifyZeroInteractions(migrationEngine); + assertThat(logTester.logs()).isEmpty(); + } + + @Test + public void stop_has_no_effect() { + underTest.stop(); + } + + private void mockFreshInstall(boolean value) { + when(serverUpgradeStatus.isFreshInstall()).thenReturn(value); + } + + private void mockDialect(Dialect dialect) { + when(dbClient.getDatabase().getDialect()).thenReturn(dialect); + } + + private void mockDbClientOpenSession() { + Connection connection = mock(Connection.class); + DbSession session = mock(DbSession.class); + when(session.getConnection()).thenReturn(connection); + when(dbClient.openSession(false)).thenReturn(session); + } + + private void verifyInfoLog() { + assertThat(logTester.logs()).hasSize(1); + assertThat(logTester.logs(LoggerLevel.INFO)).containsExactly("Automatically perform DB migration on fresh install"); + } + +} |