#75 - Polishing.

Unify connection creation by providing JDBC URL. Obtain R2DBC ConnectionFactory using connection factory discovery.

Original pull request: #84.
This commit is contained in:
Mark Paluch
2019-03-27 12:54:14 +01:00
committed by Jens Schauder
parent 3ca32b89b7
commit c9435c8797
5 changed files with 171 additions and 87 deletions

View File

@@ -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.
}
}

View File

@@ -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());
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}