/* * Copyright 2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.zonky.test.db.provider.impl; import io.zonky.test.db.config.PostgreSQLContainerCustomizer; import io.zonky.test.db.flyway.BlockingDataSourceWrapper; import io.zonky.test.db.provider.DatabasePreparer; import io.zonky.test.db.provider.DatabaseType; import io.zonky.test.db.provider.ProviderType; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.postgresql.ds.PGSimpleDataSource; import org.springframework.beans.factory.ObjectProvider; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.mock.env.MockEnvironment; import javax.sql.DataSource; import java.sql.SQLException; import java.time.Duration; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class DockerPostgresDatabaseProviderTest { @Mock private ObjectProvider<List<PostgreSQLContainerCustomizer>> containerCustomizers; @Before public void setUp() { when(containerCustomizers.getIfAvailable()).thenReturn(Collections.emptyList()); } @Test public void databaseTypeShouldBePostgres() { DockerPostgresDatabaseProvider provider = new DockerPostgresDatabaseProvider(new MockEnvironment(), containerCustomizers); assertThat(provider.getDatabaseType()).isEqualTo(DatabaseType.POSTGRES); } @Test public void providerTypeShouldBeDocker() { DockerPostgresDatabaseProvider provider = new DockerPostgresDatabaseProvider(new MockEnvironment(), containerCustomizers); assertThat(provider.getProviderType()).isEqualTo(ProviderType.DOCKER); } @Test public void testGetDatabase() throws SQLException { DockerPostgresDatabaseProvider provider = new DockerPostgresDatabaseProvider(new MockEnvironment(), containerCustomizers); DatabasePreparer preparer1 = dataSource -> { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); jdbcTemplate.update("create table prime_number (number int primary key not null)"); }; DatabasePreparer preparer2 = dataSource -> { JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); jdbcTemplate.update("create table prime_number (id int primary key not null, number int not null)"); }; DataSource dataSource1 = provider.getDatabase(preparer1); DataSource dataSource2 = provider.getDatabase(preparer1); DataSource dataSource3 = provider.getDatabase(preparer2); assertThat(dataSource1).isNotNull().isExactlyInstanceOf(BlockingDataSourceWrapper.class); assertThat(dataSource2).isNotNull().isExactlyInstanceOf(BlockingDataSourceWrapper.class); assertThat(dataSource3).isNotNull().isExactlyInstanceOf(BlockingDataSourceWrapper.class); assertThat(getPort(dataSource1)).isEqualTo(getPort(dataSource2)); assertThat(getPort(dataSource2)).isEqualTo(getPort(dataSource3)); JdbcTemplate jdbcTemplate1 = new JdbcTemplate(dataSource1); jdbcTemplate1.update("insert into prime_number (number) values (?)", 2); assertThat(jdbcTemplate1.queryForObject("select count(*) from prime_number", Integer.class)).isEqualTo(1); JdbcTemplate jdbcTemplate2 = new JdbcTemplate(dataSource2); jdbcTemplate2.update("insert into prime_number (number) values (?)", 3); assertThat(jdbcTemplate2.queryForObject("select count(*) from prime_number", Integer.class)).isEqualTo(1); JdbcTemplate jdbcTemplate3 = new JdbcTemplate(dataSource3); jdbcTemplate3.update("insert into prime_number (id, number) values (?, ?)", 1, 5); assertThat(jdbcTemplate3.queryForObject("select count(*) from prime_number", Integer.class)).isEqualTo(1); } @Test public void testContainerCustomizers() throws SQLException { when(containerCustomizers.getIfAvailable()).thenReturn(Collections.singletonList(container -> container.withPassword("test"))); DatabasePreparer preparer = dataSource -> {}; DockerPostgresDatabaseProvider provider = new DockerPostgresDatabaseProvider(new MockEnvironment(), containerCustomizers); DataSource dataSource = provider.getDatabase(preparer); assertThat(dataSource.unwrap(PGSimpleDataSource.class).getPassword()).isEqualTo("test"); } @Test public void providersWithSameCustomizersShouldEquals() { when(containerCustomizers.getIfAvailable()).thenReturn( Collections.singletonList(postgresContainerCustomizer(61)), Collections.singletonList(postgresContainerCustomizer(61))); DockerPostgresDatabaseProvider provider1 = new DockerPostgresDatabaseProvider(new MockEnvironment(), containerCustomizers); DockerPostgresDatabaseProvider provider2 = new DockerPostgresDatabaseProvider(new MockEnvironment(), containerCustomizers); assertThat(provider1).isEqualTo(provider2); } @Test public void providersWithDifferentCustomizersShouldNotEquals() { when(containerCustomizers.getIfAvailable()).thenReturn( Collections.singletonList(postgresContainerCustomizer(60)), Collections.singletonList(postgresContainerCustomizer(61))); DockerPostgresDatabaseProvider provider1 = new DockerPostgresDatabaseProvider(new MockEnvironment(), containerCustomizers); DockerPostgresDatabaseProvider provider2 = new DockerPostgresDatabaseProvider(new MockEnvironment(), containerCustomizers); assertThat(provider1).isNotEqualTo(provider2); } @Test public void testConfigurationProperties() throws SQLException { MockEnvironment environment = new MockEnvironment(); environment.setProperty("zonky.test.database.postgres.docker.image", "postgres:9.6.11-alpine"); environment.setProperty("zonky.test.database.postgres.client.properties.stringtype", "unspecified"); environment.setProperty("zonky.test.database.postgres.initdb.properties.lc-collate", "cs_CZ.UTF-8"); environment.setProperty("zonky.test.database.postgres.server.properties.max_connections", "100"); environment.setProperty("zonky.test.database.postgres.server.properties.shared_buffers", "64MB"); DatabasePreparer preparer = dataSource -> {}; DockerPostgresDatabaseProvider provider = new DockerPostgresDatabaseProvider(environment, containerCustomizers); DataSource dataSource = provider.getDatabase(preparer); assertThat(dataSource.unwrap(PGSimpleDataSource.class).getProperty("stringtype")).isEqualTo("unspecified"); JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); String postgresVersion = jdbcTemplate.queryForObject("show server_version", String.class); assertThat(postgresVersion).startsWith("9.6."); String collate = jdbcTemplate.queryForObject("show lc_collate", String.class); assertThat(collate).isEqualTo("cs_CZ.UTF-8"); String maxConnections = jdbcTemplate.queryForObject("show max_connections", String.class); assertThat(maxConnections).isEqualTo("100"); String sharedBuffers = jdbcTemplate.queryForObject("show shared_buffers", String.class); assertThat(sharedBuffers).isEqualTo("64MB"); } @Test public void providersWithDefaultConfigurationShouldEquals() { MockEnvironment environment = new MockEnvironment(); DockerPostgresDatabaseProvider provider1 = new DockerPostgresDatabaseProvider(environment, containerCustomizers); DockerPostgresDatabaseProvider provider2 = new DockerPostgresDatabaseProvider(environment, containerCustomizers); assertThat(provider1).isEqualTo(provider2); } @Test public void providersWithSameConfigurationShouldEquals() { MockEnvironment environment = new MockEnvironment(); environment.setProperty("zonky.test.database.postgres.docker.image", "test-image"); environment.setProperty("zonky.test.database.postgres.docker.tmpfs.options", "mount-options"); environment.setProperty("zonky.test.database.postgres.docker.tmpfs.enabled", "true"); environment.setProperty("zonky.test.database.postgres.initdb.properties.xxx", "xxx-value"); environment.setProperty("zonky.test.database.postgres.server.properties.yyy", "yyy-value"); environment.setProperty("zonky.test.database.postgres.client.properties.zzz", "zzz-value"); DockerPostgresDatabaseProvider provider1 = new DockerPostgresDatabaseProvider(environment, containerCustomizers); DockerPostgresDatabaseProvider provider2 = new DockerPostgresDatabaseProvider(environment, containerCustomizers); assertThat(provider1).isEqualTo(provider2); } @Test public void providersWithDifferentConfigurationShouldNotEquals() { Map<String, String> mockProperties = new HashMap<>(); mockProperties.put("zonky.test.database.postgres.docker.image", "test-image"); mockProperties.put("zonky.test.database.postgres.docker.tmpfs.options", "mount-options"); mockProperties.put("zonky.test.database.postgres.docker.tmpfs.enabled", "true"); mockProperties.put("zonky.test.database.postgres.initdb.properties.xxx", "xxx-value"); mockProperties.put("zonky.test.database.postgres.server.properties.yyy", "yyy-value"); mockProperties.put("zonky.test.database.postgres.client.properties.zzz", "zzz-value"); Map<String, String> diffProperties = new HashMap<>(); diffProperties.put("zonky.test.database.postgres.docker.image", "diff-test-image"); diffProperties.put("zonky.test.database.postgres.docker.tmpfs.options", "diff-mount-options"); diffProperties.put("zonky.test.database.postgres.docker.tmpfs.enabled", "false"); diffProperties.put("zonky.test.database.postgres.initdb.properties.xxx", "xxx-diff-value"); diffProperties.put("zonky.test.database.postgres.server.properties.yyy", "yyy-diff-value"); diffProperties.put("zonky.test.database.postgres.client.properties.zzz", "zzz-diff-value"); for (Entry<String, String> diffProperty : diffProperties.entrySet()) { MockEnvironment environment1 = new MockEnvironment(); MockEnvironment environment2 = new MockEnvironment(); for (Entry<String, String> mockProperty : mockProperties.entrySet()) { environment1.setProperty(mockProperty.getKey(), mockProperty.getValue()); environment2.setProperty(mockProperty.getKey(), mockProperty.getValue()); } environment2.setProperty(diffProperty.getKey(), diffProperty.getValue()); DockerPostgresDatabaseProvider provider1 = new DockerPostgresDatabaseProvider(environment1, containerCustomizers); DockerPostgresDatabaseProvider provider2 = new DockerPostgresDatabaseProvider(environment2, containerCustomizers); assertThat(provider1).isNotEqualTo(provider2); } } private static int getPort(DataSource dataSource) throws SQLException { return dataSource.unwrap(PGSimpleDataSource.class).getPortNumber(); } private static PostgreSQLContainerCustomizer postgresContainerCustomizer(long timeout) { return container -> container.withStartupTimeout(Duration.ofSeconds(timeout)); } }