From de283781b91b38eed7d7c3f158fd06340df6c9d9 Mon Sep 17 00:00:00 2001 From: meyonsoo Date: Sun, 22 Mar 2026 21:53:24 +0900 Subject: [PATCH] feat: add getR2dbcUrl() helper to PostgreSQL, MySQL, and MariaDB R2DBC containers Add a static getR2dbcUrl(container) method to each R2DBCDatabaseContainer implementation for PostgreSQL, MySQL, and MariaDB. This mirrors the existing getJdbcUrl() ergonomics, making R2DBC URL discovery straightforward for reactive backend workflows. Both modern and compatibility package classes are updated. Integration tests verify URL correctness (database name assertion) and actual connectivity with custom credentials. --- .../MariaDBR2DBCDatabaseContainer.java | 9 ++++++ .../MariaDBR2DBCDatabaseContainer.java | 9 ++++++ .../MariaDBR2DBCDatabaseContainerTest.java | 28 +++++++++++++++++++ .../MariaDBR2DBCDatabaseContainerTest.java | 28 +++++++++++++++++++ .../MySQLR2DBCDatabaseContainer.java | 9 ++++++ .../mysql/MySQLR2DBCDatabaseContainer.java | 9 ++++++ .../MySQLR2DBCDatabaseContainerTest.java | 28 +++++++++++++++++++ .../MySQLR2DBCDatabaseContainerTest.java | 28 +++++++++++++++++++ .../PostgreSQLR2DBCDatabaseContainer.java | 9 ++++++ .../PostgreSQLR2DBCDatabaseContainer.java | 9 ++++++ .../PostgreSQLR2DBCDatabaseContainerTest.java | 28 +++++++++++++++++++ .../PostgreSQLR2DBCDatabaseContainerTest.java | 28 +++++++++++++++++++ 12 files changed, 222 insertions(+) diff --git a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java index 99041e83e28..9f0042b04fc 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainer.java @@ -12,6 +12,15 @@ public class MariaDBR2DBCDatabaseContainer implements R2DBCDatabaseContainer { @Delegate(types = Startable.class) private final MariaDBContainer container; + public static String getR2dbcUrl(MariaDBContainer container) { + return String.format( + "r2dbc:mariadb://%s:%d/%s", + container.getHost(), + container.getMappedPort(MariaDBContainer.MARIADB_PORT), + container.getDatabaseName() + ); + } + public static ConnectionFactoryOptions getOptions(MariaDBContainer container) { ConnectionFactoryOptions options = ConnectionFactoryOptions .builder() diff --git a/modules/mariadb/src/main/java/org/testcontainers/mariadb/MariaDBR2DBCDatabaseContainer.java b/modules/mariadb/src/main/java/org/testcontainers/mariadb/MariaDBR2DBCDatabaseContainer.java index 4c9e6350d23..17237564e6e 100644 --- a/modules/mariadb/src/main/java/org/testcontainers/mariadb/MariaDBR2DBCDatabaseContainer.java +++ b/modules/mariadb/src/main/java/org/testcontainers/mariadb/MariaDBR2DBCDatabaseContainer.java @@ -15,6 +15,15 @@ public MariaDBR2DBCDatabaseContainer(MariaDBContainer container) { this.container = container; } + public static String getR2dbcUrl(MariaDBContainer container) { + return String.format( + "r2dbc:mariadb://%s:%d/%s", + container.getHost(), + container.getMappedPort(MariaDBContainer.MARIADB_PORT), + container.getDatabaseName() + ); + } + public static ConnectionFactoryOptions getOptions(MariaDBContainer container) { ConnectionFactoryOptions options = ConnectionFactoryOptions .builder() diff --git a/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java b/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java index 0f4acd889d5..ff22abdcada 100644 --- a/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java +++ b/modules/mariadb/src/test/java/org/testcontainers/containers/MariaDBR2DBCDatabaseContainerTest.java @@ -1,6 +1,11 @@ package org.testcontainers.containers; +import static org.assertj.core.api.Assertions.assertThat; + +import io.r2dbc.spi.ConnectionFactories; +import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.ConnectionFactoryOptions; +import org.junit.jupiter.api.Test; import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest; import org.testcontainers.utility.DockerImageName; @@ -20,4 +25,27 @@ protected String createR2DBCUrl() { protected MariaDBContainer createContainer() { return new MariaDBContainer<>(DockerImageName.parse("mariadb:10.3.39")); } + + @Test + void testGetR2dbcUrl() { + try ( + MariaDBContainer container = new MariaDBContainer<>(DockerImageName.parse("mariadb:10.3.39")) + .withDatabaseName("testdb") + .withUsername("testuser") + .withPassword("testpass") + ) { + container.start(); + String url = MariaDBR2DBCDatabaseContainer.getR2dbcUrl(container); + assertThat(url).contains("/testdb"); + ConnectionFactory connectionFactory = ConnectionFactories.get( + ConnectionFactoryOptions + .parse(url) + .mutate() + .option(ConnectionFactoryOptions.USER, container.getUsername()) + .option(ConnectionFactoryOptions.PASSWORD, container.getPassword()) + .build() + ); + runTestQuery(connectionFactory); + } + } } diff --git a/modules/mariadb/src/test/java/org/testcontainers/mariadb/MariaDBR2DBCDatabaseContainerTest.java b/modules/mariadb/src/test/java/org/testcontainers/mariadb/MariaDBR2DBCDatabaseContainerTest.java index 8260a6937df..2d441075f18 100644 --- a/modules/mariadb/src/test/java/org/testcontainers/mariadb/MariaDBR2DBCDatabaseContainerTest.java +++ b/modules/mariadb/src/test/java/org/testcontainers/mariadb/MariaDBR2DBCDatabaseContainerTest.java @@ -1,6 +1,11 @@ package org.testcontainers.mariadb; +import static org.assertj.core.api.Assertions.assertThat; + +import io.r2dbc.spi.ConnectionFactories; +import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.ConnectionFactoryOptions; +import org.junit.jupiter.api.Test; import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest; import org.testcontainers.utility.DockerImageName; @@ -20,4 +25,27 @@ protected String createR2DBCUrl() { protected MariaDBContainer createContainer() { return new MariaDBContainer(DockerImageName.parse("mariadb:10.3.39")); } + + @Test + void testGetR2dbcUrl() { + try ( + MariaDBContainer container = new MariaDBContainer(DockerImageName.parse("mariadb:10.3.39")) + .withDatabaseName("testdb") + .withUsername("testuser") + .withPassword("testpass") + ) { + container.start(); + String url = MariaDBR2DBCDatabaseContainer.getR2dbcUrl(container); + assertThat(url).contains("/testdb"); + ConnectionFactory connectionFactory = ConnectionFactories.get( + ConnectionFactoryOptions + .parse(url) + .mutate() + .option(ConnectionFactoryOptions.USER, container.getUsername()) + .option(ConnectionFactoryOptions.PASSWORD, container.getPassword()) + .build() + ); + runTestQuery(connectionFactory); + } + } } diff --git a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java index 4bbb542fec8..c91bd5f799b 100644 --- a/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainer.java @@ -12,6 +12,15 @@ public class MySQLR2DBCDatabaseContainer implements R2DBCDatabaseContainer { @Delegate(types = Startable.class) private final MySQLContainer container; + public static String getR2dbcUrl(MySQLContainer container) { + return String.format( + "r2dbc:mysql://%s:%d/%s", + container.getHost(), + container.getMappedPort(MySQLContainer.MYSQL_PORT), + container.getDatabaseName() + ); + } + public static ConnectionFactoryOptions getOptions(MySQLContainer container) { ConnectionFactoryOptions options = ConnectionFactoryOptions .builder() diff --git a/modules/mysql/src/main/java/org/testcontainers/mysql/MySQLR2DBCDatabaseContainer.java b/modules/mysql/src/main/java/org/testcontainers/mysql/MySQLR2DBCDatabaseContainer.java index d2a272559d9..5c1a1b12c23 100644 --- a/modules/mysql/src/main/java/org/testcontainers/mysql/MySQLR2DBCDatabaseContainer.java +++ b/modules/mysql/src/main/java/org/testcontainers/mysql/MySQLR2DBCDatabaseContainer.java @@ -15,6 +15,15 @@ public MySQLR2DBCDatabaseContainer(MySQLContainer container) { this.container = container; } + public static String getR2dbcUrl(MySQLContainer container) { + return String.format( + "r2dbc:mysql://%s:%d/%s", + container.getHost(), + container.getMappedPort(MySQLContainer.MYSQL_PORT), + container.getDatabaseName() + ); + } + public static ConnectionFactoryOptions getOptions(MySQLContainer container) { ConnectionFactoryOptions options = ConnectionFactoryOptions .builder() diff --git a/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java index 42a852ad1f1..5aacf0c72ca 100644 --- a/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/containers/MySQLR2DBCDatabaseContainerTest.java @@ -1,6 +1,11 @@ package org.testcontainers.containers; +import static org.assertj.core.api.Assertions.assertThat; + +import io.r2dbc.spi.ConnectionFactories; +import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.ConnectionFactoryOptions; +import org.junit.jupiter.api.Test; import org.testcontainers.MySQLTestImages; import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest; @@ -20,4 +25,27 @@ protected String createR2DBCUrl() { protected MySQLContainer createContainer() { return new MySQLContainer<>(MySQLTestImages.MYSQL_80_IMAGE); } + + @Test + void testGetR2dbcUrl() { + try ( + MySQLContainer container = new MySQLContainer<>(MySQLTestImages.MYSQL_80_IMAGE) + .withDatabaseName("testdb") + .withUsername("testuser") + .withPassword("testpass") + ) { + container.start(); + String url = MySQLR2DBCDatabaseContainer.getR2dbcUrl(container); + assertThat(url).contains("/testdb"); + ConnectionFactory connectionFactory = ConnectionFactories.get( + ConnectionFactoryOptions + .parse(url) + .mutate() + .option(ConnectionFactoryOptions.USER, container.getUsername()) + .option(ConnectionFactoryOptions.PASSWORD, container.getPassword()) + .build() + ); + runTestQuery(connectionFactory); + } + } } diff --git a/modules/mysql/src/test/java/org/testcontainers/mysql/MySQLR2DBCDatabaseContainerTest.java b/modules/mysql/src/test/java/org/testcontainers/mysql/MySQLR2DBCDatabaseContainerTest.java index 5e86a92347b..315e0614455 100644 --- a/modules/mysql/src/test/java/org/testcontainers/mysql/MySQLR2DBCDatabaseContainerTest.java +++ b/modules/mysql/src/test/java/org/testcontainers/mysql/MySQLR2DBCDatabaseContainerTest.java @@ -1,6 +1,11 @@ package org.testcontainers.mysql; +import static org.assertj.core.api.Assertions.assertThat; + +import io.r2dbc.spi.ConnectionFactories; +import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.ConnectionFactoryOptions; +import org.junit.jupiter.api.Test; import org.testcontainers.MySQLTestImages; import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest; @@ -20,4 +25,27 @@ protected String createR2DBCUrl() { protected MySQLContainer createContainer() { return new MySQLContainer(MySQLTestImages.MYSQL_80_IMAGE); } + + @Test + void testGetR2dbcUrl() { + try ( + MySQLContainer container = new MySQLContainer(MySQLTestImages.MYSQL_80_IMAGE) + .withDatabaseName("testdb") + .withUsername("testuser") + .withPassword("testpass") + ) { + container.start(); + String url = MySQLR2DBCDatabaseContainer.getR2dbcUrl(container); + assertThat(url).contains("/testdb"); + ConnectionFactory connectionFactory = ConnectionFactories.get( + ConnectionFactoryOptions + .parse(url) + .mutate() + .option(ConnectionFactoryOptions.USER, container.getUsername()) + .option(ConnectionFactoryOptions.PASSWORD, container.getPassword()) + .build() + ); + runTestQuery(connectionFactory); + } + } } diff --git a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java index d2b933694c7..4fda70134b3 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainer.java @@ -12,6 +12,15 @@ public final class PostgreSQLR2DBCDatabaseContainer implements R2DBCDatabaseCont @Delegate(types = Startable.class) private final PostgreSQLContainer container; + public static String getR2dbcUrl(PostgreSQLContainer container) { + return String.format( + "r2dbc:postgresql://%s:%d/%s", + container.getHost(), + container.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT), + container.getDatabaseName() + ); + } + public static ConnectionFactoryOptions getOptions(PostgreSQLContainer container) { ConnectionFactoryOptions options = ConnectionFactoryOptions .builder() diff --git a/modules/postgresql/src/main/java/org/testcontainers/postgresql/PostgreSQLR2DBCDatabaseContainer.java b/modules/postgresql/src/main/java/org/testcontainers/postgresql/PostgreSQLR2DBCDatabaseContainer.java index d99d638b100..3d7b07333e7 100644 --- a/modules/postgresql/src/main/java/org/testcontainers/postgresql/PostgreSQLR2DBCDatabaseContainer.java +++ b/modules/postgresql/src/main/java/org/testcontainers/postgresql/PostgreSQLR2DBCDatabaseContainer.java @@ -15,6 +15,15 @@ public PostgreSQLR2DBCDatabaseContainer(PostgreSQLContainer container) { this.container = container; } + public static String getR2dbcUrl(PostgreSQLContainer container) { + return String.format( + "r2dbc:postgresql://%s:%d/%s", + container.getHost(), + container.getMappedPort(PostgreSQLContainer.POSTGRESQL_PORT), + container.getDatabaseName() + ); + } + public static ConnectionFactoryOptions getOptions(PostgreSQLContainer container) { ConnectionFactoryOptions options = ConnectionFactoryOptions .builder() diff --git a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java index fb503bfd659..ec2c753f4d0 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/containers/PostgreSQLR2DBCDatabaseContainerTest.java @@ -1,6 +1,11 @@ package org.testcontainers.containers; +import static org.assertj.core.api.Assertions.assertThat; + +import io.r2dbc.spi.ConnectionFactories; +import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.ConnectionFactoryOptions; +import org.junit.jupiter.api.Test; import org.testcontainers.PostgreSQLTestImages; import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest; @@ -27,4 +32,27 @@ protected ConnectionFactoryOptions getOptions(PostgreSQLContainer container) protected String createR2DBCUrl() { return "r2dbc:tc:postgresql:///db?TC_IMAGE_TAG=10-alpine"; } + + @Test + void testGetR2dbcUrl() { + try ( + PostgreSQLContainer container = new PostgreSQLContainer<>(PostgreSQLTestImages.POSTGRES_TEST_IMAGE) + .withDatabaseName("testdb") + .withUsername("testuser") + .withPassword("testpass") + ) { + container.start(); + String url = PostgreSQLR2DBCDatabaseContainer.getR2dbcUrl(container); + assertThat(url).contains("/testdb"); + ConnectionFactory connectionFactory = ConnectionFactories.get( + ConnectionFactoryOptions + .parse(url) + .mutate() + .option(ConnectionFactoryOptions.USER, container.getUsername()) + .option(ConnectionFactoryOptions.PASSWORD, container.getPassword()) + .build() + ); + runTestQuery(connectionFactory); + } + } } diff --git a/modules/postgresql/src/test/java/org/testcontainers/postgresql/PostgreSQLR2DBCDatabaseContainerTest.java b/modules/postgresql/src/test/java/org/testcontainers/postgresql/PostgreSQLR2DBCDatabaseContainerTest.java index 4f5386d9f58..af40fdde54a 100644 --- a/modules/postgresql/src/test/java/org/testcontainers/postgresql/PostgreSQLR2DBCDatabaseContainerTest.java +++ b/modules/postgresql/src/test/java/org/testcontainers/postgresql/PostgreSQLR2DBCDatabaseContainerTest.java @@ -1,6 +1,11 @@ package org.testcontainers.postgresql; +import static org.assertj.core.api.Assertions.assertThat; + +import io.r2dbc.spi.ConnectionFactories; +import io.r2dbc.spi.ConnectionFactory; import io.r2dbc.spi.ConnectionFactoryOptions; +import org.junit.jupiter.api.Test; import org.testcontainers.PostgreSQLTestImages; import org.testcontainers.r2dbc.AbstractR2DBCDatabaseContainerTest; @@ -27,4 +32,27 @@ protected ConnectionFactoryOptions getOptions(PostgreSQLContainer container) { protected String createR2DBCUrl() { return "r2dbc:tc:postgresql:///db?TC_IMAGE_TAG=10-alpine"; } + + @Test + void testGetR2dbcUrl() { + try ( + PostgreSQLContainer container = new PostgreSQLContainer(PostgreSQLTestImages.POSTGRES_TEST_IMAGE) + .withDatabaseName("testdb") + .withUsername("testuser") + .withPassword("testpass") + ) { + container.start(); + String url = PostgreSQLR2DBCDatabaseContainer.getR2dbcUrl(container); + assertThat(url).contains("/testdb"); + ConnectionFactory connectionFactory = ConnectionFactories.get( + ConnectionFactoryOptions + .parse(url) + .mutate() + .option(ConnectionFactoryOptions.USER, container.getUsername()) + .option(ConnectionFactoryOptions.PASSWORD, container.getPassword()) + .build() + ); + runTestQuery(connectionFactory); + } + } }