rajadilipkolli
rajadilipkolli

Reputation: 3601

How to enable multiple databases of ServiceConnection type using testcontainer in a spring boot application

I am using multipleDatasources in my spring boot application where we connect to postgres and mysql. it is working as expected but when I want to integrate it with TestContainers in dev mode . I have written code as below


@TestConfiguration(proxyBeanMethods = false)
public class TestMultipleDataSourcesApplication {

    @ServiceConnection
    @Bean
    //@DependsOn("mySQLContainer")
    PostgreSQLContainer<?> postgreSQLContainer(DynamicPropertyRegistry dynamicPropertyRegistry) {
        PostgreSQLContainer<?> postgreSQLContainer =
                new PostgreSQLContainer<>("postgres:16.0-alpine");
        dynamicPropertyRegistry.add("app.datasource.member.url", postgreSQLContainer::getJdbcUrl);
        dynamicPropertyRegistry.add(
                "app.datasource.member.username", postgreSQLContainer::getUsername);
        dynamicPropertyRegistry.add(
                "app.datasource.member.password", postgreSQLContainer::getPassword);
        return postgreSQLContainer;
    }

    @ServiceConnection
    @Bean
    MySQLContainer<?> mySQLContainer(DynamicPropertyRegistry dynamicPropertyRegistry) {
        MySQLContainer<?> mySQLContainer = new MySQLContainer<>("mysql:8.1");
        dynamicPropertyRegistry.add("app.datasource.cardholder.url", mySQLContainer::getJdbcUrl);
        dynamicPropertyRegistry.add(
                "app.datasource.cardholder.username", mySQLContainer::getUsername);
        dynamicPropertyRegistry.add(
                "app.datasource.cardholder.password", mySQLContainer::getPassword);
        return mySQLContainer;
    }

    public static void main(String[] args) {
        SpringApplication.from(MultipleDataSourcesApplication::main)
                .with(TestMultipleDataSourcesApplication.class)
                .run(args);
    }
}

Only the postgresql Bean is getting started and mySQLContainer is getting discarded. to force start mySQLContainer I have added @DependsOn("mySQLContainer") on PostgreSQLContainer then it is getting started. My application uses flyway for connecting to mysql and liquibase for connecting to postgres as below

## Flyway uses mysql database
spring.flyway.url=${app.datasource.cardholder.url}
spring.flyway.user=${app.datasource.cardholder.username}
spring.flyway.password=${app.datasource.cardholder.password}

## Liquibase used postgres Database
spring.liquibase.url=${app.datasource.member.url}
spring.liquibase.user=${app.datasource.member.username}
spring.liquibase.password=${app.datasource.member.password}

When starting databases using above method, even my flyway is connecting to postgresqlserver instead of mysqlserver.

What is the correct way to start more than one database related ServiceConnection and how to ensure that after setting the urls it is connecting to correct liquibase or flyway instances?

source code : https://github.com/rajadilipkolli-throwaway/boot-data-multipledatasources

Edit 1:

If you are using spring boot 3.4.0+ then above can be achieve by below code

@TestConfiguration(proxyBeanMethods = false)
public class ContainersConfiguration {

    private MySQLContainer<?> mySQLContainer;
    private PostgreSQLContainer<?> postgreSQLContainer;

    @Bean
    MySQLContainer<?> mySQLContainer() {
        mySQLContainer = new MySQLContainer<>(DockerImageName.parse("mysql").withTag("9.1"));
        mySQLContainer.start();
        return mySQLContainer;
    }

    @Bean
    PostgreSQLContainer<?> postgreSQLContainer() {
        postgreSQLContainer =
                new PostgreSQLContainer<>(DockerImageName.parse("postgres").withTag("17.0-alpine"));
        postgreSQLContainer.start();
        return postgreSQLContainer;
    }

    @Bean
    public DynamicPropertyRegistrar databaseProperties(
            MySQLContainer<?> mySQLContainer, PostgreSQLContainer<?> postgreSQLContainer) {
        return (properties) -> {
            // Connect our Spring application to our Testcontainers instances
            properties.add("app.datasource.cardholder.url", mySQLContainer::getJdbcUrl);
            properties.add("app.datasource.cardholder.username", mySQLContainer::getUsername);
            properties.add("app.datasource.cardholder.password", mySQLContainer::getPassword);
            properties.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl);
            properties.add("spring.datasource.username", postgreSQLContainer::getUsername);
            properties.add("spring.datasource.password", postgreSQLContainer::getPassword);
        };
    }

Working code here

Upvotes: 1

Views: 1003

Answers (1)

Arno
Arno

Reputation: 336

Have you tried to define a spring test profile specifiying jdbc url like jdbc:tc:mysql:8.1:///cardholderdb

So Testcontainer's JDBC driver would automatically start the mysql container without your definition in TestMultipleDataSourcesApplication. I'd suggest to do the same for postgres using the jdbc:tc:postgresql:16.0-alpine:///memberdb

see https://java.testcontainers.org/modules/databases/jdbc/ for more details

Upvotes: 0

Related Questions