jeudi 13 février 2020

spring testcontainers multiple datasources

Currently, I am working in a Spring Boot (2.2.4) project with Spring Data JPA. Currently we have configured 2 datasources, since we have 2 databases (on the same host), like described here: https://springframework.guru/how-to-configure-multiple-data-sources-in-a-spring-boot-application/ or here: https://www.baeldung.com/spring-data-jpa-multiple-databases

So my application.yml file looks like this:

     app:
      datasource:
        db-1:
          url: jdbc:mariadb://db:3306/db1
          username: ***
          password: ***
          ....

        db-2:
          url: jdbc:mariadb://db:3306/db2
          username: ***
          password: ***
          ....

I am using testcontainers (https://www.testcontainers.org/) and JUnit 5 to do integration tests. Everything works fine with a single datasource, however it gets tricky when using two datasources.

Here some pseudo-code for my IntegrationTest:

@SpringBootTest
@ExtendWith(TestExtension.class)
class IntegrationTest{

 @Test
 public void test() {
  repositoryDatabase1.saveInDatabase1
 }

 @Test
 public void secondTest() {
  repositoryDatabase2.readFromDatabase2
 }

}

You may have noticed that I have defined a Junit5-Extension: "TestExtensions.class", that is extended by my IntegrationTest. This extension contains the logic to manage the containers:

   public class TestExtension
            implements BeforeAllCallback, AfterAllCallback {

        @Override
        public void beforeAll(ExtensionContext context) {

            MariaDBContainer container = 
                 new MariaDBContainer("mariadb:10.4.0").withDatabaseName("db1");

            container.start();

            System.setProperty("app.datasource.db1.url", container.getJdbcUrl());
            System.setProperty("app.datasource.db1.username", container.getUsername());
            System.setProperty("app.datasource.db1.password", container.getPassword());

            context
                    .getStore(ExtensionContext.Namespace.GLOBAL)
                    .put(MariaDBContainer.class.getSimpleName() , container);
        }

        @Override
        public void afterAll(ExtensionContext context) {
            context
                    .getStore(ExtensionContext.Namespace.GLOBAL)
                    .get(MariaDBContainer.class.getSimpleName(), MariaDBContainer.class)
                    .stop();
        }
    }

So we start a MariaDBContainer, and we set also the system properties (jdb-url, username, password) so our application can talk to the database. This setup work fine for a single data-source, however I want my integration tests to be able to talk to two different datasources.

I tried adding the properties for my second-datasource in my extension as well like this, so they are available and the application uses this to connect to the second db:

System.setProperty("app.datasource.db1.url", container.getJdbcUrl());
System.setProperty("app.datasource.db1.username", container.getUsername());
System.setProperty("app.datasource.db1.password", container.getPassword());

System.setProperty("app.datasource.db2.url", "jdbc:mariadb://db:3306/db2");
System.setProperty("app.datasource.db2.username", container.getUsername());
System.setProperty("app.datasource.db2.password", container.getPassword());

However, this doesn't work, I always get the error: Bad Credentials. I am not sure if it's possible to have different datasources in the same container, since you only can define single database-name/schema when you start the db-container:

MariaDBContainer container = 
                     new MariaDBContainer("mariadb:10.4.0").withDatabaseName("db1");

I am not sure how to solve this problem.

Aucun commentaire:

Enregistrer un commentaire