From 7b3b28511a7c7cef0622af1307ab08ed700a90b6 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Sun, 28 Oct 2018 23:02:10 +0100 Subject: [PATCH] SONARCLOUD-161 move db validations to Dialect#init() --- .../container/ComputeEngineContainerImpl.java | 4 +- .../ComputeEngineContainerImplTest.java | 2 +- .../java/org/sonar/db/DatabaseChecker.java | 106 ----------- .../java/org/sonar/db/DefaultDatabase.java | 1 + .../org/sonar/db/dialect/AbstractDialect.java | 15 ++ .../java/org/sonar/db/dialect/Dialect.java | 12 ++ .../main/java/org/sonar/db/dialect/H2.java | 6 + .../main/java/org/sonar/db/dialect/MsSql.java | 12 ++ .../main/java/org/sonar/db/dialect/MySql.java | 12 ++ .../java/org/sonar/db/dialect/Oracle.java | 22 +++ .../java/org/sonar/db/dialect/PostgreSql.java | 9 + .../org/sonar/db/DatabaseCheckerTest.java | 179 ------------------ .../java/org/sonar/db/dialect/H2Test.java | 15 ++ .../java/org/sonar/db/dialect/MsSqlTest.java | 33 ++++ .../java/org/sonar/db/dialect/MySqlTest.java | 44 +++++ .../java/org/sonar/db/dialect/OracleTest.java | 77 ++++++++ .../org/sonar/db/dialect/PostgreSqlTest.java | 34 ++++ .../platformlevel/PlatformLevel1.java | 2 - 18 files changed, 294 insertions(+), 291 deletions(-) delete mode 100644 server/sonar-db-core/src/main/java/org/sonar/db/DatabaseChecker.java delete mode 100644 server/sonar-db-core/src/test/java/org/sonar/db/DatabaseCheckerTest.java diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java index fa97df37480..c5948636384 100644 --- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java +++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java @@ -80,7 +80,6 @@ import org.sonar.core.timemachine.Periods; import org.sonar.core.util.UuidFactoryImpl; import org.sonar.db.DBSessionsImpl; import org.sonar.db.DaoModule; -import org.sonar.db.DatabaseChecker; import org.sonar.db.DbClient; import org.sonar.db.DefaultDatabase; import org.sonar.db.MyBatis; @@ -282,7 +281,6 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { WebServerImpl.class, LogbackHelper.class, DefaultDatabase.class, - DatabaseChecker.class, MyBatis.class, PurgeProfiler.class, ServerFileSystemImpl.class, @@ -481,7 +479,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { } private static Object[] startupComponents() { - return new Object[] { + return new Object[]{ ServerLifecycleNotifier.class, PurgeCeActivities.class, CeQueueCleaner.class diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java index 8f8551dc742..abc064e3142 100644 --- a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java +++ b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java @@ -120,7 +120,7 @@ public class ComputeEngineContainerImplTest { ); assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize( COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION - + 27 // level 1 + + 26 // level 1 + 57 // content of DaoModule + 3 // content of EsModule + 54 // content of CorePropertyDefinitions diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/DatabaseChecker.java b/server/sonar-db-core/src/main/java/org/sonar/db/DatabaseChecker.java deleted file mode 100644 index 4b510e29f4c..00000000000 --- a/server/sonar-db-core/src/main/java/org/sonar/db/DatabaseChecker.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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 com.google.common.base.Throwables; -import com.google.common.collect.ImmutableMap; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Map; -import org.apache.commons.lang.StringUtils; -import org.picocontainer.Startable; -import org.sonar.api.utils.MessageException; -import org.sonar.api.utils.Version; -import org.sonar.api.utils.log.Loggers; -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; - -/** - * Fail-fast checks of some database requirements - */ -public class DatabaseChecker implements Startable { - - private static final Map MINIMAL_SUPPORTED_DB_VERSIONS = ImmutableMap.of( - // MsSQL 2014 is 12.x - // https://support.microsoft.com/en-us/kb/321185 - MsSql.ID, Version.create(12, 0, 0), - MySql.ID, Version.create(5, 6, 0), - Oracle.ID, Version.create(11, 0, 0), - PostgreSql.ID, Version.create(9, 3, 0)); - - private final Database db; - - public DatabaseChecker(Database db) { - this.db = db; - } - - @Override - public void start() { - try { - checkMinDatabaseVersion(); - - // additional checks - if (H2.ID.equals(db.getDialect().getId())) { - Loggers.get(DatabaseChecker.class).warn("H2 database should be used for evaluation purpose only."); - } else if (MySql.ID.equals(db.getDialect().getId())) { - Loggers.get(DatabaseChecker.class).warn("MySQL support is deprecated and will be dropped soon."); - } else if (Oracle.ID.equals(db.getDialect().getId())) { - checkOracleDriverVersion(); - } - } catch (SQLException e) { - Throwables.propagate(e); - } - } - - @Override - public void stop() { - // nothing to do - } - - private void checkMinDatabaseVersion() throws SQLException { - Version minDbVersion = MINIMAL_SUPPORTED_DB_VERSIONS.get(db.getDialect().getId()); - if (minDbVersion != null) { - try (Connection connection = db.getDataSource().getConnection()) { - int dbMajorVersion = connection.getMetaData().getDatabaseMajorVersion(); - int dbMinorVersion = connection.getMetaData().getDatabaseMinorVersion(); - Version dbVersion = Version.create(dbMajorVersion, dbMinorVersion, 0); - if (dbVersion.compareTo(minDbVersion) < 0) { - throw MessageException.of(String.format( - "Unsupported %s version: %s. Minimal supported version is %s.", db.getDialect().getId(), dbVersion, minDbVersion)); - } - } - } - } - - private void checkOracleDriverVersion() throws SQLException { - try (Connection connection = db.getDataSource().getConnection()) { - String driverVersion = connection.getMetaData().getDriverVersion(); - String[] parts = StringUtils.split(driverVersion, "."); - int intVersion = Integer.parseInt(parts[0]) * 100 + Integer.parseInt(parts[1]); - if (intVersion < 1200) { - throw MessageException.of(String.format( - "Unsupported Oracle driver version: %s. Minimal supported version is 12.1.", driverVersion)); - } - } - } -} diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/DefaultDatabase.java b/server/sonar-db-core/src/main/java/org/sonar/db/DefaultDatabase.java index 59d8541fccc..92f3a93aae7 100644 --- a/server/sonar-db-core/src/main/java/org/sonar/db/DefaultDatabase.java +++ b/server/sonar-db-core/src/main/java/org/sonar/db/DefaultDatabase.java @@ -104,6 +104,7 @@ public class DefaultDatabase implements Database { Connection connection = null; try { connection = datasource.getConnection(); + dialect.init(connection.getMetaData()); } catch (SQLException e) { throw new IllegalStateException("Can not connect to database. Please check connectivity and settings (see the properties prefixed by 'sonar.jdbc.').", e); } finally { diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/dialect/AbstractDialect.java b/server/sonar-db-core/src/main/java/org/sonar/db/dialect/AbstractDialect.java index e31f1a81300..f4f738aa5de 100644 --- a/server/sonar-db-core/src/main/java/org/sonar/db/dialect/AbstractDialect.java +++ b/server/sonar-db-core/src/main/java/org/sonar/db/dialect/AbstractDialect.java @@ -19,8 +19,12 @@ */ package org.sonar.db.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; import java.util.Collections; import java.util.List; +import org.sonar.api.utils.MessageException; +import org.sonar.api.utils.Version; abstract class AbstractDialect implements Dialect { private final String id; @@ -82,4 +86,15 @@ abstract class AbstractDialect implements Dialect { public int getScrollSingleRowFetchSize() { return 1; } + + Version checkDbVersion(DatabaseMetaData metaData, Version minSupported) throws SQLException { + int major = metaData.getDatabaseMajorVersion(); + int minor = metaData.getDatabaseMinorVersion(); + Version version = Version.create(major, minor, 0); + if (version.compareTo(minSupported) < 0) { + throw MessageException.of(String.format( + "Unsupported %s version: %s. Minimal supported version is %s.", getId(), version, minSupported)); + } + return version; + } } diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/dialect/Dialect.java b/server/sonar-db-core/src/main/java/org/sonar/db/dialect/Dialect.java index 1a4c6707fcb..42278d51111 100644 --- a/server/sonar-db-core/src/main/java/org/sonar/db/dialect/Dialect.java +++ b/server/sonar-db-core/src/main/java/org/sonar/db/dialect/Dialect.java @@ -19,7 +19,10 @@ */ package org.sonar.db.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; import java.util.List; +import org.sonar.api.utils.MessageException; public interface Dialect { @@ -60,4 +63,13 @@ public interface Dialect { * Indicates whether DB migration can be perform on the DB vendor implementation associated with the current dialect. */ boolean supportsMigration(); + + /** + * This method is called when connecting for the first + * time to the database. + * + * @throws MessageException when validation error must be displayed to user + * @throws SQLException in case of error to run the validations + */ + void init(DatabaseMetaData metaData) throws SQLException; } diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/dialect/H2.java b/server/sonar-db-core/src/main/java/org/sonar/db/dialect/H2.java index 19451197ed2..f5ae1b9afe7 100644 --- a/server/sonar-db-core/src/main/java/org/sonar/db/dialect/H2.java +++ b/server/sonar-db-core/src/main/java/org/sonar/db/dialect/H2.java @@ -19,7 +19,9 @@ */ package org.sonar.db.dialect; +import java.sql.DatabaseMetaData; import org.apache.commons.lang.StringUtils; +import org.sonar.api.utils.log.Loggers; public class H2 extends AbstractDialect { @@ -39,4 +41,8 @@ public class H2 extends AbstractDialect { return false; } + @Override + public void init(DatabaseMetaData metaData) { + Loggers.get(getClass()).warn("H2 database should be used for evaluation purpose only."); + } } diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/dialect/MsSql.java b/server/sonar-db-core/src/main/java/org/sonar/db/dialect/MsSql.java index 416ac8cca35..759c2f350f3 100644 --- a/server/sonar-db-core/src/main/java/org/sonar/db/dialect/MsSql.java +++ b/server/sonar-db-core/src/main/java/org/sonar/db/dialect/MsSql.java @@ -19,11 +19,18 @@ */ package org.sonar.db.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; import org.apache.commons.lang.StringUtils; +import org.sonar.api.utils.Version; public class MsSql extends AbstractDialect { public static final String ID = "mssql"; + // SqlServer 2014 is 12.x + // https://support.microsoft.com/en-us/kb/321185 + private static final Version MIN_SUPPORTED_VERSION = Version.create(12, 0, 0); + public MsSql() { super(ID, "com.microsoft.sqlserver.jdbc.SQLServerDriver", "1", "0", "SELECT 1"); @@ -38,4 +45,9 @@ public class MsSql extends AbstractDialect { public boolean supportsMigration() { return true; } + + @Override + public void init(DatabaseMetaData metaData) throws SQLException { + checkDbVersion(metaData, MIN_SUPPORTED_VERSION); + } } diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/dialect/MySql.java b/server/sonar-db-core/src/main/java/org/sonar/db/dialect/MySql.java index cf0e4bcda9c..971725ccd18 100644 --- a/server/sonar-db-core/src/main/java/org/sonar/db/dialect/MySql.java +++ b/server/sonar-db-core/src/main/java/org/sonar/db/dialect/MySql.java @@ -19,11 +19,16 @@ */ package org.sonar.db.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; import org.apache.commons.lang.StringUtils; +import org.sonar.api.utils.Version; +import org.sonar.api.utils.log.Loggers; public class MySql extends AbstractDialect { public static final String ID = "mysql"; + private static final Version MIN_SUPPORTED_VERSION = Version.create(5, 6, 0); public MySql() { super(ID, "com.mysql.jdbc.Driver", "true", "false", "SELECT 1"); @@ -53,4 +58,11 @@ public class MySql extends AbstractDialect { public String getSqlFromDual() { return "from dual"; } + + @Override + public void init(DatabaseMetaData metaData) throws SQLException { + checkDbVersion(metaData, MIN_SUPPORTED_VERSION); + + Loggers.get(getClass()).warn("MySQL support is deprecated and will be dropped soon."); + } } diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/dialect/Oracle.java b/server/sonar-db-core/src/main/java/org/sonar/db/dialect/Oracle.java index 59a7e61a5f9..d150728c44d 100644 --- a/server/sonar-db-core/src/main/java/org/sonar/db/dialect/Oracle.java +++ b/server/sonar-db-core/src/main/java/org/sonar/db/dialect/Oracle.java @@ -20,13 +20,19 @@ package org.sonar.db.dialect; import com.google.common.collect.ImmutableList; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; import java.util.List; import org.apache.commons.lang.StringUtils; +import org.sonar.api.utils.MessageException; +import org.sonar.api.utils.Version; public class Oracle extends AbstractDialect { public static final String ID = "oracle"; private static final List INIT_STATEMENTS = ImmutableList.of("ALTER SESSION SET NLS_SORT='BINARY'"); + private static final Version MIN_SUPPORTED_VERSION = Version.create(11, 0, 0); + public Oracle() { super(ID, "oracle.jdbc.OracleDriver", "1", "0", "SELECT 1 FROM DUAL"); @@ -51,4 +57,20 @@ public class Oracle extends AbstractDialect { public String getSqlFromDual() { return "from dual"; } + + @Override + public void init(DatabaseMetaData metaData) throws SQLException { + checkDbVersion(metaData, MIN_SUPPORTED_VERSION); + checkDriverVersion(metaData); + } + + private static void checkDriverVersion(DatabaseMetaData metaData) throws SQLException { + String driverVersion = metaData.getDriverVersion(); + String[] parts = StringUtils.split(driverVersion, "."); + int intVersion = Integer.parseInt(parts[0]) * 100 + Integer.parseInt(parts[1]); + if (intVersion < 1200) { + throw MessageException.of(String.format( + "Unsupported Oracle driver version: %s. Minimal supported version is 12.1.", driverVersion)); + } + } } diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/dialect/PostgreSql.java b/server/sonar-db-core/src/main/java/org/sonar/db/dialect/PostgreSql.java index 9e19910575e..f80169aef21 100644 --- a/server/sonar-db-core/src/main/java/org/sonar/db/dialect/PostgreSql.java +++ b/server/sonar-db-core/src/main/java/org/sonar/db/dialect/PostgreSql.java @@ -20,13 +20,17 @@ package org.sonar.db.dialect; import com.google.common.collect.ImmutableList; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; import java.util.List; import org.apache.commons.lang.StringUtils; +import org.sonar.api.utils.Version; public class PostgreSql extends AbstractDialect { public static final String ID = "postgresql"; static final List INIT_STATEMENTS = ImmutableList.of("SET standard_conforming_strings=on", "SET backslash_quote=off"); + private static final Version MIN_SUPPORTED_VERSION = Version.create(9, 3, 0); public PostgreSql() { super(ID, "org.postgresql.Driver", "true", "false", "SELECT 1"); @@ -46,4 +50,9 @@ public class PostgreSql extends AbstractDialect { public boolean supportsMigration() { return true; } + + @Override + public void init(DatabaseMetaData metaData) throws SQLException { + checkDbVersion(metaData, MIN_SUPPORTED_VERSION); + } } diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/DatabaseCheckerTest.java b/server/sonar-db-core/src/test/java/org/sonar/db/DatabaseCheckerTest.java deleted file mode 100644 index abe98089ee5..00000000000 --- a/server/sonar-db-core/src/test/java/org/sonar/db/DatabaseCheckerTest.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; -import org.sonar.api.utils.MessageException; -import org.sonar.api.utils.log.LogTester; -import org.sonar.api.utils.log.LoggerLevel; -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 static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class DatabaseCheckerTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public LogTester logTester = new LogTester(); - - @Test - public void requires_oracle_driver_12_2() throws Exception { - Database db = mockDb(new Oracle(), 11, 2, "18.3.0.0.0"); - new DatabaseChecker(db).start(); - - db = mockDb(new Oracle(), 11, 2, "12.2.0.1.0"); - new DatabaseChecker(db).start(); - // no error - - db = mockDb(new Oracle(), 11, 2, "12.1.0.2.0"); - new DatabaseChecker(db).start(); - // no error - - db = mockDb(new Oracle(), 11, 2, "12.1.0.1.0"); - new DatabaseChecker(db).start(); - // no error - - db = mockDb(new Oracle(), 11, 2, "12.0.2"); - new DatabaseChecker(db).start(); - // no error - - db = mockDb(new Oracle(), 11, 2, "11.1.0.2"); - try { - new DatabaseChecker(db).start(); - fail(); - } catch (MessageException e) { - assertThat(e).hasMessage("Unsupported Oracle driver version: 11.1.0.2. Minimal supported version is 12.1."); - } - } - - @Test - public void requires_oracle_11g_or_greater() throws Exception { - // oracle 11.0 is ok - Database db = mockDb(new Oracle(), 11, 0, "12.1.0.1.0"); - new DatabaseChecker(db).start(); - - // oracle 11.1 is noit - db = mockDb(new Oracle(), 11, 1, "12.1.0.1.0"); - new DatabaseChecker(db).start(); - - // oracle 11.2 is ok - db = mockDb(new Oracle(), 11, 2, "12.1.0.1.0"); - new DatabaseChecker(db).start(); - - // oracle 12 is ok - db = mockDb(new Oracle(), 12, 0, "12.1.0.1.0"); - new DatabaseChecker(db).start(); - - // oracle 18 is ok - db = mockDb(new Oracle(), 18, 0, "18.3.0.0.0"); - new DatabaseChecker(db).start(); - - // oracle 10 is not supported - db = mockDb(new Oracle(), 10, 2, "12.1.0.1.0"); - try { - new DatabaseChecker(db).start(); - fail(); - } catch (MessageException e) { - assertThat(e).hasMessage("Unsupported oracle version: 10.2. Minimal supported version is 11.0."); - } - } - - @Test - public void log_warning_if_h2() throws Exception { - Database db = mockDb(new H2(), 13, 4, "13.4"); - DatabaseChecker checker = new DatabaseChecker(db); - checker.start(); - checker.stop(); - - assertThat(logTester.logs(LoggerLevel.WARN)).contains("H2 database should be used for evaluation purpose only."); - } - - @Test - public void test_mysql() throws Exception { - Database db = mockDb(new MySql(), 5, 7, "5.7"); - new DatabaseChecker(db).start(); - - // no error but warning - assertThat(logTester.logs(LoggerLevel.WARN)).contains("MySQL support is deprecated and will be dropped soon."); - } - - @Test - public void mssql_2012_is_not_supported() throws Exception { - expectedException.expect(MessageException.class); - expectedException.expectMessage("Unsupported mssql version: 11.0. Minimal supported version is 12.0."); - - Database db = mockDb(new MsSql(), 11, 0, "6.1"); - new DatabaseChecker(db).start(); - // no error - } - - @Test - public void mssql_2014_is_supported() throws Exception { - Database db = mockDb(new MsSql(), 12, 0, "6.1"); - new DatabaseChecker(db).start(); - // no error - } - - @Test - public void fail_if_mysql_less_than_5_6() throws Exception { - expectedException.expect(MessageException.class); - expectedException.expectMessage("Unsupported mysql version: 5.5. Minimal supported version is 5.6."); - - Database db = mockDb(new MySql(), 5, 5, "5.6"); - new DatabaseChecker(db).start(); - } - - @Test - public void fail_if_cant_get_db_version() throws Exception { - SQLException sqlException = new SQLException(); - Database db = mock(Database.class, Mockito.RETURNS_DEEP_STUBS); - when(db.getDialect()).thenReturn(new MySql()); - when(db.getDataSource().getConnection().getMetaData()).thenThrow(sqlException); - - try { - new DatabaseChecker(db).start(); - fail(); - } catch (RuntimeException e) { - assertThat(e.getCause()).isSameAs(sqlException); - } - } - - private Database mockDb(Dialect dialect, int dbMajorVersion, int dbMinorVersion, String driverVersion) throws SQLException { - Database db = mock(Database.class, Mockito.RETURNS_DEEP_STUBS); - when(db.getDialect()).thenReturn(dialect); - when(db.getDataSource().getConnection().getMetaData().getDatabaseMajorVersion()).thenReturn(dbMajorVersion); - when(db.getDataSource().getConnection().getMetaData().getDatabaseMinorVersion()).thenReturn(dbMinorVersion); - when(db.getDataSource().getConnection().getMetaData().getDriverVersion()).thenReturn(driverVersion); - return db; - } -} diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/dialect/H2Test.java b/server/sonar-db-core/src/test/java/org/sonar/db/dialect/H2Test.java index 1ed49200180..b208e97e984 100644 --- a/server/sonar-db-core/src/test/java/org/sonar/db/dialect/H2Test.java +++ b/server/sonar-db-core/src/test/java/org/sonar/db/dialect/H2Test.java @@ -19,12 +19,20 @@ */ package org.sonar.db.dialect; +import java.sql.DatabaseMetaData; +import org.junit.Rule; import org.junit.Test; +import org.sonar.api.utils.log.LogTester; +import org.sonar.api.utils.log.LoggerLevel; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; public class H2Test { + @Rule + public LogTester logs = new LogTester(); + private H2 underTest = new H2(); @Test @@ -60,4 +68,11 @@ public class H2Test { public void getSqlFromDual() { assertThat(underTest.getSqlFromDual()).isEqualTo(""); } + + @Test + public void init_logs_warning() { + underTest.init(mock(DatabaseMetaData.class)); + + assertThat(logs.logs(LoggerLevel.WARN)).contains("H2 database should be used for evaluation purpose only."); + } } diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/dialect/MsSqlTest.java b/server/sonar-db-core/src/test/java/org/sonar/db/dialect/MsSqlTest.java index 1f12cc186d7..ba4a9a5836f 100644 --- a/server/sonar-db-core/src/test/java/org/sonar/db/dialect/MsSqlTest.java +++ b/server/sonar-db-core/src/test/java/org/sonar/db/dialect/MsSqlTest.java @@ -19,12 +19,23 @@ */ package org.sonar.db.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; +import org.sonar.api.utils.MessageException; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class MsSqlTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + private MsSql underTest = new MsSql(); @Test @@ -63,4 +74,26 @@ public class MsSqlTest { public void getSqlFromDual() { assertThat(underTest.getSqlFromDual()).isEqualTo(""); } + + @Test + public void init_throws_MessageException_if_mssql_2012() throws Exception { + expectedException.expect(MessageException.class); + expectedException.expectMessage("Unsupported mssql version: 11.0. Minimal supported version is 12.0."); + + DatabaseMetaData metadata = newMetadata( 11, 0); + underTest.init(metadata); + } + + @Test + public void init_does_not_fail_if_mssql_2014() throws Exception { + DatabaseMetaData metadata = newMetadata( 12, 0); + underTest.init(metadata); + } + + private DatabaseMetaData newMetadata(int dbMajorVersion, int dbMinorVersion) throws SQLException { + DatabaseMetaData metadata = mock(DatabaseMetaData.class, Mockito.RETURNS_DEEP_STUBS); + when(metadata.getDatabaseMajorVersion()).thenReturn(dbMajorVersion); + when(metadata.getDatabaseMinorVersion()).thenReturn(dbMinorVersion); + return metadata; + } } diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/dialect/MySqlTest.java b/server/sonar-db-core/src/test/java/org/sonar/db/dialect/MySqlTest.java index 7ebc61f278d..de15828f258 100644 --- a/server/sonar-db-core/src/test/java/org/sonar/db/dialect/MySqlTest.java +++ b/server/sonar-db-core/src/test/java/org/sonar/db/dialect/MySqlTest.java @@ -19,12 +19,27 @@ */ package org.sonar.db.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; +import org.sonar.api.utils.MessageException; +import org.sonar.api.utils.log.LogTester; +import org.sonar.api.utils.log.LoggerLevel; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class MySqlTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public LogTester logs = new LogTester(); + private MySql underTest = new MySql(); @Test @@ -64,4 +79,33 @@ public class MySqlTest { public void getSqlFromDual() { assertThat(underTest.getSqlFromDual()).isEqualTo("from dual"); } + + @Test + public void init_throws_MessageException_if_mysql_5_5() throws Exception { + expectedException.expect(MessageException.class); + expectedException.expectMessage("Unsupported mysql version: 5.5. Minimal supported version is 5.6."); + + DatabaseMetaData metadata = newMetadata( 5, 5); + underTest.init(metadata); + } + + @Test + public void init_does_not_fail_if_mysql_5_6() throws Exception { + DatabaseMetaData metadata = newMetadata( 5, 6); + underTest.init(metadata); + } + + @Test + public void init_logs_warning() throws SQLException { + underTest.init(newMetadata(5, 6)); + + assertThat(logs.logs(LoggerLevel.WARN)).contains("MySQL support is deprecated and will be dropped soon."); + } + + private DatabaseMetaData newMetadata(int dbMajorVersion, int dbMinorVersion) throws SQLException { + DatabaseMetaData metadata = mock(DatabaseMetaData.class, Mockito.RETURNS_DEEP_STUBS); + when(metadata.getDatabaseMajorVersion()).thenReturn(dbMajorVersion); + when(metadata.getDatabaseMinorVersion()).thenReturn(dbMinorVersion); + return metadata; + } } diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/dialect/OracleTest.java b/server/sonar-db-core/src/test/java/org/sonar/db/dialect/OracleTest.java index 0f596b49a5e..e0725a0d0a0 100644 --- a/server/sonar-db-core/src/test/java/org/sonar/db/dialect/OracleTest.java +++ b/server/sonar-db-core/src/test/java/org/sonar/db/dialect/OracleTest.java @@ -19,9 +19,16 @@ */ package org.sonar.db.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; import org.junit.Test; +import org.mockito.Mockito; +import org.sonar.api.utils.MessageException; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class OracleTest { @@ -61,4 +68,74 @@ public class OracleTest { public void getSqlFromDual() { assertThat(underTest.getSqlFromDual()).isEqualTo("from dual"); } + + @Test + public void test_db_versions() throws Exception { + // oracle 11.0 is ok + DatabaseMetaData metadata = newMetadata( 11, 0, "12.1.0.1.0"); + underTest.init(metadata); + + // oracle 11.1 is noit + metadata = newMetadata(11, 1, "12.1.0.1.0"); + underTest.init(metadata); + + // oracle 11.2 is ok + metadata = newMetadata(11, 2, "12.1.0.1.0"); + underTest.init(metadata); + + // oracle 12 is ok + metadata = newMetadata(12, 0, "12.1.0.1.0"); + underTest.init(metadata); + + // oracle 18 is ok + metadata = newMetadata(18, 0, "18.3.0.0.0"); + underTest.init(metadata); + + // oracle 10 is not supported + metadata = newMetadata(10, 2, "12.1.0.1.0"); + try { + underTest.init(metadata); + fail(); + } catch (MessageException e) { + assertThat(e).hasMessage("Unsupported oracle version: 10.2. Minimal supported version is 11.0."); + } + } + + @Test + public void test_driver_versions() throws Exception { + DatabaseMetaData metadata = newMetadata( 11, 2, "18.3.0.0.0"); + underTest.init(metadata); + + metadata = newMetadata(11, 2, "12.2.0.1.0"); + underTest.init(metadata); + // no error + + metadata = newMetadata(11, 2, "12.1.0.2.0"); + underTest.init(metadata); + // no error + + metadata = newMetadata(11, 2, "12.1.0.1.0"); + underTest.init(metadata); + // no error + + metadata = newMetadata(11, 2, "12.0.2"); + underTest.init(metadata); + // no error + + metadata = newMetadata(11, 2, "11.1.0.2"); + try { + underTest.init(metadata); + fail(); + } catch (MessageException e) { + assertThat(e).hasMessage("Unsupported Oracle driver version: 11.1.0.2. Minimal supported version is 12.1."); + } + } + + private DatabaseMetaData newMetadata(int dbMajorVersion, int dbMinorVersion, String driverVersion) throws SQLException { + DatabaseMetaData metadata = mock(DatabaseMetaData.class, Mockito.RETURNS_DEEP_STUBS); + when(metadata.getDatabaseMajorVersion()).thenReturn(dbMajorVersion); + when(metadata.getDatabaseMinorVersion()).thenReturn(dbMinorVersion); + when(metadata.getDriverVersion()).thenReturn(driverVersion); + return metadata; + } } diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/dialect/PostgreSqlTest.java b/server/sonar-db-core/src/test/java/org/sonar/db/dialect/PostgreSqlTest.java index f0b9576ee4e..3e1b7b065a4 100644 --- a/server/sonar-db-core/src/test/java/org/sonar/db/dialect/PostgreSqlTest.java +++ b/server/sonar-db-core/src/test/java/org/sonar/db/dialect/PostgreSqlTest.java @@ -19,12 +19,23 @@ */ package org.sonar.db.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; +import org.sonar.api.utils.MessageException; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class PostgreSqlTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + private PostgreSql underTest = new PostgreSql(); @Test @@ -65,4 +76,27 @@ public class PostgreSqlTest { public void getSqlFromDual() { assertThat(underTest.getSqlFromDual()).isEqualTo(""); } + + @Test + public void init_throws_MessageException_if_postgresql_9_2() throws Exception { + expectedException.expect(MessageException.class); + expectedException.expectMessage("Unsupported postgresql version: 9.2. Minimal supported version is 9.3."); + + DatabaseMetaData metadata = newMetadata( 9, 2); + underTest.init(metadata); + } + + @Test + public void init_does_not_fail_if_postgresql_9_3() throws Exception { + DatabaseMetaData metadata = newMetadata( 9, 3); + underTest.init(metadata); + } + + private DatabaseMetaData newMetadata(int dbMajorVersion, int dbMinorVersion) throws SQLException { + DatabaseMetaData metadata = mock(DatabaseMetaData.class, Mockito.RETURNS_DEEP_STUBS); + when(metadata.getDatabaseMajorVersion()).thenReturn(dbMajorVersion); + when(metadata.getDatabaseMinorVersion()).thenReturn(dbMinorVersion); + return metadata; + } + } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java index 1a33812cd88..5a0beee044d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel1.java @@ -35,7 +35,6 @@ import org.sonar.core.extension.CoreExtensionsLoader; import org.sonar.core.util.UuidFactoryImpl; import org.sonar.db.DBSessionsImpl; import org.sonar.db.DaoModule; -import org.sonar.db.DatabaseChecker; import org.sonar.db.DbClient; import org.sonar.db.DefaultDatabase; import org.sonar.db.MyBatis; @@ -99,7 +98,6 @@ public class PlatformLevel1 extends PlatformLevel { LogbackHelper.class, WebServerProcessLogging.class, DefaultDatabase.class, - DatabaseChecker.class, MyBatis.class, PurgeProfiler.class, ServerFileSystemImpl.class, -- 2.39.5