Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with two data sources #236

Closed
peterlitvak opened this issue Apr 8, 2023 · 7 comments
Closed

Problem with two data sources #236

peterlitvak opened this issue Apr 8, 2023 · 7 comments
Labels
status: duplicate A duplicate of another issue

Comments

@peterlitvak
Copy link

peterlitvak commented Apr 8, 2023

I have two data sources configured for my test like so:

@AutoConfigureEmbeddedDatabase(beanName = "readOnlyDataSource",
                               type = AutoConfigureEmbeddedDatabase.DatabaseType.POSTGRES,
                               provider = AutoConfigureEmbeddedDatabase.DatabaseProvider.DOCKER,
                               refresh = AutoConfigureEmbeddedDatabase.RefreshMode.BEFORE_EACH_TEST_METHOD)
@AutoConfigureEmbeddedDatabase(beanName = "readWriteDataSource",
                               type = AutoConfigureEmbeddedDatabase.DatabaseType.POSTGRES,
                               provider = AutoConfigureEmbeddedDatabase.DatabaseProvider.DOCKER,
                               refresh = AutoConfigureEmbeddedDatabase.RefreshMode.BEFORE_EACH_TEST_METHOD)

When I execute tests, the queries against readWriteDataSource are executing fine but fail with "relation xyz does not exist" errors on the readOnlyDataSource. What could be the problem here?

@tomix26
Copy link
Collaborator

tomix26 commented Apr 8, 2023

I've already explained it here in detail. Below is the solution for your specific case.

@RunWith(SpringRunner.class)
@DataJpaTest
@AutoConfigureEmbeddedDatabase(beanName = "readWriteDataSource")
public class MultipleDataSourcesTest {

    @TestConfiguration // or @Configuration
    static class Config {

        @Bean
        public DataSource readOnlyDataSource(DataSource readWriteDataSource) {
            ReadOnlyDataSourceAdapter adapter = new ReadOnlyDataSourceAdapter();
            adapter.setTargetDataSource(readWriteDataSource);
            return adapter;
        }
    }

    public static class ReadOnlyDataSourceAdapter extends DelegatingDataSource {

        @Override
        public Connection getConnection() throws SQLException {
            Connection connection = super.getConnection();
            connection.setReadOnly(true);
            return connection;
        }

        @Override
        public Connection getConnection(String username, String password) throws SQLException {
            Connection connection = super.getConnection(username, password);
            connection.setReadOnly(true);
            return connection;
        }
    }

    @Autowired
    @Qualifier("readWriteDataSource")
    private DataSource readWriteDataSource;

    @Autowired
    @Qualifier("readOnlyDataSource")
    private DataSource readOnlyDataSource;

    // class body...
}

@tomix26 tomix26 added the status: waiting-for-feedback We need additional information before we can continue label Apr 8, 2023
@peterlitvak
Copy link
Author

peterlitvak commented Apr 8, 2023

Thank you!
I ended up configuring tests to use actual data sources (defined in the app) connecting to the embedded Postgres.
I used one of the tests you have as an example. It seems to work as expected.

Is this indeed the right way to do this:

public class EmbeddedPostgresInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    public static PostgreSQLContainer<?> postgresContainer = new PostgreSQLContainer<>("postgres:11-alpine");

    static {
        postgresContainer.start();
    }

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {

        applicationContext.getEnvironment().getPropertySources().addFirst(new MapPropertySource(
            "some_name", Map.of(
            "datasource.rw.url", postgresContainer.getJdbcUrl(),
            "datasource.rw.username", postgresContainer.getUsername(),
            "datasource.rw.password", postgresContainer.getPassword(),
            "datasource.ro.url", postgresContainer.getJdbcUrl(),
            "datasource.ro.username", postgresContainer.getUsername(),
            "datasource.ro.password", postgresContainer.getPassword()
        )));
    }
}

in the test:

@ExtendWith(SpringExtension.class)
@SpringBootTest
@ContextConfiguration(classes = MyTestConfiguration.class,
                      initializers = EmbeddedPostgresInitializer.class)
@AutoConfigureEmbeddedDatabase(type = POSTGRES, replace = NONE, refresh = AFTER_EACH_TEST_METHOD)
public class MyIntegTest {
...
}

@tomix26
Copy link
Collaborator

tomix26 commented Apr 8, 2023

Yes, that certainly looks functional. However, you don't actually use this library at all anymore, because the container you are starting this way is out of the control of this library. Which results in refresh = AFTER_EACH_TEST_METHOD having no effect.

@peterlitvak
Copy link
Author

Will it still pull the container?
Is there a better way to preserve the original data sources but have the library do its thing?

@tomix26
Copy link
Collaborator

tomix26 commented Apr 8, 2023

Will it still pull the container?

As I wrote, it will work fine. You just don't use this library and you will lose the benefits it brings.

Is there a better way to preserve the original data sources but have the library do its thing?

The library automatically replaces the original data sources with the testing ones. In general, this should not be a problem, because in most cases the app code refers to the DataSource interface and in tests you rarely care about the specific implementation (e.g. HikariCP). However, no, the library does not allow the use of any specific connection pool in tests.

@peterlitvak
Copy link
Author

Thank you for the explanation!

@tomix26 tomix26 removed the status: waiting-for-feedback We need additional information before we can continue label May 16, 2023
@tomix26
Copy link
Collaborator

tomix26 commented May 16, 2023

I'm closing this issue is favor of #234, which seems to be similar.

@tomix26 tomix26 closed this as completed May 16, 2023
@tomix26 tomix26 added the status: duplicate A duplicate of another issue label May 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

2 participants