2

I'm using both r2dbc and Liquibase in the same application. However, Liquibase is not able to run migrations using r2dbc so I need to use a separate jdbc driver just for it.

I followed the solution here, and used testcontainers for testing, so my application-test.yaml looks exactly like this:

spring:
  liquibase:
    url: jdbc:tc:postgresql:14.1:///testdb
  r2dbc:
    url: r2dbc:tc:postgresql:///testdb?TC_IMAGE_TAG=14.1

This works perfectly, migrations are launched and then the queries are able to run. The problem is, that this starts two different containers! So the migrations are run against one of them, and the queries against the other, and thus they find the database empty.

Is there any way I can tell testcontainers to use the same container for both connections.

Haf
  • 375
  • 1
  • 3
  • 13
  • Welcome to Stack Overflow. If possible, please do not refer to another source to provide information that is critical to your question. Your question should be able to be understood even if the external links it refers to all became broken. You'd be better off copying portions of the content at the end of that link and supplying them in the body of your question. – CryptoFool Feb 13 '22 at 18:50

1 Answers1

5

When you use Testcontainers' JDBC support, which you configure by adding tc in the jdbc url, the lifecycle of the container is managed automatically. Since you have two different urls instrumented like that, you get 2 containers.

Instead you can choose a different way to manage the lifecycle that gives you more control.

You can either do it yourself by creating a containers instances and calling start()/stop() or for example use JUnit integration which will correspond containers lifecycle with the tests lifecycle.

For example for JUnit5, you mark you class with @Testcontainers and the fields with @Container, something like:

@Testcontainers
class MixedLifecycleTests {
    @Container
    private static PostgreSQLContainer postgresqlContainer = new PostgreSQLContainer();
}

Since you're working on a Spring application you want to configure it to use the container, for that use @DynamicPropertySource: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/context/DynamicPropertySource.html

In a nutshell, you mark a method with it and inside it configure Spring to use the databases in the container:

@DynamicPropertySource
static void redisProperties(DynamicPropertyRegistry registry) {
  registry.add("spring.datasource.url", postgresqlContainer:: getJdbcUrl);
  registry.add("spring.datasource.username", postgresqlContainer::getUsername);
  registry.add("spring.datasource.password", postgresqlContainer::getPassword);

  registry.add("spring.r2dbc.url", () -> "r2dbc:postgresql://"
                + postgreSQLContainer.getHost() + ":" + postgreSQLContainer.getFirstMappedPort()
                + "/" + postgreSQLContainer.getDatabaseName());
  registry.add("spring.r2dbc.username", postgreSQLContainer::getUsername);
  registry.add("spring.r2dbc.password", postgreSQLContainer::getPassword);
}

Note that since your app uses r2dbc and Liquibase works with non-reactive jdbc you should configure both.

Oleg Šelajev
  • 3,530
  • 1
  • 17
  • 25
  • 1
    Thank you, a surprisingly good answer. Though I have to specify that I'm using Liquibase and not Flyway, but surely that was just a typo – Haf Feb 14 '22 at 11:32
  • 1
    ha! indeed, you had it in the question and I mixed it up with Flyway. Sorry! The idea stands and you probably need to configure the jdbc url or liqubase properties in addition to r2dbc. – Oleg Šelajev Feb 14 '22 at 15:04