diff options
-rw-r--r-- | sonar-db/src/main/java/org/sonar/db/DatabaseChecker.java | 74 | ||||
-rw-r--r-- | sonar-db/src/test/java/org/sonar/db/DatabaseCheckerTest.java | 63 |
2 files changed, 101 insertions, 36 deletions
diff --git a/sonar-db/src/main/java/org/sonar/db/DatabaseChecker.java b/sonar-db/src/main/java/org/sonar/db/DatabaseChecker.java index 1e74532700d..eb436a8a155 100644 --- a/sonar-db/src/main/java/org/sonar/db/DatabaseChecker.java +++ b/sonar-db/src/main/java/org/sonar/db/DatabaseChecker.java @@ -20,19 +20,34 @@ 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 org.apache.commons.dbutils.DbUtils; +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.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 { - public static final int ORACLE_MIN_MAJOR_VERSION = 11; + private static final Map<String, Version> MINIMAL_SUPPORTED_DB_VERSIONS = ImmutableMap.of( + // MsSQL 2008 is 10.x + // MsSQL 2012 is 11.x + // MsSQL 2014 is 12.x + // https://support.microsoft.com/en-us/kb/321185 + MsSql.ID, new Version(10, 0), + MySql.ID, new Version(5, 6), + Oracle.ID, new Version(11, 0), + PostgreSql.ID, new Version(8, 0)); private final Database db; @@ -43,12 +58,15 @@ public class DatabaseChecker implements Startable { @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 (Oracle.ID.equals(db.getDialect().getId())) { - checkOracleVersion(); + checkOracleDriverVersion(); } - } catch (Exception e) { + } catch (SQLException e) { Throwables.propagate(e); } } @@ -58,29 +76,49 @@ public class DatabaseChecker implements Startable { // nothing to do } - private void checkOracleVersion() throws SQLException { - Connection connection = db.getDataSource().getConnection(); - try { - // check version of db - // See http://jira.sonarsource.com/browse/SONAR-6434 - int majorVersion = connection.getMetaData().getDatabaseMajorVersion(); - if (majorVersion < ORACLE_MIN_MAJOR_VERSION) { - throw MessageException.of(String.format( - "Unsupported Oracle version: %s. Minimal required version is %d.", connection.getMetaData().getDatabaseProductVersion(), ORACLE_MIN_MAJOR_VERSION)); + 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 = new Version(dbMajorVersion, dbMinorVersion); + if (!dbVersion.isGreaterThanOrEqual(minDbVersion)) { + throw MessageException.of(String.format( + "Unsupported %s version: %s. Minimal supported version is %s.", db.getDialect().getId(), dbVersion, minDbVersion)); + } } + } + } - // check version of driver + 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 < 1102) { throw MessageException.of(String.format( - "Unsupported Oracle JDBC driver version: %s. Minimal required version is 11.2.", driverVersion)); + "Unsupported Oracle driver version: %s. Minimal supported version is 11.2.", driverVersion)); } - - } finally { - DbUtils.closeQuietly(connection); } } + private static class Version { + private final int major; + private final int minor; + + public Version(int major, int minor) { + this.major = major; + this.minor = minor; + } + + public boolean isGreaterThanOrEqual(Version other) { + return major >= other.major && (major != other.major || minor >= other.minor); + } + + @Override + public String toString() { + return new StringBuilder().append(major).append(".").append(minor).toString(); + } + } } diff --git a/sonar-db/src/test/java/org/sonar/db/DatabaseCheckerTest.java b/sonar-db/src/test/java/org/sonar/db/DatabaseCheckerTest.java index 3b09f853c60..59ffa7f3af8 100644 --- a/sonar-db/src/test/java/org/sonar/db/DatabaseCheckerTest.java +++ b/sonar-db/src/test/java/org/sonar/db/DatabaseCheckerTest.java @@ -20,8 +20,9 @@ package org.sonar.db; import java.sql.SQLException; -import org.apache.commons.lang.StringUtils; +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.db.dialect.Dialect; @@ -30,66 +31,70 @@ import org.sonar.db.dialect.MySql; import org.sonar.db.dialect.Oracle; import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.is; 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(); + @Test public void requires_oracle_driver_11_2() throws Exception { - Database db = mockDb(new Oracle(), "11.2.1", "11.2.0.0.1"); + Database db = mockDb(new Oracle(), 11, 2, "11.2.0.0.1"); new DatabaseChecker(db).start(); // no error - db = mockDb(new Oracle(), "11.2.1", "11.3.1"); + db = mockDb(new Oracle(), 11, 2, "11.3.1"); new DatabaseChecker(db).start(); // no error - db = mockDb(new Oracle(), "11.2.1", "12.0.2"); + db = mockDb(new Oracle(), 11, 2, "12.0.2"); new DatabaseChecker(db).start(); // no error - db = mockDb(new Oracle(), "11.2.1", "11.1.0.2"); + db = mockDb(new Oracle(), 11, 2, "11.1.0.2"); try { new DatabaseChecker(db).start(); fail(); } catch (MessageException e) { - assertThat(e).hasMessage("Unsupported Oracle JDBC driver version: 11.1.0.2. Minimal required version is 11.2."); + assertThat(e).hasMessage("Unsupported Oracle driver version: 11.1.0.2. Minimal supported version is 11.2."); } } @Test public void requires_oracle_11g_or_greater() throws Exception { // oracle 11.0 is ok - Database db = mockDb(new Oracle(), "11.0.1", "11.2.0.0.1"); + Database db = mockDb(new Oracle(), 11, 0, "11.2.0.0.1"); new DatabaseChecker(db).start(); // oracle 11.1 is ok - db = mockDb(new Oracle(), "11.1.1", "11.2.0.0.1"); + db = mockDb(new Oracle(), 11, 1, "11.2.0.0.1"); new DatabaseChecker(db).start(); // oracle 11.2 is ok - db = mockDb(new Oracle(), "11.2.1", "11.2.0.0.1"); + db = mockDb(new Oracle(), 11, 2, "11.2.0.0.1"); new DatabaseChecker(db).start(); // oracle 12 is ok - db = mockDb(new Oracle(), "12.0.1", "11.2.0.0.1"); + db = mockDb(new Oracle(), 12, 0, "11.2.0.0.1"); new DatabaseChecker(db).start(); // oracle 10 is not supported - db = mockDb(new Oracle(), "10.2.1", "11.2.0.0.1"); + db = mockDb(new Oracle(), 10, 2, "11.2.0.0.1"); try { new DatabaseChecker(db).start(); fail(); } catch (MessageException e) { - assertThat(e).hasMessage("Unsupported Oracle version: 10.2.1. Minimal required version is 11."); + 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"); + Database db = mockDb(new H2(), 13, 4, "13.4"); DatabaseChecker checker = new DatabaseChecker(db); checker.start(); checker.stop(); @@ -97,17 +102,39 @@ public class DatabaseCheckerTest { } @Test - public void do_not_fail_if_mysql() throws Exception { - Database db = mockDb(new MySql(), "5.7", "5.7"); + public void test_mysql() throws Exception { + Database db = mockDb(new MySql(), 5, 7, "5.7"); new DatabaseChecker(db).start(); // no error } - private Database mockDb(Dialect dialect, String dbVersion, String driverVersion) throws SQLException { + @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(); + expectedException.expect(RuntimeException.class); + expectedException.expectCause(is(sqlException)); + + Database db = mock(Database.class, Mockito.RETURNS_DEEP_STUBS); + when(db.getDialect()).thenReturn(new MySql()); + when(db.getDataSource().getConnection().getMetaData()).thenThrow(sqlException); + + new DatabaseChecker(db).start(); + } + + 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(Integer.parseInt(StringUtils.substringBefore(dbVersion, "."))); - when(db.getDataSource().getConnection().getMetaData().getDatabaseProductVersion()).thenReturn(dbVersion); + 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; } |