embedded-database-spring-test icon indicating copy to clipboard operation
embedded-database-spring-test copied to clipboard

Support for R2DBC

Open lukaszweg opened this issue 4 years ago • 11 comments

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

lukaszweg avatar Oct 06 '20 12:10 lukaszweg

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 avatar Oct 07 '20 16:10 tomix26

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

tomix26 avatar Oct 07 '20 16:10 tomix26

Let me know if the solution described above works.

tomix26 avatar Oct 07 '20 16:10 tomix26

@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.

bfrggit avatar Mar 24 '21 17:03 bfrggit

@bfrggit Ok, thanks for the info 👍

tomix26 avatar Mar 26 '21 14:03 tomix26

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

SalyczeQ avatar Oct 12 '21 14:10 SalyczeQ

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 😉

tomix26 avatar Nov 14 '21 17:11 tomix26

@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.

neeru-bhaskar avatar Oct 31 '22 21:10 neeru-bhaskar

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

tomix26 avatar Nov 12 '22 18:11 tomix26

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.

d-wire avatar Jul 31 '23 19:07 d-wire

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.

tomix26 avatar Aug 03 '23 11:08 tomix26