From c9435c879734e9c643997a42a5f3d8c74d8e5e69 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 27 Mar 2019 12:54:14 +0100 Subject: [PATCH] #75 - Polishing. Unify connection creation by providing JDBC URL. Obtain R2DBC ConnectionFactory using connection factory discovery. Original pull request: #84. --- .../data/r2dbc/testing/ConnectionUtils.java | 65 +++++++++ .../data/r2dbc/testing/ExternalDatabase.java | 124 +++++++++++++----- .../data/r2dbc/testing/MySqlTestSupport.java | 24 +--- .../r2dbc/testing/PostgresTestSupport.java | 29 +--- .../r2dbc/testing/SqlServerTestSupport.java | 16 +-- 5 files changed, 171 insertions(+), 87 deletions(-) create mode 100644 src/test/java/org/springframework/data/r2dbc/testing/ConnectionUtils.java diff --git a/src/test/java/org/springframework/data/r2dbc/testing/ConnectionUtils.java b/src/test/java/org/springframework/data/r2dbc/testing/ConnectionUtils.java new file mode 100644 index 00000000..a0725e8d --- /dev/null +++ b/src/test/java/org/springframework/data/r2dbc/testing/ConnectionUtils.java @@ -0,0 +1,65 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.r2dbc.testing; + +import static io.r2dbc.spi.ConnectionFactoryOptions.*; + +import io.r2dbc.spi.ConnectionFactories; +import io.r2dbc.spi.ConnectionFactory; +import io.r2dbc.spi.ConnectionFactoryOptions; + +import javax.sql.DataSource; + +/** + * Utility methods to configure {@link DataSource}/{@link ConnectionFactoryOptions}. + * + * @author Mark Paluch + */ +abstract class ConnectionUtils { + + /** + * Obtain a {@link ConnectionFactory} given {@link ExternalDatabase} and {@code driver}. + * + * @param driver + * @param configuration + * @return + */ + static ConnectionFactory getConnectionFactory(String driver, ExternalDatabase configuration) { + return ConnectionFactories.get(createOptions(driver, configuration)); + } + + /** + * Create {@link ConnectionFactoryOptions} from {@link ExternalDatabase} and {@code driver}. + * + * @param driver + * @param configuration + * @return + */ + private static ConnectionFactoryOptions createOptions(String driver, ExternalDatabase configuration) { + + return ConnectionFactoryOptions.builder().option(DRIVER, driver) // + .option(USER, configuration.getUsername()) // + .option(PASSWORD, configuration.getPassword()) // + .option(DATABASE, configuration.getDatabase()) // + .option(HOST, configuration.getHostname()) // + .option(PORT, configuration.getPort()) // + .build(); + } + + private ConnectionUtils() { + // utility constructor. + } +} diff --git a/src/test/java/org/springframework/data/r2dbc/testing/ExternalDatabase.java b/src/test/java/org/springframework/data/r2dbc/testing/ExternalDatabase.java index 996abf9d..54c8cb17 100644 --- a/src/test/java/org/springframework/data/r2dbc/testing/ExternalDatabase.java +++ b/src/test/java/org/springframework/data/r2dbc/testing/ExternalDatabase.java @@ -26,6 +26,7 @@ import org.junit.AssumptionViolatedException; import org.junit.rules.ExternalResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.testcontainers.containers.JdbcDatabaseContainer; /** * {@link ExternalResource} wrapper to encapsulate {@link ProvidedDatabase} and @@ -47,15 +48,25 @@ public abstract class ExternalDatabase extends ExternalResource { return NoAvailableDatabase.INSTANCE; } + /** + * @return hostname on which the database service runs. + */ + public abstract String getHostname(); + /** * @return the post of the database service. */ public abstract int getPort(); /** - * @return hostname on which the database service runs. + * @return database user name. */ - public abstract String getHostname(); + public abstract String getUsername(); + + /** + * @return password for the database user. + */ + public abstract String getPassword(); /** * @return name of the database. @@ -63,9 +74,9 @@ public abstract class ExternalDatabase extends ExternalResource { public abstract String getDatabase(); /** - * @return database user name. + * @return JDBC URL for the endpoint. */ - public abstract String getUsername(); + public abstract String getJdbcUrl(); /** * Throws an {@link AssumptionViolatedException} if the database cannot be reached. @@ -98,22 +109,56 @@ public abstract class ExternalDatabase extends ExternalResource { return false; } - /** - * @return password for the database user. - */ - public abstract String getPassword(); - /** * Provided (unmanaged resource) database connection coordinates. */ @Builder public static class ProvidedDatabase extends ExternalDatabase { - private final int port; private final String hostname; - private final String database; + private final int port; private final String username; private final String password; + private final String database; + private final String jdbcUrl; + + public static ProvidedDatabaseBuilder builder() { + return new ProvidedDatabaseBuilder(); + } + + /** + * Create a {@link ProvidedDatabaseBuilder} initialized with {@link JdbcDatabaseContainer}. + * + * @param container + * @return + */ + public static ProvidedDatabaseBuilder builder(JdbcDatabaseContainer container) { + + return builder().hostname(container.getContainerIpAddress()) // + .port(container.getFirstMappedPort()) // + .username(container.getUsername()) // + .password(container.getPassword()) // + .database(container.getDatabaseName()) // + .jdbcUrl(container.getJdbcUrl()); + } + + /** + * Create a {@link ProvidedDatabase} from {@link JdbcDatabaseContainer}. + * + * @param container + * @return + */ + public static ProvidedDatabase from(JdbcDatabaseContainer container) { + return builder(container).build(); + } + + /* (non-Javadoc) + * @see org.springframework.data.jdbc.core.function.ExternalDatabase#getHostname() + */ + @Override + public String getHostname() { + return hostname; + } /* (non-Javadoc) * @see org.springframework.data.jdbc.core.function.ExternalDatabase#getPort() @@ -123,22 +168,6 @@ public abstract class ExternalDatabase extends ExternalResource { return port; } - /* (non-Javadoc) - * @see org.springframework.data.jdbc.core.function.ExternalDatabase#getHostname() - */ - @Override - public String getHostname() { - return hostname; - } - - /* (non-Javadoc) - * @see org.springframework.data.jdbc.core.function.ExternalDatabase#getDatabase() - */ - @Override - public String getDatabase() { - return database; - } - /* (non-Javadoc) * @see org.springframework.data.jdbc.core.function.ExternalDatabase#getUsername() */ @@ -154,6 +183,22 @@ public abstract class ExternalDatabase extends ExternalResource { public String getPassword() { return password; } + + /* (non-Javadoc) + * @see org.springframework.data.jdbc.core.function.ExternalDatabase#getDatabase() + */ + @Override + public String getDatabase() { + return database; + } + + /* (non-Javadoc) + * @see org.springframework.data.jdbc.core.function.ExternalDatabase#getJdbcUrl() + */ + @Override + public String getJdbcUrl() { + return jdbcUrl; + } } /** @@ -173,11 +218,6 @@ public abstract class ExternalDatabase extends ExternalResource { return false; } - @Override - public int getPort() { - throw new UnsupportedOperationException(getClass().getSimpleName()); - } - /* (non-Javadoc) * @see org.springframework.data.jdbc.core.function.ExternalDatabase#getHostname() */ @@ -187,10 +227,10 @@ public abstract class ExternalDatabase extends ExternalResource { } /* (non-Javadoc) - * @see org.springframework.data.jdbc.core.function.ExternalDatabase#getDatabase() + * @see org.springframework.data.jdbc.core.function.ExternalDatabase#getPort() */ @Override - public String getDatabase() { + public int getPort() { throw new UnsupportedOperationException(getClass().getSimpleName()); } @@ -209,5 +249,21 @@ public abstract class ExternalDatabase extends ExternalResource { public String getPassword() { throw new UnsupportedOperationException(getClass().getSimpleName()); } + + /* (non-Javadoc) + * @see org.springframework.data.jdbc.core.function.ExternalDatabase#getDatabase() + */ + @Override + public String getDatabase() { + throw new UnsupportedOperationException(getClass().getSimpleName()); + } + + /* (non-Javadoc) + * @see org.springframework.data.jdbc.core.function.ExternalDatabase#getJdbcUrl() + */ + @Override + public String getJdbcUrl() { + throw new UnsupportedOperationException(getClass().getSimpleName()); + } } } diff --git a/src/test/java/org/springframework/data/r2dbc/testing/MySqlTestSupport.java b/src/test/java/org/springframework/data/r2dbc/testing/MySqlTestSupport.java index 8c13bda5..387dc401 100644 --- a/src/test/java/org/springframework/data/r2dbc/testing/MySqlTestSupport.java +++ b/src/test/java/org/springframework/data/r2dbc/testing/MySqlTestSupport.java @@ -26,9 +26,6 @@ import org.springframework.data.r2dbc.testing.ExternalDatabase.ProvidedDatabase; import org.testcontainers.containers.MySQLContainer; -import com.github.jasync.r2dbc.mysql.JasyncConnectionFactory; -import com.github.jasync.sql.db.Configuration; -import com.github.jasync.sql.db.mysql.pool.MySQLConnectionFactory; import com.mysql.jdbc.jdbc2.optional.MysqlDataSource; /** @@ -104,15 +101,12 @@ public class MySqlTestSupport { if (testContainerDatabase == null) { try { - MySQLContainer mySQLContainer = new MySQLContainer("mysql:5.6.43"); - mySQLContainer.start(); + MySQLContainer container = new MySQLContainer("mysql:5.6.43"); + container.start(); - testContainerDatabase = ProvidedDatabase.builder() // - .hostname("localhost") // - .port(mySQLContainer.getFirstMappedPort()) // - .database(mySQLContainer.getDatabaseName()) // + testContainerDatabase = ProvidedDatabase.builder(container) // .username("root") // - .password(mySQLContainer.getPassword()).build(); + .build(); } catch (IllegalStateException ise) { // docker not available. testContainerDatabase = ExternalDatabase.unavailable(); @@ -126,10 +120,7 @@ public class MySqlTestSupport { * Creates a new {@link ConnectionFactory} configured from the {@link ExternalDatabase}.. */ public static ConnectionFactory createConnectionFactory(ExternalDatabase database) { - - MySQLConnectionFactory jasync = new MySQLConnectionFactory(new Configuration(database.getUsername(), - database.getHostname(), database.getPort(), database.getPassword(), database.getDatabase())); - return new JasyncConnectionFactory(jasync); + return ConnectionUtils.getConnectionFactory("mysql", database); } /** @@ -141,11 +132,8 @@ public class MySqlTestSupport { dataSource.setUser(database.getUsername()); dataSource.setPassword(database.getPassword()); - dataSource.setDatabaseName(database.getDatabase()); - dataSource.setServerName(database.getHostname()); - dataSource.setPortNumber(database.getPort()); + dataSource.setURL(database.getJdbcUrl()); return dataSource; } - } diff --git a/src/test/java/org/springframework/data/r2dbc/testing/PostgresTestSupport.java b/src/test/java/org/springframework/data/r2dbc/testing/PostgresTestSupport.java index 834af652..31475a46 100644 --- a/src/test/java/org/springframework/data/r2dbc/testing/PostgresTestSupport.java +++ b/src/test/java/org/springframework/data/r2dbc/testing/PostgresTestSupport.java @@ -1,7 +1,5 @@ package org.springframework.data.r2dbc.testing; -import io.r2dbc.postgresql.PostgresqlConnectionConfiguration; -import io.r2dbc.postgresql.PostgresqlConnectionFactory; import io.r2dbc.spi.ConnectionFactory; import java.util.function.Supplier; @@ -10,7 +8,9 @@ import java.util.stream.Stream; import javax.sql.DataSource; import org.postgresql.ds.PGSimpleDataSource; + import org.springframework.data.r2dbc.testing.ExternalDatabase.ProvidedDatabase; + import org.testcontainers.containers.PostgreSQLContainer; /** @@ -87,15 +87,10 @@ public class PostgresTestSupport { if (testContainerDatabase == null) { try { - PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer(); - postgreSQLContainer.start(); + PostgreSQLContainer container = new PostgreSQLContainer(); + container.start(); - testContainerDatabase = ProvidedDatabase.builder() // - .hostname("localhost") // - .port(postgreSQLContainer.getFirstMappedPort()) // - .database(postgreSQLContainer.getDatabaseName()) // - .username(postgreSQLContainer.getUsername()) // - .password(postgreSQLContainer.getPassword()).build(); + testContainerDatabase = ProvidedDatabase.from(container); } catch (IllegalStateException ise) { // docker not available. @@ -111,14 +106,7 @@ public class PostgresTestSupport { * Creates a new {@link ConnectionFactory} configured from the {@link ExternalDatabase}.. */ public static ConnectionFactory createConnectionFactory(ExternalDatabase database) { - - return new PostgresqlConnectionFactory(PostgresqlConnectionConfiguration.builder() // - .host(database.getHostname()) // - .database(database.getDatabase()) // - .port(database.getPort()) // - .username(database.getUsername()) // - .password(database.getPassword()) // - .build()); + return ConnectionUtils.getConnectionFactory("postgresql", database); } /** @@ -130,11 +118,8 @@ public class PostgresTestSupport { dataSource.setUser(database.getUsername()); dataSource.setPassword(database.getPassword()); - dataSource.setDatabaseName(database.getDatabase()); - dataSource.setServerName(database.getHostname()); - dataSource.setPortNumber(database.getPort()); + dataSource.setURL(database.getJdbcUrl()); return dataSource; } - } diff --git a/src/test/java/org/springframework/data/r2dbc/testing/SqlServerTestSupport.java b/src/test/java/org/springframework/data/r2dbc/testing/SqlServerTestSupport.java index d52c8476..fd12621e 100644 --- a/src/test/java/org/springframework/data/r2dbc/testing/SqlServerTestSupport.java +++ b/src/test/java/org/springframework/data/r2dbc/testing/SqlServerTestSupport.java @@ -1,7 +1,5 @@ package org.springframework.data.r2dbc.testing; -import io.r2dbc.mssql.MssqlConnectionConfiguration; -import io.r2dbc.mssql.MssqlConnectionFactory; import io.r2dbc.spi.ConnectionFactory; import javax.sql.DataSource; @@ -53,16 +51,10 @@ public class SqlServerTestSupport { } /** - * Creates a new {@link ConnectionFactory} configured from the {@link ExternalDatabase}.. + * Creates a new {@link ConnectionFactory} configured from the {@link ExternalDatabase}. */ public static ConnectionFactory createConnectionFactory(ExternalDatabase database) { - - return new MssqlConnectionFactory(MssqlConnectionConfiguration.builder().host(database.getHostname()) // - .database(database.getDatabase()) // - .username(database.getUsername()) // - .password(database.getPassword()) // - .port(database.getPort()) // - .build()); + return ConnectionUtils.getConnectionFactory("mssql", database); } /** @@ -74,9 +66,7 @@ public class SqlServerTestSupport { dataSource.setUser(database.getUsername()); dataSource.setPassword(database.getPassword()); - dataSource.setDatabaseName(database.getDatabase()); - dataSource.setServerName(database.getHostname()); - dataSource.setPortNumber(database.getPort()); + dataSource.setURL(database.getJdbcUrl()); return dataSource; }