From 26aceee57542712fc72fcf7bdea319f420c0eb32 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Fri, 19 Jul 2019 14:17:16 +0200 Subject: [PATCH] SONAR-8520 move H2 scripts to sonar-db-dao --- server/sonar-db-core/build.gradle | 1 + .../db/{DdlUtils.java => CoreDdlUtils.java} | 15 +- .../java/org/sonar/db/AbstractDbTester.java | 4 +- .../test/java/org/sonar/db/CoreDbTester.java | 3 +- .../java/org/sonar/db/CoreDdlUtilsTest.java | 40 +++++ .../java/org/sonar/db/CoreH2Database.java | 104 ++++++++++++ .../test/java/org/sonar/db/CoreTestDb.java | 149 +++++++++--------- .../src/test/java/org/sonar/db/TestDb.java | 48 ++++++ server/sonar-db-dao/build.gradle | 1 + .../src/main/java/org/sonar/db/DdlUtils.java | 42 +++++ .../main/resources/org/sonar/db}/rows-h2.sql | 0 .../resources/org/sonar/db}/schema-h2.ddl | 0 .../org/sonar/db}/schema_migrations-h2.ddl | 0 .../src/test/java/org/sonar/db/DbTester.java | 6 +- .../test/java/org/sonar/db/DdlUtilsTest.java | 14 +- .../test/java/org/sonar/db/H2Database.java | 2 +- .../java/org/sonar/db/H2DatabaseTest.java | 0 .../src/test/java/org/sonar/db/TestDb.java | 69 -------- .../test/java/org/sonar/db/TestDbImpl.java | 115 ++++++++++++++ .../db/migration/AutoDbMigration.java | 2 +- 20 files changed, 436 insertions(+), 179 deletions(-) rename server/sonar-db-core/src/main/java/org/sonar/db/{DdlUtils.java => CoreDdlUtils.java} (77%) create mode 100644 server/sonar-db-core/src/test/java/org/sonar/db/CoreDdlUtilsTest.java create mode 100644 server/sonar-db-core/src/test/java/org/sonar/db/CoreH2Database.java create mode 100644 server/sonar-db-core/src/test/java/org/sonar/db/TestDb.java create mode 100644 server/sonar-db-dao/src/main/java/org/sonar/db/DdlUtils.java rename server/{sonar-db-core/src/main/resources/org/sonar/db/version => sonar-db-dao/src/main/resources/org/sonar/db}/rows-h2.sql (100%) rename server/{sonar-db-core/src/main/resources/org/sonar/db/version => sonar-db-dao/src/main/resources/org/sonar/db}/schema-h2.ddl (100%) rename server/{sonar-db-core/src/main/resources/org/sonar/db/version => sonar-db-dao/src/main/resources/org/sonar/db}/schema_migrations-h2.ddl (100%) rename server/{sonar-db-core => sonar-db-dao}/src/test/java/org/sonar/db/DdlUtilsTest.java (85%) rename server/{sonar-db-core => sonar-db-dao}/src/test/java/org/sonar/db/H2Database.java (98%) rename server/{sonar-db-core => sonar-db-dao}/src/test/java/org/sonar/db/H2DatabaseTest.java (100%) delete mode 100644 server/sonar-db-dao/src/test/java/org/sonar/db/TestDb.java create mode 100644 server/sonar-db-dao/src/test/java/org/sonar/db/TestDbImpl.java diff --git a/server/sonar-db-core/build.gradle b/server/sonar-db-core/build.gradle index 77ecbeb8818..5a89af7bac3 100644 --- a/server/sonar-db-core/build.gradle +++ b/server/sonar-db-core/build.gradle @@ -24,6 +24,7 @@ dependencies { compileOnly 'com.google.code.findbugs:jsr305' testCompile 'com.google.code.findbugs:jsr305' + testCompile 'com.h2database:h2' testCompile 'com.microsoft.sqlserver:mssql-jdbc' testCompile 'com.oracle.jdbc:ojdbc8' testCompile 'com.tngtech.java:junit-dataprovider' diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/DdlUtils.java b/server/sonar-db-core/src/main/java/org/sonar/db/CoreDdlUtils.java similarity index 77% rename from server/sonar-db-core/src/main/java/org/sonar/db/DdlUtils.java rename to server/sonar-db-core/src/main/java/org/sonar/db/CoreDdlUtils.java index 67c005054db..a219ff51ce7 100644 --- a/server/sonar-db-core/src/main/java/org/sonar/db/DdlUtils.java +++ b/server/sonar-db-core/src/main/java/org/sonar/db/CoreDdlUtils.java @@ -30,26 +30,15 @@ import org.apache.ibatis.jdbc.ScriptRunner; * * @since 2.12 */ -public final class DdlUtils { +public final class CoreDdlUtils { - private DdlUtils() { + private CoreDdlUtils() { } public static boolean supportsDialect(String dialect) { return "h2".equals(dialect); } - /** - * The connection is commited in this method but not closed. - */ - public static void createSchema(Connection connection, String dialect, boolean createSchemaMigrations) { - if (createSchemaMigrations) { - executeScript(connection, "org/sonar/db/version/schema_migrations-" + dialect + ".ddl"); - } - executeScript(connection, "org/sonar/db/version/schema-" + dialect + ".ddl"); - executeScript(connection, "org/sonar/db/version/rows-" + dialect + ".sql"); - } - public static void executeScript(Connection connection, String path) { ScriptRunner scriptRunner = newScriptRunner(connection); try { diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/AbstractDbTester.java b/server/sonar-db-core/src/test/java/org/sonar/db/AbstractDbTester.java index 23ae8e7dd32..2d3c7df948d 100644 --- a/server/sonar-db-core/src/test/java/org/sonar/db/AbstractDbTester.java +++ b/server/sonar-db-core/src/test/java/org/sonar/db/AbstractDbTester.java @@ -76,8 +76,8 @@ import static java.sql.ResultSetMetaData.columnNullable; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; -public class AbstractDbTester extends ExternalResource { - protected static final Joiner COMMA_JOINER = Joiner.on(", "); +public class AbstractDbTester extends ExternalResource { + private static final Joiner COMMA_JOINER = Joiner.on(", "); protected final T db; public AbstractDbTester(T db) { diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/CoreDbTester.java b/server/sonar-db-core/src/test/java/org/sonar/db/CoreDbTester.java index 68826bdb35c..6df2eccaba2 100644 --- a/server/sonar-db-core/src/test/java/org/sonar/db/CoreDbTester.java +++ b/server/sonar-db-core/src/test/java/org/sonar/db/CoreDbTester.java @@ -19,7 +19,6 @@ */ package org.sonar.db; -import javax.annotation.Nullable; import org.apache.commons.lang.StringUtils; /** @@ -29,7 +28,7 @@ import org.apache.commons.lang.StringUtils; public class CoreDbTester extends AbstractDbTester { private final DefaultOrganizationTesting defaultOrganizationTesting; - private CoreDbTester(@Nullable String schemaPath) { + private CoreDbTester(String schemaPath) { super(CoreTestDb.create(schemaPath)); this.defaultOrganizationTesting = new DefaultOrganizationTesting(this); } diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/CoreDdlUtilsTest.java b/server/sonar-db-core/src/test/java/org/sonar/db/CoreDdlUtilsTest.java new file mode 100644 index 00000000000..20acb793425 --- /dev/null +++ b/server/sonar-db-core/src/test/java/org/sonar/db/CoreDdlUtilsTest.java @@ -0,0 +1,40 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.db; + +import org.assertj.core.api.Assertions; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CoreDdlUtilsTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Test + public void shouldSupportOnlyH2() { + Assertions.assertThat(CoreDdlUtils.supportsDialect("h2")).isTrue(); + assertThat(CoreDdlUtils.supportsDialect("postgresql")).isFalse(); + assertThat(CoreDdlUtils.supportsDialect("oracle")).isFalse(); + assertThat(CoreDdlUtils.supportsDialect("mssql")).isFalse(); + } +} diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/CoreH2Database.java b/server/sonar-db-core/src/test/java/org/sonar/db/CoreH2Database.java new file mode 100644 index 00000000000..08c7f2b22ba --- /dev/null +++ b/server/sonar-db-core/src/test/java/org/sonar/db/CoreH2Database.java @@ -0,0 +1,104 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.db; + +import java.sql.Connection; +import java.sql.SQLException; +import javax.sql.DataSource; +import org.apache.commons.dbcp2.BasicDataSource; +import org.apache.commons.dbutils.DbUtils; +import org.sonar.db.dialect.Dialect; +import org.sonar.db.dialect.H2; + +import static java.lang.String.format; + +/** + * H2 in-memory database, used for unit tests only. + * + * @since 3.2 + */ +public class CoreH2Database implements Database { + private final String name; + private BasicDataSource datasource; + + /** + * IMPORTANT: change DB name in order to not conflict with {@link DefaultDatabaseTest} + */ + public CoreH2Database(String name) { + this.name = name; + } + + @Override + public void start() { + startDatabase(); + } + + private void startDatabase() { + try { + datasource = new BasicDataSource(); + datasource.setDriverClassName("org.h2.Driver"); + datasource.setUsername("sonar"); + datasource.setPassword("sonar"); + datasource.setUrl("jdbc:h2:mem:" + name); + } catch (Exception e) { + throw new IllegalStateException("Fail to start H2", e); + } + } + + public void executeScript(String classloaderPath) { + Connection connection = null; + try { + connection = datasource.getConnection(); + CoreDdlUtils.executeScript(connection, classloaderPath); + + } catch (SQLException e) { + throw new IllegalStateException("Fail to execute script: " + classloaderPath, e); + } finally { + DbUtils.closeQuietly(connection); + } + } + + @Override + public void stop() { + try { + datasource.close(); + } catch (SQLException e) { + // Ignore error + } + } + + public DataSource getDataSource() { + return datasource; + } + + public Dialect getDialect() { + return new H2(); + } + + @Override + public void enableSqlLogging(boolean enable) { + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + return format("H2 Database[%s]", name); + } +} diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/CoreTestDb.java b/server/sonar-db-core/src/test/java/org/sonar/db/CoreTestDb.java index e673d167ac4..6699612c5bb 100644 --- a/server/sonar-db-core/src/test/java/org/sonar/db/CoreTestDb.java +++ b/server/sonar-db-core/src/test/java/org/sonar/db/CoreTestDb.java @@ -23,19 +23,16 @@ import java.io.File; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URI; -import java.sql.SQLException; import java.util.Map; import java.util.Properties; import java.util.function.BiConsumer; -import javax.annotation.Nullable; +import java.util.function.Function; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.text.StrSubstitutor; import org.dbunit.DataSourceDatabaseTester; import org.dbunit.IDatabaseTester; -import org.dbunit.dataset.datatype.IDataTypeFactory; import org.junit.AssumptionViolatedException; import org.sonar.api.config.Settings; import org.sonar.api.config.internal.MapSettings; @@ -44,123 +41,125 @@ import org.sonar.api.utils.log.Loggers; import org.sonar.db.dialect.H2; import org.sonar.process.logging.LogbackHelper; -import static org.apache.commons.lang.StringUtils.isNotEmpty; +import static java.util.Objects.requireNonNull; +import static org.apache.commons.lang.StringUtils.isEmpty; import static org.sonar.process.ProcessProperties.Property.JDBC_USERNAME; /** * This class should be call using @ClassRule in order to create the schema once (if @Rule is used * the schema will be recreated before each test). */ -class CoreTestDb { - - private static CoreTestDb DEFAULT; - - private static final Logger LOG = Loggers.get(CoreTestDb.class); +class CoreTestDb implements TestDb { private Database db; private DatabaseCommands commands; private IDatabaseTester tester; - private boolean isDefault; protected CoreTestDb() { // use static factory method } + protected CoreTestDb(Database db, DatabaseCommands commands, IDatabaseTester tester) { + this.db = db; + this.commands = commands; + this.tester = tester; + } - protected CoreTestDb(CoreTestDb base) { - this.db = base.db; - this.isDefault = base.isDefault; - this.commands = base.commands; - this.tester = base.tester; + static CoreTestDb create(String schemaPath) { + return new CoreTestDb().init(schemaPath); } - CoreTestDb init(@Nullable String schemaPath, BiConsumer extendedStart) { - if (db == null) { - Settings settings = new MapSettings().addProperties(System.getProperties()); - if (isNotEmpty(settings.getString("orchestrator.configUrl"))) { - loadOrchestratorSettings(settings); - } - String login = settings.getString(JDBC_USERNAME.getKey()); - for (String key : settings.getKeysStartingWith("sonar.jdbc")) { - LOG.info(key + ": " + settings.getString(key)); - } + private CoreTestDb init(String schemaPath) { + requireNonNull(schemaPath, "schemaPath can't be null"); + + Function databaseCreator = settings -> { String dialect = settings.getString("sonar.jdbc.dialect"); if (dialect != null && !"h2".equals(dialect)) { - db = new DefaultDatabase(new LogbackHelper(), settings); - } else { - db = new H2Database("h2Tests" + DigestUtils.md5Hex(StringUtils.defaultString(schemaPath)), schemaPath == null); + return new DefaultDatabase(new LogbackHelper(), settings); + } + return new CoreH2Database("h2Tests-" + DigestUtils.md5Hex(schemaPath)); + }; + Function databaseInitializer = database -> { + // will fail if not H2 + if (!database.getDialect().getId().equals("h2")) { + return false; } + + ((CoreH2Database) database).executeScript(schemaPath); + return true; + }; + BiConsumer noPostStartAction = (db, created) -> { + }; + + init(databaseCreator, databaseInitializer, noPostStartAction); + return this; + } + + protected void init(Function databaseSupplier, + Function databaseInitializer, + BiConsumer extendedStart) { + if (db == null) { + Settings settings = new MapSettings().addProperties(System.getProperties()); + loadOrchestratorSettings(settings); + logJdbcSettings(settings); + db = databaseSupplier.apply(settings); db.start(); - if (schemaPath != null) { - // will fail if not H2 - if (db.getDialect().getId().equals("h2")) { - ((H2Database) db).executeScript(schemaPath); - } else { - db.stop(); - } + + if (!databaseInitializer.apply(db)) { + db.stop(); + throw new IllegalStateException("Can't apply init script"); } - isDefault = (schemaPath == null); - LOG.debug("Test Database: " + db); + Loggers.get(getClass()).debug("Test Database: " + db); commands = DatabaseCommands.forDialect(db.getDialect()); + String login = settings.getString(JDBC_USERNAME.getKey()); tester = new DataSourceDatabaseTester(db.getDataSource(), commands.useLoginAsSchema() ? login : null); extendedStart.accept(db, true); } else { extendedStart.accept(db, false); } - return this; } - static CoreTestDb create(@Nullable String schemaPath) { - if (schemaPath == null) { - if (DEFAULT == null) { - DEFAULT = new CoreTestDb().init(null, (db, created) -> { - }); - } - return DEFAULT; - } - return new CoreTestDb().init(schemaPath, (db, created) -> { - }); + @Override + public Database getDatabase() { + return db; } - public void start() { - if (!isDefault && !H2.ID.equals(db.getDialect().getId())) { - throw new AssumptionViolatedException("Test disabled because it supports only H2"); - } + @Override + public DatabaseCommands getCommands() { + return commands; } - void stop() { - if (!isDefault) { - db.stop(); - } + @Override + public IDatabaseTester getDbUnitTester() { + return tester; } - void truncateTables() { - try { - commands.truncateDatabase(db.getDataSource()); - } catch (SQLException e) { - throw new IllegalStateException("Fail to truncate db tables", e); + @Override + public void start() { + if (!H2.ID.equals(db.getDialect().getId())) { + throw new AssumptionViolatedException("Test disabled because it supports only H2"); } } - Database getDatabase() { - return db; - } - - DatabaseCommands getCommands() { - return commands; + @Override + public void stop() { + db.stop(); } - IDatabaseTester getDbUnitTester() { - return tester; - } - - IDataTypeFactory getDbUnitFactory() { - return commands.getDbUnitFactory(); + private void logJdbcSettings(Settings settings) { + Logger logger = Loggers.get(getClass()); + for (String key : settings.getKeysStartingWith("sonar.jdbc")) { + logger.info(key + ": " + settings.getString(key)); + } } - private void loadOrchestratorSettings(Settings settings) { + private static void loadOrchestratorSettings(Settings settings) { String url = settings.getString("orchestrator.configUrl"); + if (isEmpty(url)) { + return; + } + InputStream input = null; try { URI uri = new URI(url); diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/TestDb.java b/server/sonar-db-core/src/test/java/org/sonar/db/TestDb.java new file mode 100644 index 00000000000..22645af7787 --- /dev/null +++ b/server/sonar-db-core/src/test/java/org/sonar/db/TestDb.java @@ -0,0 +1,48 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.db; + +import java.sql.SQLException; +import org.dbunit.IDatabaseTester; +import org.dbunit.dataset.datatype.IDataTypeFactory; + +public interface TestDb { + void start(); + + void stop(); + + Database getDatabase(); + + DatabaseCommands getCommands(); + + IDatabaseTester getDbUnitTester(); + + default void truncateTables() { + try { + getCommands().truncateDatabase(getDatabase().getDataSource()); + } catch (SQLException e) { + throw new IllegalStateException("Fail to truncate db tables", e); + } + } + + default IDataTypeFactory getDbUnitFactory() { + return getCommands().getDbUnitFactory(); + } +} diff --git a/server/sonar-db-dao/build.gradle b/server/sonar-db-dao/build.gradle index 0443ad91e38..18f3fefcfe8 100644 --- a/server/sonar-db-dao/build.gradle +++ b/server/sonar-db-dao/build.gradle @@ -21,6 +21,7 @@ dependencies { compileOnly 'com.google.code.findbugs:jsr305' + testCompile 'com.h2database:h2' testCompile 'com.tngtech.java:junit-dataprovider' testCompile 'junit:junit' testCompile 'org.assertj:assertj-core' diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DdlUtils.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DdlUtils.java new file mode 100644 index 00000000000..b3bf45b89ae --- /dev/null +++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DdlUtils.java @@ -0,0 +1,42 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.db; + +import java.sql.Connection; + +import static org.sonar.db.CoreDdlUtils.executeScript; + +public class DdlUtils { + + private DdlUtils() { + // prevents instantiation + } + + /** + * The connection is commited in this method but not closed. + */ + public static void createSchema(Connection connection, String dialect, boolean createSchemaMigrations) { + if (createSchemaMigrations) { + executeScript(connection, "org/sonar/db/schema_migrations-" + dialect + ".ddl"); + } + executeScript(connection, "org/sonar/db/schema-" + dialect + ".ddl"); + executeScript(connection, "org/sonar/db/rows-" + dialect + ".sql"); + } +} diff --git a/server/sonar-db-core/src/main/resources/org/sonar/db/version/rows-h2.sql b/server/sonar-db-dao/src/main/resources/org/sonar/db/rows-h2.sql similarity index 100% rename from server/sonar-db-core/src/main/resources/org/sonar/db/version/rows-h2.sql rename to server/sonar-db-dao/src/main/resources/org/sonar/db/rows-h2.sql diff --git a/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl b/server/sonar-db-dao/src/main/resources/org/sonar/db/schema-h2.ddl similarity index 100% rename from server/sonar-db-core/src/main/resources/org/sonar/db/version/schema-h2.ddl rename to server/sonar-db-dao/src/main/resources/org/sonar/db/schema-h2.ddl diff --git a/server/sonar-db-core/src/main/resources/org/sonar/db/version/schema_migrations-h2.ddl b/server/sonar-db-dao/src/main/resources/org/sonar/db/schema_migrations-h2.ddl similarity index 100% rename from server/sonar-db-core/src/main/resources/org/sonar/db/version/schema_migrations-h2.ddl rename to server/sonar-db-dao/src/main/resources/org/sonar/db/schema_migrations-h2.ddl diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/DbTester.java b/server/sonar-db-dao/src/test/java/org/sonar/db/DbTester.java index 930250b2943..52a064a1ac2 100644 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/DbTester.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/DbTester.java @@ -63,7 +63,7 @@ import static org.apache.commons.lang.RandomStringUtils.randomAlphanumeric; * This class should be called using @Rule. * Data is truncated between each tests. The schema is created between each test. */ -public class DbTester extends AbstractDbTester { +public class DbTester extends AbstractDbTester { private final System2 system2; private DbClient client; @@ -96,7 +96,7 @@ public class DbTester extends AbstractDbTester { private final InternalComponentPropertyDbTester internalComponentPropertyTester; private DbTester(System2 system2, @Nullable String schemaPath, MyBatisConfExtension... confExtensions) { - super(TestDb.create(schemaPath, confExtensions)); + super(TestDbImpl.create(schemaPath, confExtensions)); this.system2 = system2; initDbClient(); @@ -374,7 +374,7 @@ public class DbTester extends AbstractDbTester { } private static class DbTesterMyBatisConfExtension implements MyBatisConfExtension { - // do not replace with a lambda to allow cache of MyBatis instances in TestDb to work + // do not replace with a lambda to allow cache of MyBatis instances in TestDbImpl to work private final Class[] mapperClasses; public DbTesterMyBatisConfExtension(Class firstMapperClass, Class... otherMapperClasses) { diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/DdlUtilsTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/DdlUtilsTest.java similarity index 85% rename from server/sonar-db-core/src/test/java/org/sonar/db/DdlUtilsTest.java rename to server/sonar-db-dao/src/test/java/org/sonar/db/DdlUtilsTest.java index 4972d77be33..0423d6d46c3 100644 --- a/server/sonar-db-core/src/test/java/org/sonar/db/DdlUtilsTest.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/DdlUtilsTest.java @@ -24,25 +24,12 @@ import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import org.assertj.core.api.Assertions; import org.h2.Driver; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; import static org.assertj.core.api.Assertions.assertThat; public class DdlUtilsTest { - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void shouldSupportOnlyH2() { - Assertions.assertThat(DdlUtils.supportsDialect("h2")).isTrue(); - assertThat(DdlUtils.supportsDialect("postgresql")).isFalse(); - assertThat(DdlUtils.supportsDialect("oracle")).isFalse(); - assertThat(DdlUtils.supportsDialect("mssql")).isFalse(); - } @Test public void shouldCreateSchema_with_schema_migrations() throws SQLException { @@ -88,4 +75,5 @@ public class DdlUtilsTest { assertThat(resultSet.next()).isFalse(); } } + } diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/H2Database.java b/server/sonar-db-dao/src/test/java/org/sonar/db/H2Database.java similarity index 98% rename from server/sonar-db-core/src/test/java/org/sonar/db/H2Database.java rename to server/sonar-db-dao/src/test/java/org/sonar/db/H2Database.java index d6ab7c1bf6f..44bbaf93dfa 100644 --- a/server/sonar-db-core/src/test/java/org/sonar/db/H2Database.java +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/H2Database.java @@ -84,7 +84,7 @@ public class H2Database implements Database { Connection connection = null; try { connection = datasource.getConnection(); - DdlUtils.executeScript(connection, classloaderPath); + CoreDdlUtils.executeScript(connection, classloaderPath); } catch (SQLException e) { throw new IllegalStateException("Fail to execute script: " + classloaderPath, e); diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/H2DatabaseTest.java b/server/sonar-db-dao/src/test/java/org/sonar/db/H2DatabaseTest.java similarity index 100% rename from server/sonar-db-core/src/test/java/org/sonar/db/H2DatabaseTest.java rename to server/sonar-db-dao/src/test/java/org/sonar/db/H2DatabaseTest.java diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/TestDb.java b/server/sonar-db-dao/src/test/java/org/sonar/db/TestDb.java deleted file mode 100644 index cd04e022b3f..00000000000 --- a/server/sonar-db-dao/src/test/java/org/sonar/db/TestDb.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2019 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.db; - -import java.util.HashMap; -import java.util.Map; -import javax.annotation.Nullable; - -class TestDb extends CoreTestDb { - - private static TestDb defaultSchemaBaseTestDb; - // instantiating MyBatis objects is costly => we cache them for default schema - private static final Map defaultSchemaTestDbsWithExtensions = new HashMap<>(); - - private MyBatis myBatis; - - private TestDb(@Nullable String schemaPath, MyBatisConfExtension... confExtensions) { - super(); - init(schemaPath, (db, created) -> myBatis = newMyBatis(db, confExtensions)); - } - - private TestDb(TestDb base, MyBatis myBatis) { - super(base); - this.myBatis = myBatis; - } - - private static MyBatis newMyBatis(Database db, MyBatisConfExtension[] extensions) { - MyBatis newMyBatis = new MyBatis(db, extensions); - newMyBatis.start(); - return newMyBatis; - } - - static TestDb create(@Nullable String schemaPath, MyBatisConfExtension... confExtensions) { - MyBatisConfExtension[] extensionArray = confExtensions == null || confExtensions.length == 0 ? null : confExtensions; - if (schemaPath == null) { - if (defaultSchemaBaseTestDb == null) { - defaultSchemaBaseTestDb = new TestDb((String) null); - } - if (extensionArray != null) { - return defaultSchemaTestDbsWithExtensions.computeIfAbsent( - extensionArray, - extensions -> new TestDb(defaultSchemaBaseTestDb, newMyBatis(defaultSchemaBaseTestDb.getDatabase(), extensions))); - } - return defaultSchemaBaseTestDb; - } - return new TestDb(schemaPath, confExtensions); - } - - MyBatis getMyBatis() { - return myBatis; - } -} diff --git a/server/sonar-db-dao/src/test/java/org/sonar/db/TestDbImpl.java b/server/sonar-db-dao/src/test/java/org/sonar/db/TestDbImpl.java new file mode 100644 index 00000000000..e5ef68b7fcf --- /dev/null +++ b/server/sonar-db-dao/src/test/java/org/sonar/db/TestDbImpl.java @@ -0,0 +1,115 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 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.db; + +import java.util.HashMap; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.Function; +import javax.annotation.Nullable; +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.lang.StringUtils; +import org.junit.AssumptionViolatedException; +import org.sonar.api.config.Settings; +import org.sonar.db.dialect.H2; +import org.sonar.process.logging.LogbackHelper; + +class TestDbImpl extends CoreTestDb { + private static TestDbImpl defaultSchemaBaseTestDb; + // instantiating MyBatis objects is costly => we cache them for default schema + private static final Map defaultSchemaTestDbsWithExtensions = new HashMap<>(); + + private boolean isDefault; + private MyBatis myBatis; + + private TestDbImpl(@Nullable String schemaPath, MyBatisConfExtension... confExtensions) { + super(); + isDefault = (schemaPath == null); + init(schemaPath, confExtensions); + } + + private TestDbImpl(TestDbImpl base, MyBatis myBatis) { + super(base.getDatabase(), base.getCommands(), base.getDbUnitTester()); + this.isDefault = base.isDefault; + this.myBatis = myBatis; + } + + void init(@Nullable String schemaPath, MyBatisConfExtension[] confExtensions) { + Function databaseCreator = settings -> { + String dialect = settings.getString("sonar.jdbc.dialect"); + if (dialect != null && !"h2".equals(dialect)) { + return new DefaultDatabase(new LogbackHelper(), settings); + } + return new H2Database("h2Tests" + DigestUtils.md5Hex(StringUtils.defaultString(schemaPath)), schemaPath == null); + }; + Function schemaPathExecutor = database -> { + if (schemaPath != null) { + // will fail if not H2 + if (!database.getDialect().getId().equals("h2")) { + return false; + } + ((H2Database) database).executeScript(schemaPath); + } + return true; + }; + BiConsumer createMyBatis = (db, created) -> myBatis = newMyBatis(db, confExtensions); + init(databaseCreator, schemaPathExecutor, createMyBatis); + } + + private static MyBatis newMyBatis(Database db, MyBatisConfExtension[] extensions) { + MyBatis newMyBatis = new MyBatis(db, extensions); + newMyBatis.start(); + return newMyBatis; + } + + static TestDbImpl create(@Nullable String schemaPath, MyBatisConfExtension... confExtensions) { + MyBatisConfExtension[] extensionArray = confExtensions == null || confExtensions.length == 0 ? null : confExtensions; + if (schemaPath == null) { + if (defaultSchemaBaseTestDb == null) { + defaultSchemaBaseTestDb = new TestDbImpl((String) null); + } + if (extensionArray != null) { + return defaultSchemaTestDbsWithExtensions.computeIfAbsent( + extensionArray, + extensions -> new TestDbImpl(defaultSchemaBaseTestDb, newMyBatis(defaultSchemaBaseTestDb.getDatabase(), extensions))); + } + return defaultSchemaBaseTestDb; + } + return new TestDbImpl(schemaPath, confExtensions); + } + + @Override + public void start() { + if (!isDefault && !H2.ID.equals(getDatabase().getDialect().getId())) { + throw new AssumptionViolatedException("Test disabled because it supports only H2"); + } + } + + @Override + public void stop() { + if (!isDefault) { + super.stop(); + } + } + + MyBatis getMyBatis() { + return myBatis; + } +} 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 index bac37c6cefe..a54d45ec9e0 100644 --- 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 @@ -41,7 +41,7 @@ import static org.sonar.server.property.InternalProperties.INSTALLATION_DATE; import static org.sonar.server.property.InternalProperties.INSTALLATION_VERSION; /** - * FIXME fix this class to remove use of DdlUtils.createSchema + * FIXME fix this class to remove use of CoreDdlUtils.createSchema */ public class AutoDbMigration implements Startable { private final DefaultServerUpgradeStatus serverUpgradeStatus; -- 2.39.5