Skip to content

Commit 68af0f8

Browse files
committed
#61 add customizer to configure postgres container
1 parent a1ae71c commit 68af0f8

File tree

9 files changed

+174
-31
lines changed

9 files changed

+174
-31
lines changed

README.md

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ or through `zonky.test.database.provider` property globally.
228228
### Common Configuration
229229

230230
The `@AutoConfigureEmbeddedDatabase` annotation can be used for some basic configuration, advanced configuration requires properties or yaml files.
231-
The following configuration keys are used by all providers:
231+
The following configuration keys are honored by all providers:
232232

233233
```properties
234234
zonky.test.database.provider=zonky # Provider used to create the underlying embedded database, see the documentation for the comparision matrix.
@@ -339,7 +339,7 @@ Note that not all architectures are supported by all platforms, look here for an
339339

340340
Since `PostgreSQL 10.0`, there are additional artifacts with `alpine-lite` suffix. These artifacts contain postgres binaries for Alpine Linux with disabled [ICU support](https://blog.2ndquadrant.com/icu-support-postgresql-10/) for further size reduction.
341341

342-
#### Zonky-specific provider configuration [![zonky-provider only](https://img.shields.io/badge/-zonky--provider%20only-3399ff.svg)](#database-providers)
342+
#### Zonky-provider specific configuration [![zonky-provider only](https://img.shields.io/badge/-zonky--provider%20only-3399ff.svg)](#database-providers)
343343

344344
The provider configuration can be customized with bean implementing `Consumer<EmbeddedPostgres.Builder>` interface.
345345
The obtained builder provides methods to change the configuration before the database is started.
@@ -392,7 +392,7 @@ public class DockerProviderIntegrationTest {
392392
}
393393
```
394394

395-
#### Docker-specific provider configuration
395+
#### Docker-provider specific configuration
396396

397397
The provider configuration can be controlled by properties in the `zonky.test.database.postgres.docker` group.
398398

@@ -402,6 +402,30 @@ zonky.test.database.postgres.docker.tmpfs.enabled=false # Whether to mount postg
402402
zonky.test.database.postgres.docker.tmpfs.options=rw,noexec,nosuid # Mount options used to configure the tmpfs filesystem.
403403
```
404404

405+
Or, the provider configuration can be also customized with bean implementing `PostgreSQLContainerCustomizer` interface.
406+
407+
```java
408+
import io.zonky.test.db.config.PostgreSQLContainerCustomizer;
409+
410+
@Configuration
411+
public class EmbeddedPostgresConfiguration {
412+
413+
@Bean
414+
public PostgreSQLContainerCustomizer postgresContainerCustomizer() {
415+
return container -> container.withStartupTimeout(Duration.ofSeconds(60L));
416+
}
417+
}
418+
```
419+
420+
```java
421+
@RunWith(SpringRunner.class)
422+
@AutoConfigureEmbeddedDatabase(provider = DOCKER)
423+
@ContextConfiguration(classes = EmbeddedPostgresConfiguration.class)
424+
public class EmbeddedPostgresIntegrationTest {
425+
// class body...
426+
}
427+
```
428+
405429
### Using OpenTable Provider
406430

407431
Before you use OpenTable provider, you must add the following Maven dependency:
@@ -425,7 +449,7 @@ public class OpenTableProviderIntegrationTest {
425449
}
426450
```
427451

428-
#### OpenTable-specific provider configuration
452+
#### OpenTable-provider specific configuration
429453

