Skip to content

Commit

Permalink
delegate getMetadata() to R2DBCDatabaseContainerProvider (#2577)
Browse files Browse the repository at this point in the history
Apparently, R2DBC ConnectionFactories perform early validation of options, and it fails because the original options (when specified as `r2dbc://mysql:///db`) miss some required options like host/port/username/password.

After talking to Mark from R2DBC, it seems that the checks will stay, so we need to workaround it somehow. I ended up with the delegation to `R2DBCDatabaseContainerProvider`, because these provides should know which options they add and which are required.
  • Loading branch information
bsideup committed Apr 19, 2020
1 parent d2fe97b commit 3530e63
Show file tree
Hide file tree
Showing 11 changed files with 116 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@ public class MariaDBContainer<SELF extends MariaDBContainer<SELF>> extends JdbcD
public static final String IMAGE = "mariadb";
public static final String DEFAULT_TAG = "10.3.6";

static final String DEFAULT_USER = "test";

static final String DEFAULT_PASSWORD = "test";

static final Integer MARIADB_PORT = 3306;
private String databaseName = "test";
private String username = "test";
private String password = "test";
private String username = DEFAULT_USER;
private String password = DEFAULT_PASSWORD;
private static final String MARIADB_ROOT_USER = "root";
private static final String MY_CNF_CONFIG_OVERRIDE_PARAM_NAME = "TC_MY_CNF";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package org.testcontainers.containers;

import com.google.auto.service.AutoService;
import io.r2dbc.spi.ConnectionFactoryMetadata;
import io.r2dbc.spi.ConnectionFactoryOptions;
import org.mariadb.r2dbc.MariadbConnectionFactoryProvider;
import org.testcontainers.r2dbc.R2DBCDatabaseContainer;
import org.testcontainers.r2dbc.R2DBCDatabaseContainerProvider;

import javax.annotation.Nullable;

@AutoService(R2DBCDatabaseContainerProvider.class)
public class MariaDBR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider {

Expand All @@ -27,4 +30,17 @@ public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options)
}
return new MariaDBR2DBCDatabaseContainer(container);
}

@Nullable
@Override
public ConnectionFactoryMetadata getMetadata(ConnectionFactoryOptions options) {
ConnectionFactoryOptions.Builder builder = options.mutate();
if (!options.hasOption(ConnectionFactoryOptions.USER)) {
builder.option(ConnectionFactoryOptions.USER, MariaDBContainer.DEFAULT_USER);
}
if (!options.hasOption(ConnectionFactoryOptions.PASSWORD)) {
builder.option(ConnectionFactoryOptions.PASSWORD, MariaDBContainer.DEFAULT_PASSWORD);
}
return R2DBCDatabaseContainerProvider.super.getMetadata(builder.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

import com.google.auto.service.AutoService;
import io.r2dbc.mssql.MssqlConnectionFactoryProvider;
import io.r2dbc.spi.ConnectionFactoryMetadata;
import io.r2dbc.spi.ConnectionFactoryOptions;
import org.testcontainers.r2dbc.R2DBCDatabaseContainer;
import org.testcontainers.r2dbc.R2DBCDatabaseContainerProvider;

import javax.annotation.Nullable;

@AutoService(R2DBCDatabaseContainerProvider.class)
public class MSSQLR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider {

Expand All @@ -26,4 +29,17 @@ public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options)
}
return new MSSQLR2DBCDatabaseContainer(container);
}

