From fbc90a2c18e3369df541dcae5ee5d6425c4de7a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sondre=20Eikanger=20Kval=C3=B8?= Date: Wed, 2 May 2018 15:16:33 +0200 Subject: [PATCH] HSQLDB ftw :-) --- ...nitializerDefaultSettingsHypersqlTest.java | 32 +++++++ .../FlywayInitializerDefaultSettingsTest.java | 2 +- ...1_0_0__Create_tables_for_user_and_role.sql | 2 +- .../junit/db/plugin/LiquibaseInitializer.java | 49 ++++++++--- .../LiquibaseInitializerWithContextTest.java | 26 ++---- ...InitializerWithSchemaNameHyperSQLTest.java | 39 +++++++++ ...iquibaseInitializerWithoutContextTest.java | 13 +-- .../zapodot/junit/db/plugin/dao/RoleDao.java | 30 +++++++ .../junit/db/EmbeddedDatabaseRule.java | 67 ++++++++++++--- .../junit/db/internal/H2JdbcUrlFactory.java | 49 ++++++----- .../db/internal/HyperSqlJdbcUrlFactory.java | 56 ++++++++++++ .../junit/db/internal/JdbcUrlFactory.java | 20 +++++ .../db/EmbeddedDatabaseRuleHsqlTest.java | 39 +++++++++ .../db/internal/H2JdbcUrlFactoryTest.java | 52 ++++------- .../internal/HyperSqlJdbcUrlFactoryTest.java | 86 +++++++++++++++++++ .../internal/SQLInitializationPluginTest.java | 44 ++++++++++ 16 files changed, 495 insertions(+), 111 deletions(-) create mode 100644 embedded-db-flyway/src/test/java/org/zapodot/junit/db/plugin/FlywayInitializerDefaultSettingsHypersqlTest.java create mode 100644 embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/LiquibaseInitializerWithSchemaNameHyperSQLTest.java create mode 100644 embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/dao/RoleDao.java create mode 100644 embedded-db-junit/src/main/java/org/zapodot/junit/db/internal/HyperSqlJdbcUrlFactory.java create mode 100644 embedded-db-junit/src/test/java/org/zapodot/junit/db/EmbeddedDatabaseRuleHsqlTest.java create mode 100644 embedded-db-junit/src/test/java/org/zapodot/junit/db/internal/HyperSqlJdbcUrlFactoryTest.java create mode 100644 embedded-db-junit/src/test/java/org/zapodot/junit/db/internal/SQLInitializationPluginTest.java diff --git a/embedded-db-flyway/src/test/java/org/zapodot/junit/db/plugin/FlywayInitializerDefaultSettingsHypersqlTest.java b/embedded-db-flyway/src/test/java/org/zapodot/junit/db/plugin/FlywayInitializerDefaultSettingsHypersqlTest.java new file mode 100644 index 0000000..7494f62 --- /dev/null +++ b/embedded-db-flyway/src/test/java/org/zapodot/junit/db/plugin/FlywayInitializerDefaultSettingsHypersqlTest.java @@ -0,0 +1,32 @@ +package org.zapodot.junit.db.plugin; + +import org.junit.Rule; +import org.junit.Test; +import org.zapodot.junit.db.EmbeddedDatabaseRule; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; + +import static org.junit.Assert.*; + +public class FlywayInitializerDefaultSettingsHypersqlTest { + + @Rule + public final EmbeddedDatabaseRule embeddedDatabaseRule = EmbeddedDatabaseRule.hsqldb() + .initializedByPlugin( + new FlywayInitializer.Builder() + .withLocations( + "classpath:migrations/") + .build()).build(); + + + @Test + public void checkMigrationsHasRun() throws Exception { + try (final Connection connection = embeddedDatabaseRule.getConnection(); + final Statement statement = connection.createStatement(); + final ResultSet resultSet = statement.executeQuery("SELECT * FROM USER")) { + assertTrue(resultSet.next()); + } + } +} \ No newline at end of file diff --git a/embedded-db-flyway/src/test/java/org/zapodot/junit/db/plugin/FlywayInitializerDefaultSettingsTest.java b/embedded-db-flyway/src/test/java/org/zapodot/junit/db/plugin/FlywayInitializerDefaultSettingsTest.java index 5455992..4f4f05a 100644 --- a/embedded-db-flyway/src/test/java/org/zapodot/junit/db/plugin/FlywayInitializerDefaultSettingsTest.java +++ b/embedded-db-flyway/src/test/java/org/zapodot/junit/db/plugin/FlywayInitializerDefaultSettingsTest.java @@ -13,7 +13,7 @@ public class FlywayInitializerDefaultSettingsTest { @Rule - public final EmbeddedDatabaseRule embeddedDatabaseRule = EmbeddedDatabaseRule.builder() + public final EmbeddedDatabaseRule embeddedDatabaseRule = EmbeddedDatabaseRule.h2() .initializedByPlugin( new FlywayInitializer.Builder() .withLocations( diff --git a/embedded-db-flyway/src/test/resources/migrations/V1_0_0__Create_tables_for_user_and_role.sql b/embedded-db-flyway/src/test/resources/migrations/V1_0_0__Create_tables_for_user_and_role.sql index 5a7f74e..680c3c6 100644 --- a/embedded-db-flyway/src/test/resources/migrations/V1_0_0__Create_tables_for_user_and_role.sql +++ b/embedded-db-flyway/src/test/resources/migrations/V1_0_0__Create_tables_for_user_and_role.sql @@ -1,7 +1,7 @@ CREATE TABLE User ( id INT IDENTITY PRIMARY KEY, name VARCHAR(255), - created TIMESTAMP NOT NULL DEFAULT (CURRENT_TIMESTAMP) + created TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE Role ( id INT IDENTITY PRIMARY KEY, diff --git a/embedded-db-junit-liquibase/src/main/java/org/zapodot/junit/db/plugin/LiquibaseInitializer.java b/embedded-db-junit-liquibase/src/main/java/org/zapodot/junit/db/plugin/LiquibaseInitializer.java index 430061e..3c1e269 100644 --- a/embedded-db-junit-liquibase/src/main/java/org/zapodot/junit/db/plugin/LiquibaseInitializer.java +++ b/embedded-db-junit-liquibase/src/main/java/org/zapodot/junit/db/plugin/LiquibaseInitializer.java @@ -3,14 +3,18 @@ import liquibase.Contexts; import liquibase.LabelExpression; import liquibase.Liquibase; +import liquibase.database.Database; +import liquibase.database.DatabaseFactory; import liquibase.database.core.H2Database; import liquibase.database.jvm.JdbcConnection; +import liquibase.exception.DatabaseException; import liquibase.exception.LiquibaseException; import liquibase.resource.ClassLoaderResourceAccessor; import liquibase.resource.ResourceAccessor; import java.io.IOException; import java.sql.Connection; +import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Arrays; import java.util.LinkedList; @@ -24,20 +28,32 @@ public class LiquibaseInitializer implements InitializationPlugin { private final Contexts contexts; + private final LabelExpression labelExpression; + private final String changeLog; + private final ResourceAccessor resourceAccessor; + private final Integer changesLimit; + private final boolean addDbNameToContext; + private final String defaultSchemaName; public static class Builder { private String databaseChangeLog; + private ResourceAccessor resourceAccessor; + private List contexts = new LinkedList<>(); + private List labels = new LinkedList<>(); + private Integer changesToApply; + private boolean addNameToContext = false; + private String defaultSchemaName; public Builder() { @@ -57,6 +73,7 @@ public Builder withChangelogResource(final String resource) { /** * Limit the number of changes in the changelog to be applied + * * @param limit the number of changes * @return the same builder */ @@ -120,14 +137,19 @@ public Builder withDefaultSchemaName(String schemaName) { */ public LiquibaseInitializer build() { if (databaseChangeLog == null) { - throw new IllegalArgumentException("You must provide a changelog file to the LiquibaseIntitializer Plugin builder"); + throw new IllegalArgumentException( + "You must provide a changelog file to the LiquibaseIntitializer Plugin builder"); } try { - if(resourceAccessor.getResourcesAsStream(databaseChangeLog) == null) { - throw new IllegalArgumentException(String.format("Can not load changelog from resource \"%s\". Does it exist?", databaseChangeLog)); + if (resourceAccessor.getResourcesAsStream(databaseChangeLog) == null) { + throw new IllegalArgumentException(String.format( + "Can not load changelog from resource \"%s\". Does it exist?", + databaseChangeLog)); } } catch (IOException e) { - throw new IllegalArgumentException(String.format("An IO exception occurred while loading changelog from resource \"%s\"", databaseChangeLog), e); + throw new IllegalArgumentException(String.format( + "An IO exception occurred while loading changelog from resource \"%s\"", + databaseChangeLog), e); } return new LiquibaseInitializer(createContexts(), createLabels(), databaseChangeLog, resourceAccessor, changesToApply, addNameToContext, @@ -163,10 +185,9 @@ private LiquibaseInitializer(final Contexts contexts, @Override public void connectionMade(final String name, final Connection connection) { if (defaultSchemaName != null) { - try { - connection.prepareStatement( - String.format("CREATE SCHEMA IF NOT EXISTS %s", defaultSchemaName)) - .execute(); + try (final PreparedStatement preparedStatement = connection.prepareStatement( + String.format("CREATE SCHEMA IF NOT EXISTS %s", defaultSchemaName))) { + preparedStatement.execute(); } catch (SQLException e) { throw new RuntimeException(e); } @@ -190,17 +211,21 @@ public void connectionMade(final String name, final Connection connection) { private Liquibase createLiquibase(final Connection connection) { try { JdbcConnection conn = new JdbcConnection(connection); - H2Database h2Database = new H2Database(); - h2Database.setConnection(conn); + Database database = resolveDatabase(connection); + database.setConnection(conn); if (defaultSchemaName != null) { - h2Database.setDefaultSchemaName(defaultSchemaName); + database.setDefaultSchemaName(defaultSchemaName); } - return new Liquibase(changeLog, resourceAccessor, h2Database); + return new Liquibase(changeLog, resourceAccessor, database); } catch (LiquibaseException e) { throw new RuntimeException("Could not initialize Liquibase", e); } } + private final Database resolveDatabase(final Connection connection) throws DatabaseException { + return DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection)); + } + /** * Creates a builder for providing parameters for Liquibase to be run * diff --git a/embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/LiquibaseInitializerWithContextTest.java b/embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/LiquibaseInitializerWithContextTest.java index 0e2b9fc..ac1e60d 100644 --- a/embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/LiquibaseInitializerWithContextTest.java +++ b/embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/LiquibaseInitializerWithContextTest.java @@ -3,14 +3,12 @@ import org.junit.Rule; import org.junit.Test; import org.zapodot.junit.db.EmbeddedDatabaseRule; +import org.zapodot.junit.db.plugin.dao.RoleDao; import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.util.LinkedList; import java.util.List; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; /** * @author zapodot @@ -22,24 +20,16 @@ public class LiquibaseInitializerWithContextTest { .builder() .withMode(EmbeddedDatabaseRule.CompatibilityMode.MSSQLServer) .initializedByPlugin(LiquibaseInitializer.builder() - .withChangelogResource("example-changelog.sql") - .withContexts("addUsersAndRoles") - .build()) + .withChangelogResource("example-changelog.sql") + .withContexts("addUsersAndRoles") + .build()) .build(); @Test public void testFindRolesInsertedByLiquibase() throws Exception { - try(final Connection connection = embeddedDatabaseRule.getConnection()) { - try(final PreparedStatement statement = connection.prepareStatement("Select * FROM ROLE r INNER JOIN USERROLE ur on r.ID = ur.ROLE_ID INNER JOIN USER u on ur.USER_ID = u.ID where u.NAME = ?")) { - statement.setString(1, "Ada"); - try(final ResultSet resultSet = statement.executeQuery()) { - final List roles = new LinkedList<>(); - while(resultSet.next()) { - roles.add(resultSet.getString("name")); - } - assertEquals(2, roles.size()); - } - } + try (final Connection connection = embeddedDatabaseRule.getConnection()) { + final List roles = new RoleDao(connection).rolesForUser("Ada"); + assertEquals(2, roles.size()); } } diff --git a/embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/LiquibaseInitializerWithSchemaNameHyperSQLTest.java b/embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/LiquibaseInitializerWithSchemaNameHyperSQLTest.java new file mode 100644 index 0000000..cbe6552 --- /dev/null +++ b/embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/LiquibaseInitializerWithSchemaNameHyperSQLTest.java @@ -0,0 +1,39 @@ +package org.zapodot.junit.db.plugin; + +import org.junit.Rule; +import org.junit.Test; +import org.zapodot.junit.db.EmbeddedDatabaseRule; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import static org.junit.Assert.*; + +/** + * @author zapodot + */ +public class LiquibaseInitializerWithSchemaNameHyperSQLTest { + + @Rule + public final EmbeddedDatabaseRule embeddedDatabaseRule = EmbeddedDatabaseRule + .hsqldb() + .withMode(EmbeddedDatabaseRule.CompatibilityMode.MSSQLServer) + .initializedByPlugin(LiquibaseInitializer.builder() + .withChangelogResource("example-changelog.xml") + .withDefaultSchemaName("some_schema_name") + .build()) + .build(); + + @Test + public void testFindUserTable() throws Exception { + try (final Connection connection = embeddedDatabaseRule.getConnection(); + final PreparedStatement preparedStatement = connection + .prepareStatement("SELECT * FROM some_schema_name.USER"); + final ResultSet resultSet = preparedStatement.executeQuery() + ) { + assertFalse(resultSet.next()); + } + + } +} \ No newline at end of file diff --git a/embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/LiquibaseInitializerWithoutContextTest.java b/embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/LiquibaseInitializerWithoutContextTest.java index 7d21635..471f704 100644 --- a/embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/LiquibaseInitializerWithoutContextTest.java +++ b/embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/LiquibaseInitializerWithoutContextTest.java @@ -3,6 +3,7 @@ import org.junit.Rule; import org.junit.Test; import org.zapodot.junit.db.EmbeddedDatabaseRule; +import org.zapodot.junit.db.plugin.dao.RoleDao; import java.sql.Connection; import java.sql.PreparedStatement; @@ -29,16 +30,8 @@ public class LiquibaseInitializerWithoutContextTest { @Test public void testFindRolesInsertedByLiquibase() throws Exception { try(final Connection connection = embeddedDatabaseRule.getConnection()) { - try(final PreparedStatement statement = connection.prepareStatement("Select * FROM ROLE r INNER JOIN USERROLE ur on r.ID = ur.ROLE_ID INNER JOIN USER u on ur.USER_ID = u.ID where u.NAME = ?")) { - statement.setString(1, "Ada"); - try(final ResultSet resultSet = statement.executeQuery()) { - final List roles = new LinkedList<>(); - while(resultSet.next()) { - roles.add(resultSet.getString("name")); - } - assertEquals(2, roles.size()); - } - } + final List roles = new RoleDao(connection).rolesForUser("Ada"); + assertEquals(2, roles.size()); } } diff --git a/embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/dao/RoleDao.java b/embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/dao/RoleDao.java new file mode 100644 index 0000000..280a800 --- /dev/null +++ b/embedded-db-junit-liquibase/src/test/java/org/zapodot/junit/db/plugin/dao/RoleDao.java @@ -0,0 +1,30 @@ +package org.zapodot.junit.db.plugin.dao; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; + +public class RoleDao { + + private final Connection connection; + + public RoleDao(final Connection connection) { + this.connection = connection; + } + + public List rolesForUser(final String userName) throws SQLException { + try(final PreparedStatement statement = connection.prepareStatement("Select * FROM ROLE r INNER JOIN USERROLE ur on r.ID = ur.ROLE_ID INNER JOIN USER u on ur.USER_ID = u.ID where u.NAME = ?")) { + statement.setString(1, userName); + try(final ResultSet resultSet = statement.executeQuery()) { + final List roles = new LinkedList<>(); + while(resultSet.next()) { + roles.add(resultSet.getString("name")); + } + return roles; + } + } + } +} diff --git a/embedded-db-junit/src/main/java/org/zapodot/junit/db/EmbeddedDatabaseRule.java b/embedded-db-junit/src/main/java/org/zapodot/junit/db/EmbeddedDatabaseRule.java index 43d214f..322743b 100755 --- a/embedded-db-junit/src/main/java/org/zapodot/junit/db/EmbeddedDatabaseRule.java +++ b/embedded-db-junit/src/main/java/org/zapodot/junit/db/EmbeddedDatabaseRule.java @@ -10,6 +10,8 @@ import org.zapodot.junit.db.internal.EmbeddedDataSource; import org.zapodot.junit.db.internal.FilePathInitializationPlugin; import org.zapodot.junit.db.internal.H2JdbcUrlFactory; +import org.zapodot.junit.db.internal.HyperSqlJdbcUrlFactory; +import org.zapodot.junit.db.internal.JdbcUrlFactory; import org.zapodot.junit.db.internal.SQLInitializationPlugin; import org.zapodot.junit.db.plugin.InitializationPlugin; @@ -19,6 +21,7 @@ import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; +import java.util.Arrays; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; @@ -30,10 +33,6 @@ */ public class EmbeddedDatabaseRule implements TestRule { - public static final String PROP_INIT_SQL = "INIT"; - - public static final String PROP_MODE = "MODE"; - private final boolean autoCommit; private final String predefinedName; @@ -46,24 +45,32 @@ public class EmbeddedDatabaseRule implements TestRule { private final Map, InitializationPlugin> initializationPlugins; + private final JdbcUrlFactory jdbcUrlFactory; + + private final CompatibilityMode compatibilityMode; + private Connection connection; /** * Standard constructor that is suitable if you don't need to do anything special */ public EmbeddedDatabaseRule() { - this(true, null, null, null); + this(true, null, null, null, null, CompatibilityMode.REGULAR); } private EmbeddedDatabaseRule(final boolean autoCommit, final String name, final Map jdbcUrlProperties, - final Map, InitializationPlugin> initializationPlugins) { + final Map, InitializationPlugin> initializationPlugins, + final JdbcUrlFactory jdbcUrlFactory, + final CompatibilityMode compatibilityMode) { this.autoCommit = autoCommit; this.predefinedName = name; this.jdbcUrlProperties = jdbcUrlProperties == null ? Collections.emptyMap() : jdbcUrlProperties; this.initializationPlugins = initializationPlugins == null ? Collections.emptyMap() : initializationPlugins; + this.jdbcUrlFactory = jdbcUrlFactory == null ? new H2JdbcUrlFactory() : jdbcUrlFactory; + this.compatibilityMode = compatibilityMode; } /** @@ -115,13 +122,14 @@ public boolean isAutoCommit() { return autoCommit; } + /** * Returns a JDBC url for connecting to the in-memory database created by this rule with all INIT params stripped * * @return a JDBC url string */ public String getConnectionJdbcUrl() { - return H2JdbcUrlFactory.buildFilteringInitProperties(getInMemoryDatabaseName(), jdbcUrlProperties); + return jdbcUrlFactory.connectionUrl(getInMemoryDatabaseName(), getJdbcUrlProperties()); } /** @@ -130,7 +138,14 @@ public String getConnectionJdbcUrl() { * @return a JDBC URL string */ private String generateJdbcUrl() { - return H2JdbcUrlFactory.buildWithNameAndProperties(getInMemoryDatabaseName(), jdbcUrlProperties); + return jdbcUrlFactory.connectionUrlForInitialization(getInMemoryDatabaseName(), getJdbcUrlProperties()); + } + + private Map getJdbcUrlProperties() { + final LinkedHashMap properties = new LinkedHashMap<>(); + properties.putAll(jdbcUrlFactory.compatibilityModeParam(compatibilityMode)); + properties.putAll(jdbcUrlProperties); + return properties; } private String getInMemoryDatabaseName() { @@ -210,6 +225,8 @@ public static class Builder { private final Engine engine; + private CompatibilityMode compatibilityMode = CompatibilityMode.REGULAR; + private Builder(final Engine engine) { if (engine == null) { throw new IllegalArgumentException("The \"engine\" argument can not be null"); @@ -290,7 +307,21 @@ public Builder withMode(final String mode) { if (mode == null) { throw new IllegalArgumentException("The \"mode\" argument can not be null"); } - return withProperty(PROP_MODE, mode); + if (mode != "") { + return withMode(mapToCompatibilityMode(mode)); + } else { + return this; + } + } + + private CompatibilityMode mapToCompatibilityMode(final String mode) { + if (mode == null) { + throw new IllegalArgumentException("The \"mode\" argument can not be null"); + } + return Arrays.stream(CompatibilityMode.values()) + .filter(c -> c.name().equalsIgnoreCase(mode)) + .findAny() + .orElseThrow(() -> new IllegalArgumentException("Could not map mode \"" + mode + "\" to a valid Compatibility mode")); } public Builder withMode(final CompatibilityMode compatibilityMode) { @@ -298,7 +329,8 @@ public Builder withMode(final CompatibilityMode compatibilityMode) { if (compatibilityMode == null) { throw new IllegalArgumentException("The \"compatibilityMode\" argument can not be null"); } - return withMode(compatibilityMode.name()); + this.compatibilityMode = compatibilityMode; + return this; } public

Builder initializedByPlugin(final P plugin) { @@ -326,7 +358,20 @@ private Map propertiesMap() { } public EmbeddedDatabaseRule build() { - return new EmbeddedDatabaseRule(autoCommit, name, propertiesMap(), initializationPlugins); + return new EmbeddedDatabaseRule(autoCommit, + name, + propertiesMap(), + initializationPlugins, + createJdbcUrlFactory(), + compatibilityMode); + } + + private JdbcUrlFactory createJdbcUrlFactory() { + if (engine == Engine.HSQLDB) { + return new HyperSqlJdbcUrlFactory(); + } else { + return new H2JdbcUrlFactory(); + } } } diff --git a/embedded-db-junit/src/main/java/org/zapodot/junit/db/internal/H2JdbcUrlFactory.java b/embedded-db-junit/src/main/java/org/zapodot/junit/db/internal/H2JdbcUrlFactory.java index 948c91c..ff8eeba 100644 --- a/embedded-db-junit/src/main/java/org/zapodot/junit/db/internal/H2JdbcUrlFactory.java +++ b/embedded-db-junit/src/main/java/org/zapodot/junit/db/internal/H2JdbcUrlFactory.java @@ -2,26 +2,29 @@ import org.zapodot.junit.db.EmbeddedDatabaseRule; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Optional; /** * @author zapodot */ -public class H2JdbcUrlFactory { +public class H2JdbcUrlFactory implements JdbcUrlFactory { - private H2JdbcUrlFactory() { - } + public static final String PROP_MODE = "MODE"; + + public static final String PROP_INIT_SQL = "INIT"; static final String H2_IN_MEMORY_JDBC_URL_PREFIX = "jdbc:h2:mem:"; - public static Map filterInitProperties(final Map jdbcUrlProperties) { + static Map filterInitProperties(final Map jdbcUrlProperties) { if (jdbcUrlProperties == null) { return null; } else { final Map propertiesCopy = new LinkedHashMap<>(); for (final Map.Entry property : jdbcUrlProperties.entrySet()) { - if (!EmbeddedDatabaseRule.PROP_INIT_SQL.equalsIgnoreCase(property.getKey())) { + if (!PROP_INIT_SQL.equalsIgnoreCase(property.getKey())) { propertiesCopy.put(property.getKey(), property.getValue()); } } @@ -29,23 +32,8 @@ public static Map filterInitProperties(final Map } } - private static String createJdbcUrlParameterString(final Map properties) { - if (properties == null) { - return ""; - } - final StringBuilder paramStringBuilder = new StringBuilder(""); - for (final Map.Entry property : properties.entrySet()) { - if (property.getValue() != null) { - paramStringBuilder.append(';') - .append(property.getKey()) - .append('=') - .append(property.getValue()); - } - } - return paramStringBuilder.toString(); - } - public static String buildWithNameAndProperties(final String name, final Map properties) { + private String buildWithNameAndProperties(final String name, final Map properties) { if (name == null) { throw new NullPointerException("The value of the \"name\" parameter can not be null"); } @@ -55,7 +43,22 @@ public static String buildWithNameAndProperties(final String name, final Map properties) { - return buildWithNameAndProperties(name, filterInitProperties(properties)); + @Override + public String connectionUrlForInitialization(final String name, final Map properties) { + return buildWithNameAndProperties(name, properties); + + } + + @Override + public String connectionUrl(final String name, final Map properties) { + return buildWithNameAndProperties(name,filterInitProperties(properties)); + } + + @Override + public Map compatibilityModeParam(final EmbeddedDatabaseRule.CompatibilityMode compatibilityMode) { + return Optional.ofNullable(compatibilityMode) + .filter(cm -> cm != EmbeddedDatabaseRule.CompatibilityMode.REGULAR) + .map(cm -> Collections.singletonMap(PROP_MODE, cm.name())) + .orElse(Collections.emptyMap()); } } diff --git a/embedded-db-junit/src/main/java/org/zapodot/junit/db/internal/HyperSqlJdbcUrlFactory.java b/embedded-db-junit/src/main/java/org/zapodot/junit/db/internal/HyperSqlJdbcUrlFactory.java new file mode 100644 index 0000000..53984d9 --- /dev/null +++ b/embedded-db-junit/src/main/java/org/zapodot/junit/db/internal/HyperSqlJdbcUrlFactory.java @@ -0,0 +1,56 @@ +package org.zapodot.junit.db.internal; + +import org.zapodot.junit.db.EmbeddedDatabaseRule; + +import java.util.Collections; +import java.util.Map; + +public class HyperSqlJdbcUrlFactory implements JdbcUrlFactory { + + public static final String HSQLDB_MEM_URL = "jdbc:hsqldb:mem:"; + + private static final String ENABLED_SETTING = Boolean.TRUE.toString(); + + static final String SQL_SYNTAX_MSSQLSERVER = "sql.syntax_mss"; + + static final String SQL_SYNTAX_DB2 = "sql.syntax_db2"; + + static final String SQL_SYNTAX_ORACLE = "sql.syntax_ora"; + + static final String SQL_SYNTAX_MYSQL = "sql.syntax_mys"; + + static final String SQL_SYNTAX_POSTGRESQL = "sql.syntax_pgs"; + + @Override + public String connectionUrlForInitialization(final String name, final Map properties) { + return connectionUrl(name, properties); + } + + @Override + public String connectionUrl(final String name, final Map properties) { + return new StringBuilder(HSQLDB_MEM_URL).append(name) + .append(createJdbcUrlParameterString(properties)) + .toString(); + } + + @Override + public Map compatibilityModeParam(final EmbeddedDatabaseRule.CompatibilityMode compatibilityMode) { + if (EmbeddedDatabaseRule.CompatibilityMode.MSSQLServer == compatibilityMode) { + return createEnabledSettingMap(SQL_SYNTAX_MSSQLSERVER); + } else if (EmbeddedDatabaseRule.CompatibilityMode.DB2 == compatibilityMode) { + return createEnabledSettingMap(SQL_SYNTAX_DB2); + } else if (EmbeddedDatabaseRule.CompatibilityMode.Oracle == compatibilityMode) { + return createEnabledSettingMap(SQL_SYNTAX_ORACLE); + } else if (EmbeddedDatabaseRule.CompatibilityMode.MySQL == compatibilityMode) { + return createEnabledSettingMap(SQL_SYNTAX_MYSQL); + } else if (EmbeddedDatabaseRule.CompatibilityMode.PostgreSQL == compatibilityMode) { + return createEnabledSettingMap(SQL_SYNTAX_POSTGRESQL); + } else { + return Collections.emptyMap(); + } + } + + private Map createEnabledSettingMap(final String property) { + return Collections.singletonMap(property, ENABLED_SETTING); + } +} diff --git a/embedded-db-junit/src/main/java/org/zapodot/junit/db/internal/JdbcUrlFactory.java b/embedded-db-junit/src/main/java/org/zapodot/junit/db/internal/JdbcUrlFactory.java index 2a210cd..047807f 100644 --- a/embedded-db-junit/src/main/java/org/zapodot/junit/db/internal/JdbcUrlFactory.java +++ b/embedded-db-junit/src/main/java/org/zapodot/junit/db/internal/JdbcUrlFactory.java @@ -1,5 +1,7 @@ package org.zapodot.junit.db.internal; +import org.zapodot.junit.db.EmbeddedDatabaseRule; + import java.util.Map; public interface JdbcUrlFactory { @@ -7,4 +9,22 @@ public interface JdbcUrlFactory { String connectionUrlForInitialization(final String name, final Map properties); String connectionUrl(final String name, final Map properties); + + Map compatibilityModeParam(final EmbeddedDatabaseRule.CompatibilityMode compatibilityMode); + + default String createJdbcUrlParameterString(final Map properties) { + if (properties == null) { + return ""; + } + final StringBuilder paramStringBuilder = new StringBuilder(); + for (final Map.Entry property : properties.entrySet()) { + if (property.getValue() != null) { + paramStringBuilder.append(';') + .append(property.getKey()) + .append('=') + .append(property.getValue()); + } + } + return paramStringBuilder.toString(); + } } diff --git a/embedded-db-junit/src/test/java/org/zapodot/junit/db/EmbeddedDatabaseRuleHsqlTest.java b/embedded-db-junit/src/test/java/org/zapodot/junit/db/EmbeddedDatabaseRuleHsqlTest.java new file mode 100644 index 0000000..d68f6c6 --- /dev/null +++ b/embedded-db-junit/src/test/java/org/zapodot/junit/db/EmbeddedDatabaseRuleHsqlTest.java @@ -0,0 +1,39 @@ +package org.zapodot.junit.db; + +import org.junit.Rule; +import org.junit.Test; +import org.zapodot.junit.db.internal.HyperSqlJdbcUrlFactory; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import static org.junit.Assert.*; + +public class EmbeddedDatabaseRuleHsqlTest { + + @Rule + public final EmbeddedDatabaseRule databaseRule = EmbeddedDatabaseRule.hsqldb() + .withMode(EmbeddedDatabaseRule.CompatibilityMode.MSSQLServer) + .build(); + + @Test + public void hsqldbConnection() { + assertEquals(HyperSqlJdbcUrlFactory.HSQLDB_MEM_URL + getClass().getSimpleName() + ";sql.syntax_mss=true", + databaseRule.getConnectionJdbcUrl()); + } + + @Test + public void mssqlCompatibility() { + final String testString = "A test string"; + try (final Connection connection = databaseRule.getConnection(); + final Statement statement = connection.createStatement(); + final ResultSet resultSet = statement.executeQuery("Select '" + testString + "'")) { + assertTrue(resultSet.next()); + assertEquals(testString, resultSet.getString(1)); + } catch (SQLException e) { + fail("Could not execute SQL due to an exception \"" + e.getMessage() + "\""); + } + } +} \ No newline at end of file diff --git a/embedded-db-junit/src/test/java/org/zapodot/junit/db/internal/H2JdbcUrlFactoryTest.java b/embedded-db-junit/src/test/java/org/zapodot/junit/db/internal/H2JdbcUrlFactoryTest.java index db3aa91..4ec4af1 100644 --- a/embedded-db-junit/src/test/java/org/zapodot/junit/db/internal/H2JdbcUrlFactoryTest.java +++ b/embedded-db-junit/src/test/java/org/zapodot/junit/db/internal/H2JdbcUrlFactoryTest.java @@ -1,9 +1,7 @@ package org.zapodot.junit.db.internal; import org.junit.Test; -import org.zapodot.junit.db.EmbeddedDatabaseRule; -import java.lang.reflect.Constructor; import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -16,74 +14,58 @@ public class H2JdbcUrlFactoryTest { @Test - public void testFilterInitPropertiesNoInit() throws Exception { + public void testFilterInitPropertiesNoInit() { Map properties = new HashMap<>(); properties.put("someKey", "someValue"); assertEquals(properties, H2JdbcUrlFactory.filterInitProperties(properties)); } @Test - public void testFilterInitPropertiesInit() throws Exception { + public void testFilterInitPropertiesInit() { final Map properties = createPropertyWithInitValue("someValue"); assertEquals(Collections.emptyMap(), H2JdbcUrlFactory.filterInitProperties(properties)); } private Map createPropertyWithInitValue(final String initPropValue) { final Map properties = new HashMap<>(); - properties.put(EmbeddedDatabaseRule.PROP_INIT_SQL, initPropValue); + properties.put(H2JdbcUrlFactory.PROP_INIT_SQL, initPropValue); return properties; } @Test(expected = NullPointerException.class) - public void testBuildWithNameNull() throws Exception { - H2JdbcUrlFactory.buildWithNameAndProperties(null, null); + public void testBuildWithNameNull() { + new H2JdbcUrlFactory().connectionUrl(null, null); } @Test - public void testBuildWitNameAndNoFilter() throws Exception { + public void testBuildWitNameAndNoFilter() { final String name = "illegalSqlFromResource"; - final String jdbcUrl = H2JdbcUrlFactory.buildWithNameAndProperties(name, createPropertyWithInitValue("something")); - assertTrue(jdbcUrl.contains(EmbeddedDatabaseRule.PROP_INIT_SQL)); + final String jdbcUrl = new H2JdbcUrlFactory() + .connectionUrlForInitialization(name, createPropertyWithInitValue("something")); + assertTrue(jdbcUrl.contains(H2JdbcUrlFactory.PROP_INIT_SQL)); } @Test - public void testBuildWitNameAndFilter() throws Exception { - final String jdbcUrl = H2JdbcUrlFactory.buildFilteringInitProperties("illegalSqlFromResource", createPropertyWithInitValue("something")); - assertFalse(jdbcUrl.contains(EmbeddedDatabaseRule.PROP_INIT_SQL)); + public void testBuildWitNameAndFilter() { + final String jdbcUrl = new H2JdbcUrlFactory() + .connectionUrl("illegalSqlFromResource", createPropertyWithInitValue("something")); + assertFalse(jdbcUrl.contains(H2JdbcUrlFactory.PROP_INIT_SQL)); } @Test - public void testBuildWithoutFilterAndNullProperties() throws Exception { + public void testBuildWithoutFilterAndNullProperties() { final String dbName = "illegalSqlFromResource"; - final String jdbcUrl = H2JdbcUrlFactory.buildWithNameAndProperties(dbName, null); + final String jdbcUrl = new H2JdbcUrlFactory().connectionUrl(dbName, null); assertEquals(H2JdbcUrlFactory.H2_IN_MEMORY_JDBC_URL_PREFIX + dbName, jdbcUrl); } @Test - public void testBuildWithFilterAndNullProperties() throws Exception { + public void testBuildWithFilterAndNullProperties() { final String dbName = "illegalSqlFromResource"; - final String jdbcUrl = H2JdbcUrlFactory.buildFilteringInitProperties(dbName, null); + final String jdbcUrl = new H2JdbcUrlFactory().connectionUrlForInitialization(dbName, null); assertEquals(H2JdbcUrlFactory.H2_IN_MEMORY_JDBC_URL_PREFIX + dbName, jdbcUrl); } - @Test(expected = IllegalAccessException.class) - public void testInstantiation() throws Exception { - final Constructor declaredConstructor = H2JdbcUrlFactory.class.getDeclaredConstructor(); - declaredConstructor.newInstance(); - - } - - /** - * This test is added only to reach 100% test coverage - * @throws Exception if test fails - */ - @Test - public void testFakeInstantiation() throws Exception { - final Constructor declaredConstructor = H2JdbcUrlFactory.class.getDeclaredConstructor(); - declaredConstructor.setAccessible(true); - declaredConstructor.newInstance(); - - } } \ No newline at end of file diff --git a/embedded-db-junit/src/test/java/org/zapodot/junit/db/internal/HyperSqlJdbcUrlFactoryTest.java b/embedded-db-junit/src/test/java/org/zapodot/junit/db/internal/HyperSqlJdbcUrlFactoryTest.java new file mode 100644 index 0000000..0750421 --- /dev/null +++ b/embedded-db-junit/src/test/java/org/zapodot/junit/db/internal/HyperSqlJdbcUrlFactoryTest.java @@ -0,0 +1,86 @@ +package org.zapodot.junit.db.internal; + +import org.junit.Test; +import org.zapodot.junit.db.EmbeddedDatabaseRule; + +import java.util.Collections; + +import static org.junit.Assert.*; + +public class HyperSqlJdbcUrlFactoryTest { + + private static final HyperSqlJdbcUrlFactory URL_FACTORY = new HyperSqlJdbcUrlFactory(); + + @Test + public void compatibilityModeParamNull() { + assertEquals(Collections.emptyMap(), URL_FACTORY.compatibilityModeParam(null)); + } + + @Test + public void compatibilityModeParamRegular() { + assertEquals(Collections.emptyMap(), + URL_FACTORY.compatibilityModeParam(EmbeddedDatabaseRule.CompatibilityMode.REGULAR)); + } + + @Test + public void compatibilityModeDerby() { + assertEquals(Collections.emptyMap(), + URL_FACTORY.compatibilityModeParam(EmbeddedDatabaseRule.CompatibilityMode.Derby)); + } + + @Test + public void compatibilityModeMssql() { + assertEquals(HyperSqlJdbcUrlFactory.SQL_SYNTAX_MSSQLSERVER, + URL_FACTORY.compatibilityModeParam(EmbeddedDatabaseRule.CompatibilityMode.MSSQLServer) + .entrySet() + .iterator() + .next() + .getKey()); + } + + @Test + public void compatibilityModeOracle() { + assertEquals(HyperSqlJdbcUrlFactory.SQL_SYNTAX_ORACLE, + URL_FACTORY.compatibilityModeParam(EmbeddedDatabaseRule.CompatibilityMode.Oracle) + .entrySet() + .iterator() + .next() + .getKey()); + } + + @Test + public void compatibilityModeMysql() { + assertEquals(HyperSqlJdbcUrlFactory.SQL_SYNTAX_MYSQL, + URL_FACTORY.compatibilityModeParam(EmbeddedDatabaseRule.CompatibilityMode.MySQL) + .entrySet() + .iterator() + .next() + .getKey()); + } + + @Test + public void compatibilityModeDB2() { + assertEquals(HyperSqlJdbcUrlFactory.SQL_SYNTAX_DB2, + URL_FACTORY.compatibilityModeParam(EmbeddedDatabaseRule.CompatibilityMode.DB2) + .entrySet() + .iterator() + .next() + .getKey()); + } + + @Test + public void compatibilityModePostgresql() { + assertEquals(HyperSqlJdbcUrlFactory.SQL_SYNTAX_POSTGRESQL, + URL_FACTORY.compatibilityModeParam(EmbeddedDatabaseRule.CompatibilityMode.PostgreSQL) + .entrySet() + .iterator() + .next() + .getKey()); + } + + @Test + public void compatibilityModeHsqldb() { + assertEquals(Collections.emptyMap(), + URL_FACTORY.compatibilityModeParam(EmbeddedDatabaseRule.CompatibilityMode.HSQLDB)); + } +} \ No newline at end of file diff --git a/embedded-db-junit/src/test/java/org/zapodot/junit/db/internal/SQLInitializationPluginTest.java b/embedded-db-junit/src/test/java/org/zapodot/junit/db/internal/SQLInitializationPluginTest.java new file mode 100644 index 0000000..2d9e538 --- /dev/null +++ b/embedded-db-junit/src/test/java/org/zapodot/junit/db/internal/SQLInitializationPluginTest.java @@ -0,0 +1,44 @@ +package org.zapodot.junit.db.internal; + +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + +public class SQLInitializationPluginTest { + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private Connection connection; + + @Mock + private Statement statement; + + @Test(expected = IllegalArgumentException.class) + public void constructionNull() { + assertNull(new SQLInitializationPlugin(null)); + } + + @Test(expected = IllegalStateException.class) + public void connectionMadeSQLFails() throws SQLException { + final SQLInitializationPlugin sqlInitializationPlugin = new SQLInitializationPlugin( + "INSERT INTO MyTables values(1, 'User');"); + assertNotNull(sqlInitializationPlugin); + when(connection.createStatement()).thenReturn(statement); + when(statement.execute(anyString())).thenThrow(new SQLException("Reason")); + + sqlInitializationPlugin.connectionMade("name", connection); + + } +} \ No newline at end of file