testcontainers / testcontainers-java

Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.
https://testcontainers.org
MIT License
7.97k stars 1.64k forks source link

Allow consumption of a relational database testcontainer through R2DBC #1003

Open mp911de opened 5 years ago

mp911de commented 5 years ago

R2DBC is an initiative to establish a reactive API for relational database integration. It would be great to additionally consume a test container with a relational database through R2DBC by exposing the connection through a preconfigured ConnectionFactory.

ConnectionFactory is in R2DBC what a DataSource is in JDBC. R2DBC drivers are available for:

More to come eventually.

Right now I can think of the following consumption scenarios:

mp911de commented 5 years ago

I took a look at how R2DBC could be implemented and found that a suitable implementation might be hard to achieve because of the way how containers are organized.

Here are my thoughts:

SQL databases are assumed to be JDBC containers and not Database containers. Adding a getR2dbcConnectionUrl() would provide a pre-constructed URL for R2DBC usage on specific containers. At the same time, it would make sense to have a common interface for database I/O. What would be the right place for such an interface?

Ideally, database containers are represented as subclass of DatabaseContainer or SqlDatabaseContainer where DatabaseContainer exposes several methods that are now defined on JdbcDatabaseContainer (such as getUsername, getPassword, getTestQueryString, withInitScript, withConnectTimeoutSeconds).

JdbcDatabaseContainer could potentially survive as a general-purpose container. The actual container implementations (MySQLContainer, PostgreSQLContainer) would extend DatabaseContainer and implement a JDBC-specific interface. Containers, which are also available with R2DBC access, would implement an R2DBC-specific interface.

This brings us ultimately to ContainerDatabaseDriver: ContainerDatabaseDriver holds references to started containers. Now, if we would like to provide a similar feature for R2DBC, then we would need to replicate what happens in ContainerDatabaseDriver.

If a test wants to use JDBC and R2DBC using URL-based container bootstrapping, then potentially, we would end up with two container instances. But what we rather want to achieve is a test setup where both integration technologies (JDBC and R2DBC) point to the same database (jdbc:tc:mysql:5.6.23://somehostname:someport/databasename and r2dbc:tc:mysql:5.6.23://somehostname:someport/databasename). This is because typical bootstrapping use-cases (schema and data setup) fully synchronous cases whereas running application code would use R2DBC technology.

That being said, a potential design could be:

This way, containers can be consumed without pulling R2DBC API and are appropriately segregated by access technology.

Let me know what you think, whether that is something worth pursuing.

n0mer commented 3 years ago

@mp911de @kiview maybe it's worth considering implementation provided by @lmyslinski in #1141 ? He made it work back in 2019