430454
The provider configuration can be customized with bean implementing `Consumer<EmbeddedPostgres.Builder>` interface.
431455
The obtained builder provides methods to change the configuration before the database is started.
@@ -475,7 +499,7 @@ public class YandexProviderIntegrationTest {
475499
}
476500
```
477501

478-
#### Yandex-specific provider configuration
502+
#### Yandex-provider specific configuration
479503

480504
The provider configuration can be controlled by properties in the `zonky.test.database.postgres.yandex-provider` group.
481505

build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ project(':embedded-database-spring-test') {
162162
compile "org.flywaydb.flyway-test-extensions:flyway-spring-test:$flywayTestVersion"
163163
compile 'com.google.guava:guava:23.0'
164164
compile 'org.tukaani:xz:1.8'
165+
166+
compile('com.cedarsoftware:java-util:1.34.0') {
167+
exclude group: 'org.apache.logging.log4j'
168+
}
165169

166170
testCompile 'org.springframework.boot:spring-boot-starter-test:1.5.19.RELEASE'
167171
testCompile 'ch.qos.logback:logback-classic:1.2.3'
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package io.zonky.test.db.config;
2+
3+
import org.testcontainers.containers.PostgreSQLContainer;
4+
5+
/**
6+
* Callback interface that can be implemented by beans wishing to customize
7+
* the postgres container before it is used by a {@code DockerPostgresDatabaseProvider}.
8+
*/
9+
@FunctionalInterface
10+
public interface PostgreSQLContainerCustomizer {
11+
12+
/**
13+
* Customize the given {@link PostgreSQLContainer}.
14+
* @param container the container to customize
15+
*/
16+
void customize(PostgreSQLContainer container);
17+
18+
}

embedded-database-spring-test/src/main/java/io/zonky/test/db/provider/impl/DockerPostgresDatabaseProvider.java

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616

1717
package io.zonky.test.db.provider.impl;
1818

19+
import com.cedarsoftware.util.DeepEquals;
1920
import com.github.dockerjava.api.command.CreateContainerCmd;
2021
import com.google.common.cache.CacheBuilder;
2122
import com.google.common.cache.CacheLoader;
2223
import com.google.common.cache.LoadingCache;
2324
import com.google.common.collect.ImmutableMap;
25+
import io.zonky.test.db.config.PostgreSQLContainerCustomizer;
2426
import io.zonky.test.db.flyway.BlockingDataSourceWrapper;
2527
import io.zonky.test.db.provider.DatabasePreparer;
2628
import io.zonky.test.db.provider.DatabaseProvider;
@@ -31,6 +33,7 @@
3133
import org.apache.commons.lang3.RandomStringUtils;
3234
import org.postgresql.ds.PGSimpleDataSource;
3335
import org.slf4j.LoggerFactory;
36+
import org.springframework.beans.factory.ObjectProvider;
3437
import org.springframework.core.env.Environment;
3538
import org.testcontainers.containers.PostgreSQLContainer;
3639
import org.testcontainers.containers.output.Slf4jLogConsumer;
@@ -40,19 +43,22 @@
4043
import java.sql.PreparedStatement;
4144
import java.sql.SQLException;
4245
import java.util.HashMap;
46+
import java.util.List;
4347
import java.util.Locale;
4448
import java.util.Map;
4549
import java.util.Objects;
50+
import java.util.Optional;
4651
import java.util.concurrent.Semaphore;
4752
import java.util.function.Consumer;
4853
import java.util.stream.Collectors;
4954

55+
import static java.util.Collections.emptyList;
5056
import static org.testcontainers.containers.PostgreSQLContainer.POSTGRESQL_PORT;
5157

5258
public class DockerPostgresDatabaseProvider implements DatabaseProvider {
5359

54-
private static final String POSTGRES_USERNAME = "postgres";
55-
private static final String POSTGRES_PASSWORD = "docker";
60+
private static final String DEFAULT_POSTGRES_USERNAME = "postgres";
61+
private static final String DEFAULT_POSTGRES_PASSWORD = "docker";
5662

5763
private static final LoadingCache<DatabaseConfig, DatabaseInstance> databases = CacheBuilder.newBuilder()
5864
.build(new CacheLoader<DatabaseConfig, DatabaseInstance>() {
@@ -64,7 +70,7 @@ public DatabaseInstance load(DatabaseConfig config) {
6470
private final DatabaseConfig databaseConfig;
6571
private final ClientConfig clientConfig;
6672

67-
public DockerPostgresDatabaseProvider(Environment environment) {
73+
public DockerPostgresDatabaseProvider(Environment environment, ObjectProvider<List<PostgreSQLContainerCustomizer>> containerCustomizers) {
6874
String dockerImage = environment.getProperty("zonky.test.database.postgres.docker.image", "postgres:10.9-alpine");
6975
String tmpfsOptions = environment.getProperty("zonky.test.database.postgres.docker.tmpfs.options", "rw,noexec,nosuid");
7076
boolean tmpfsEnabled = environment.getProperty("zonky.test.database.postgres.docker.tmpfs.enabled", boolean.class, false);
@@ -73,7 +79,9 @@ public DockerPostgresDatabaseProvider(Environment environment) {
7379
Map<String, String> configProperties = PropertyUtils.extractAll(environment, "zonky.test.database.postgres.server.properties");
7480
Map<String, String> connectProperties = PropertyUtils.extractAll(environment, "zonky.test.database.postgres.client.properties");
7581

76-
this.databaseConfig = new DatabaseConfig(dockerImage, tmpfsOptions, tmpfsEnabled, initdbProperties, configProperties);
82+
List<PostgreSQLContainerCustomizer> customizers = Optional.ofNullable(containerCustomizers.getIfAvailable()).orElse(emptyList());
83+
84+
this.databaseConfig = new DatabaseConfig(dockerImage, tmpfsOptions, tmpfsEnabled, initdbProperties, configProperties, customizers);
7785
this.clientConfig = new ClientConfig(connectProperties);
7886
}
7987

@@ -150,13 +158,15 @@ protected void configure() {
150158
container.withCreateContainerCmdModifier(consumer);
151159
}
152160

153-
container.withUsername(POSTGRES_USERNAME);
154-
container.withPassword(POSTGRES_PASSWORD);
161+
container.withUsername(DEFAULT_POSTGRES_USERNAME);
162+
container.withPassword(DEFAULT_POSTGRES_PASSWORD);
163+
164+
config.customizers.forEach(c -> c.customize(container));
165+
155166
container.start();
156167
container.followOutput(new Slf4jLogConsumer(LoggerFactory.getLogger(DockerPostgresDatabaseProvider.class)));
157168

158169
semaphore = new Semaphore(Integer.parseInt(serverProperties.get("max_connections")));
159-
160170
}
161171

162172
public DatabaseTemplate getTemplate(ClientConfig config, DatabasePreparer preparer) {
@@ -197,8 +207,8 @@ private DataSource getDatabase(String dbName) throws SQLException {
197207
dataSource.setPortNumber(container.getMappedPort(POSTGRESQL_PORT));
198208
dataSource.setDatabaseName(dbName);
199209

200-
dataSource.setUser(POSTGRES_USERNAME);
201-
dataSource.setPassword(POSTGRES_PASSWORD);
210+
dataSource.setUser(container.getUsername());
211+
dataSource.setPassword(container.getPassword());
202212

203213
for (Map.Entry<String, String> entry : config.connectProperties.entrySet()) {
204214
dataSource.setProperty(entry.getKey(), entry.getValue());
@@ -241,13 +251,15 @@ private static class DatabaseConfig {
241251
private final boolean tmpfsEnabled;
242252
private final Map<String, String> initdbProperties;
243253
private final Map<String, String> configProperties;
254+
private final List<PostgreSQLContainerCustomizer> customizers;
244255

245-
private DatabaseConfig(String dockerImage, String tmpfsOptions, boolean tmpfsEnabled, Map<String, String> initdbProperties, Map<String, String> configProperties) {
256+
private DatabaseConfig(String dockerImage, String tmpfsOptions, boolean tmpfsEnabled, Map<String, String> initdbProperties, Map<String, String> configProperties, List<PostgreSQLContainerCustomizer> customizers) {
246257
this.dockerImage = dockerImage;
247258
this.tmpfsOptions = tmpfsOptions;
248259
this.tmpfsEnabled = tmpfsEnabled;
249260
this.initdbProperties = ImmutableMap.copyOf(initdbProperties);
250261
this.configProperties = ImmutableMap.copyOf(configProperties);
262+
this.customizers = customizers;
251263
}
252264

253265
@Override
@@ -259,12 +271,15 @@ public boolean equals(Object o) {
259271
Objects.equals(dockerImage, that.dockerImage) &&
260272
Objects.equals(tmpfsOptions, that.tmpfsOptions) &&
261273
Objects.equals(initdbProperties, that.initdbProperties) &&
262-
Objects.equals(configProperties, that.configProperties);
274+
Objects.equals(configProperties, that.configProperties) &&
275+
DeepEquals.deepEquals(customizers, that.customizers);
263276
}
264277

265278
@Override
266279
public int hashCode() {
267-
return Objects.hash(dockerImage, tmpfsOptions, tmpfsEnabled, initdbProperties, configProperties);
280+
int result = Objects.hash(dockerImage, tmpfsOptions, tmpfsEnabled, initdbProperties, configProperties);
281+
result = 31 * result + DeepEquals.deepHashCode(customizers);
282+
return result;
268283
}
269284
}
270285

embedded-database-spring-test/src/main/java/io/zonky/test/db/provider/impl/OpenTablePostgresDatabaseProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public OpenTablePostgresDatabaseProvider(Environment environment, ObjectProvider
6767
Map<String, String> initdbProperties = PropertyUtils.extractAll(environment, "zonky.test.database.postgres.initdb.properties");
6868
Map<String, String> configProperties = PropertyUtils.extractAll(environment, "zonky.test.database.postgres.server.properties");
6969
Map<String, String> connectProperties = PropertyUtils.extractAll(environment, "zonky.test.database.postgres.client.properties");
70+
7071
List<Consumer<EmbeddedPostgres.Builder>> customizers = Optional.ofNullable(databaseCustomizers.getIfAvailable()).orElse(emptyList());
7172

7273
this.databaseConfig = new DatabaseConfig(initdbProperties, configProperties, customizers);
@@ -122,7 +123,6 @@ private DatabaseInstance(DatabaseConfig config) throws IOException {
122123

123124
postgres = builder.start();
124125
semaphore = new Semaphore(MAX_DATABASE_CONNECTIONS);
125-
126126
}
127127

128128
public DatabaseTemplate getTemplate(ClientConfig config, DatabasePreparer preparer) {

embedded-database-spring-test/src/main/java/io/zonky/test/db/provider/impl/ZonkyPostgresDatabaseProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public ZonkyPostgresDatabaseProvider(Environment environment, ObjectProvider<Lis
7070
Map<String, String> initdbProperties = PropertyUtils.extractAll(environment, "zonky.test.database.postgres.initdb.properties");
7171
Map<String, String> configProperties = PropertyUtils.extractAll(environment, "zonky.test.database.postgres.server.properties");
7272
Map<String, String> connectProperties = PropertyUtils.extractAll(environment, "zonky.test.database.postgres.client.properties");
73+
7374
List<Consumer<EmbeddedPostgres.Builder>> customizers = Optional.ofNullable(databaseCustomizers.getIfAvailable()).orElse(emptyList());
7475

7576
this.databaseConfig = new DatabaseConfig(initdbProperties, configProperties, customizers, isolation);
@@ -126,7 +127,6 @@ private DatabaseInstance(DatabaseConfig config) throws IOException {
126127

127128
postgres = builder.start();
128129
semaphore = new Semaphore(MAX_DATABASE_CONNECTIONS);
129-
130130
}
131131

132132
public DatabaseTemplate getTemplate(ClientConfig config, DatabasePreparer preparer) {

embedded-database-spring-test/src/test/java/io/zonky/test/db/provider/DockerProviderWithConfigurationIntegrationTest.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717
package io.zonky.test.db.provider;
1818

1919
import io.zonky.test.db.AutoConfigureEmbeddedDatabase;
20+
import io.zonky.test.db.config.PostgreSQLContainerCustomizer;
2021
import org.junit.Test;
2122
import org.junit.runner.RunWith;
2223
import org.postgresql.ds.PGSimpleDataSource;
2324
import org.springframework.beans.factory.annotation.Autowired;
25+
import org.springframework.context.annotation.Bean;
26+
import org.springframework.context.annotation.Configuration;
2427
import org.springframework.jdbc.core.JdbcTemplate;
2528
import org.springframework.test.context.ContextConfiguration;
2629
import org.springframework.test.context.TestPropertySource;
@@ -41,12 +44,21 @@
4144
@ContextConfiguration
4245
public class DockerProviderWithConfigurationIntegrationTest {
4346

47+
@Configuration
48+
static class Config {
49+
50+
@Bean
51+
public PostgreSQLContainerCustomizer postgresContainerCustomizer() {
52+
return container -> container.withPassword("docker-postgres");
53+
}
54+
}
55+
4456
@Autowired
4557
private DataSource dataSource;
4658

4759
@Test
4860
public void testDataSource() throws SQLException {
49-
assertThat(dataSource.unwrap(PGSimpleDataSource.class).getPassword()).isEqualTo("docker");
61+
assertThat(dataSource.unwrap(PGSimpleDataSource.class).getPassword()).isEqualTo("docker-postgres");
5062

5163
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
5264
String version = jdbcTemplate.queryForObject("show server_version", String.class);

embedded-database-spring-test/src/test/java/io/zonky/test/db/provider/DockerProviderWithPostgisImageIntegrationTest.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717
package io.zonky.test.db.provider;
1818

1919
import io.zonky.test.db.AutoConfigureEmbeddedDatabase;
20+
import io.zonky.test.db.config.PostgreSQLContainerCustomizer;
2021
import org.junit.Test;
2122
import org.junit.runner.RunWith;
2223
import org.postgresql.ds.PGSimpleDataSource;
2324
import org.springframework.beans.factory.annotation.Autowired;
25+
import org.springframework.context.annotation.Bean;
26+
import org.springframework.context.annotation.Configuration;
2427
import org.springframework.jdbc.core.JdbcTemplate;
2528
import org.springframework.test.context.ContextConfiguration;
2629
import org.springframework.test.context.TestPropertySource;
@@ -40,12 +43,21 @@
4043
@ContextConfiguration
4144
public class DockerProviderWithPostgisImageIntegrationTest {
4245

46+
@Configuration
47+
static class Config {
48+
49+
@Bean
50+
public PostgreSQLContainerCustomizer postgresContainerCustomizer() {
51+
return container -> container.withPassword("docker-postgis");
52+
}
53+
}
54+
4355
@Autowired
4456
private DataSource dataSource;
4557

4658
@Test
4759
public void testDataSource() throws SQLException {
48-
assertThat(dataSource.unwrap(PGSimpleDataSource.class).getPassword()).isEqualTo("docker");
60+
assertThat(dataSource.unwrap(PGSimpleDataSource.class).getPassword()).isEqualTo("docker-postgis");
4961

5062
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
5163

0 commit comments

Comments
 (0)