@Nullable
@Override
public ConnectionFactoryMetadata getMetadata(ConnectionFactoryOptions options) {
ConnectionFactoryOptions.Builder builder = options.mutate();
if (!options.hasOption(ConnectionFactoryOptions.USER)) {
builder.option(ConnectionFactoryOptions.USER, MSSQLServerContainer.DEFAULT_USER);
}
if (!options.hasOption(ConnectionFactoryOptions.PASSWORD)) {
builder.option(ConnectionFactoryOptions.PASSWORD, MSSQLServerContainer.DEFAULT_PASSWORD);
}
return R2DBCDatabaseContainerProvider.super.getMetadata(builder.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ public class MSSQLServerContainer<SELF extends MSSQLServerContainer<SELF>> exten
public static final String DEFAULT_TAG = "2017-CU12";

public static final Integer MS_SQL_SERVER_PORT = 1433;
private String username = "SA";
private String password = "A_Str0ng_Required_Password";

static final String DEFAULT_USER = "SA";

static final String DEFAULT_PASSWORD = "A_Str0ng_Required_Password";

private String password = DEFAULT_PASSWORD;

private static final int DEFAULT_STARTUP_TIMEOUT_SECONDS = 240;
private static final int DEFAULT_CONNECT_TIMEOUT_SECONDS = 240;
Expand Down Expand Up @@ -63,7 +67,7 @@ public String getJdbcUrl() {

@Override
public String getUsername() {
return username;
return DEFAULT_USER;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ public class MySQLContainer<SELF extends MySQLContainer<SELF>> extends JdbcDatab
public static final String IMAGE = "mysql";
public static final String DEFAULT_TAG = "5.7.22";

static final String DEFAULT_USER = "test";

static final String DEFAULT_PASSWORD = "test";

private static final String MY_CNF_CONFIG_OVERRIDE_PARAM_NAME = "TC_MY_CNF";
public static final Integer MYSQL_PORT = 3306;
private String databaseName = "test";
private String username = "test";
private String password = "test";
private String username = DEFAULT_USER;
private String password = DEFAULT_PASSWORD;
private static final String MYSQL_ROOT_USER = "root";

public MySQLContainer() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

import com.google.auto.service.AutoService;
import dev.miku.r2dbc.mysql.MySqlConnectionFactoryProvider;
import io.r2dbc.spi.ConnectionFactoryMetadata;
import io.r2dbc.spi.ConnectionFactoryOptions;
import org.testcontainers.r2dbc.R2DBCDatabaseContainer;
import org.testcontainers.r2dbc.R2DBCDatabaseContainerProvider;

import javax.annotation.Nullable;

@AutoService(R2DBCDatabaseContainerProvider.class)
public class MySQLR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider {

Expand All @@ -27,4 +30,17 @@ public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options)
}
return new MySQLR2DBCDatabaseContainer(container);
}

@Nullable
@Override
public ConnectionFactoryMetadata getMetadata(ConnectionFactoryOptions options) {
ConnectionFactoryOptions.Builder builder = options.mutate();
if (!options.hasOption(ConnectionFactoryOptions.USER)) {
builder.option(ConnectionFactoryOptions.USER, MySQLContainer.DEFAULT_USER);
}
if (!options.hasOption(ConnectionFactoryOptions.PASSWORD)) {
builder.option(ConnectionFactoryOptions.PASSWORD, MySQLContainer.DEFAULT_PASSWORD);
}
return R2DBCDatabaseContainerProvider.super.getMetadata(builder.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ public class PostgreSQLContainer<SELF extends PostgreSQLContainer<SELF>> extends
public static final String DEFAULT_TAG = "9.6.12";

public static final Integer POSTGRESQL_PORT = 5432;

static final String DEFAULT_USER = "test";

static final String DEFAULT_PASSWORD = "test";

private String databaseName = "test";
private String username = "test";
private String password = "test";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

import com.google.auto.service.AutoService;
import io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider;
import io.r2dbc.spi.ConnectionFactoryMetadata;
import io.r2dbc.spi.ConnectionFactoryOptions;
import org.testcontainers.r2dbc.R2DBCDatabaseContainer;
import org.testcontainers.r2dbc.R2DBCDatabaseContainerProvider;

import javax.annotation.Nullable;

@AutoService(R2DBCDatabaseContainerProvider.class)
public final class PostgreSQLR2DBCDatabaseContainerProvider implements R2DBCDatabaseContainerProvider {

Expand All @@ -27,4 +30,17 @@ public R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options)
}
return new PostgreSQLR2DBCDatabaseContainer(container);
}

@Nullable
@Override
public ConnectionFactoryMetadata getMetadata(ConnectionFactoryOptions options) {
ConnectionFactoryOptions.Builder builder = options.mutate();
if (!options.hasOption(ConnectionFactoryOptions.USER)) {
builder.option(ConnectionFactoryOptions.USER, PostgreSQLContainer.DEFAULT_USER);
}
if (!options.hasOption(ConnectionFactoryOptions.PASSWORD)) {
builder.option(ConnectionFactoryOptions.PASSWORD, PostgreSQLContainer.DEFAULT_PASSWORD);
}
return R2DBCDatabaseContainerProvider.super.getMetadata(builder.build());
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package org.testcontainers.r2dbc;

import io.r2dbc.spi.ConnectionFactories;
import io.r2dbc.spi.ConnectionFactory;
import io.r2dbc.spi.ConnectionFactoryMetadata;
import io.r2dbc.spi.ConnectionFactoryOptions;
import io.r2dbc.spi.Option;

import javax.annotation.Nullable;

public interface R2DBCDatabaseContainerProvider {

Option<Boolean> REUSABLE_OPTION = Option.valueOf("TC_REUSABLE");
Expand All @@ -12,4 +17,18 @@ public interface R2DBCDatabaseContainerProvider {
boolean supports(ConnectionFactoryOptions options);

R2DBCDatabaseContainer createContainer(ConnectionFactoryOptions options);

@Nullable
default ConnectionFactoryMetadata getMetadata(ConnectionFactoryOptions options) {
ConnectionFactoryOptions.Builder builder = options.mutate();
if (!options.hasOption(ConnectionFactoryOptions.HOST)) {
builder.option(ConnectionFactoryOptions.HOST, "localhost");
}
if (!options.hasOption(ConnectionFactoryOptions.PORT)) {
builder.option(ConnectionFactoryOptions.PORT, 65535);
}

ConnectionFactory connectionFactory = ConnectionFactories.find(builder.build());
return connectionFactory != null ? connectionFactory.getMetadata() : null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ public Publisher<? extends Connection> create() {

@Override
public ConnectionFactoryMetadata getMetadata() {
// TODO check whether it is fine to call it without setting the host/port and other values
return ConnectionFactories.find(options).getMetadata();
return containerProvider.getMetadata(options);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.r2dbc.spi.Connection;
import io.r2dbc.spi.ConnectionFactories;
import io.r2dbc.spi.ConnectionFactory;
import io.r2dbc.spi.ConnectionFactoryMetadata;
import io.r2dbc.spi.ConnectionFactoryOptions;
import org.junit.Test;
import org.testcontainers.containers.GenericContainer;
Expand Down Expand Up @@ -38,6 +39,13 @@ public final void testUrlSupport() {
runTestQuery(connectionFactory);
}

@Test
public final void testGetMetadata() {
ConnectionFactory connectionFactory = ConnectionFactories.get(createR2DBCUrl());
ConnectionFactoryMetadata metadata = connectionFactory.getMetadata();
assertThat(metadata).isNotNull();
}

protected abstract T createContainer();

protected void runTestQuery(ConnectionFactory connectionFactory) {
Expand Down

0 comments on commit 3530e63

Please sign in to comment.