zonkyio / embedded-database-spring-test

A library for creating isolated embedded databases for Spring-powered integration tests.
Apache License 2.0
402 stars 37 forks source link

Support for R2DBC #121

Open lukaszweg opened 4 years ago

lukaszweg commented 4 years ago

Hello is there way to use zonky with R2DBC? I tried many things, but nothing help at all. Maybe it is possible to set port? Because as I see hostname, password and username name are always same and problem is with port which changing all time, not allowing to set url in properties

tomix26 commented 4 years ago

Hey, thanks for the question. This library is strongly based on JDBC, so note it needs to be present on the classpath, at least in the test scope. Otherwise, there should be no other problem and it should be enough to create an adapter between JDBC and R2DBC projects. Check the example below.

The only thing to keep in mind is that the injected data source is actually an AOP proxy and the target database may change over time. This happens when the database is refreshed via @FlywayTest annotation. So it is necessary to detect it and create a new connection factory if that happens.

public class EmbeddedPostgresConnectionFactory implements ConnectionFactory {

    private final DataSource dataSource; // an AOP proxy with a changing target database

    private volatile BaseDataSource config; // the last instance of the target database
    private volatile PostgresqlConnectionFactory factory;

    public EmbeddedPostgresConnectionFactory(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    private PostgresqlConnectionFactory connectionFactory() {
        BaseDataSource freshConfig;
        try {
            freshConfig = dataSource.unwrap(BaseDataSource.class);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        if (factory == null || config != freshConfig) { // checks if the target database has changed or not
            config = freshConfig;
            factory = new PostgresqlConnectionFactory(PostgresqlConnectionConfiguration.builder()
                    .host(freshConfig.getServerName())
                    .port(freshConfig.getPortNumber())
                    .username(freshConfig.getUser())
                    .password(freshConfig.getPassword())
                    .database(freshConfig.getDatabaseName())
                    .build());
        }

        return factory;
    }

    @Override
    public Publisher<io.r2dbc.postgresql.api.PostgresqlConnection> create() {
        return connectionFactory().create();
    }

    @Override
    public ConnectionFactoryMetadata getMetadata() {
        return connectionFactory().getMetadata();
    }
}
@RunWith(SpringRunner.class)
@AutoConfigureEmbeddedDatabase(beanName = "dataSource")
public class EmptyDatabaseIntegrationTest {

    @Configuration
    static class Config {

        @Bean
        public ConnectionFactory connectionFactory(DataSource dataSource) {
            return new EmbeddedPostgresConnectionFactory(dataSource);
        }
    }

    @Autowired
    private ConnectionFactory connectionFactory;

    @Test
    public void testMethod() {
        // some testing code...
        Mono.from(connectionFactory.create())
                .flatMapMany(connection -> Flux.from(connection
                        .createBatch()
                        .add("select * from player")
                        .add("select * from player")
                        .execute()))
                .as(StepVerifier::create)
                .expectNextCount(2)
                .verifyComplete();
    }
}
tomix26 commented 4 years ago

I will try to implement this functionality to one of the next releases.

tomix26 commented 4 years ago

Let me know if the solution described above works.

bfrggit commented 3 years ago

@tomix26 I tested your posted version of EmbeddedPostgresConnectionFactory and it works for me. Only a nit that freshConfig.getServerName() and freshConfig.getPortNumber() are deprecated now. Also my IDE warns that the two overriding methods do not have @NonNullApi when the overridden methods are.

tomix26 commented 3 years ago

@bfrggit Ok, thanks for the info 👍

SalyczeQ commented 2 years ago

Hello, is this still planned to be implemented in new releases? :)

tomix26 commented 2 years ago

Hi, maybe sometime in the future. Now it doesn't have enough priority for me. However, you can still use the example above, or prepare a pull request on your own. Any help is welcome 😉

neeru-bhaskar commented 1 year ago

@tomix26 Can you post the complete code. I am trying to test my r2dbc application using zonky embedded postgres. I could not get the above example work for me.

tomix26 commented 1 year ago

@neeru-bhaskar I'm sorry, but R2DBC is not yet supported. I did my best in the example above.

d-wire commented 1 year ago

Where is the class BaseDataSource in your example coming from? Trying to figure out which dependency I'm missing since I don't seem to be able to import that class.

tomix26 commented 1 year ago

Where is the class BaseDataSource in your example coming from? Trying to figure out which dependency I'm missing since I don't seem to be able to import that class.

BaseDataSource is a class of the postgres jdbc driver. As I mentioned at the beginning of this conversation:

This library is strongly based on JDBC, so note it needs to be present on the classpath, at least in the test scope.