Skip to content

Commit 153e577

Browse files
committed
#6 upgrade to otj-pg-embedded 0.12.0
1 parent 7e47c96 commit 153e577

File tree

7 files changed

+164
-18
lines changed

7 files changed

+164
-18
lines changed

build.gradle

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ ext {
1313

1414
flywayCoreVersions = ['3.0', '3.1', '3.2.1', '4.0.3', '4.1.2']
1515
flywayTestExtensionsVersions = ['3.0.1', '3.1', '3.2.1.1', '4.0.1', '4.1.0']
16+
embeddedPostgresVersions = ['9.3.23', '9.4.18', '9.5.13', '9.6.9', '10.4.0']
17+
18+
postgresVersion = embeddedPostgresVersions.last()
1619
}
1720

1821
allprojects {
@@ -132,10 +135,10 @@ project(':embedded-database-spring-test-autoconfigure') {
132135

133136
project(':embedded-database-spring-test') {
134137
dependencies {
135-
runtime 'io.zonky.test.postgres:embedded-postgres-binaries-windows-amd64:10.4.0'
136-
runtime 'io.zonky.test.postgres:embedded-postgres-binaries-darwin-amd64:10.4.0'
137-
runtime 'io.zonky.test.postgres:embedded-postgres-binaries-linux-amd64:10.4.0'
138-
runtime 'io.zonky.test.postgres:embedded-postgres-binaries-linux-amd64-alpine:10.4.0'
138+
runtime "io.zonky.test.postgres:embedded-postgres-binaries-windows-amd64:$postgresVersion"
139+
runtime "io.zonky.test.postgres:embedded-postgres-binaries-darwin-amd64:$postgresVersion"
140+
runtime "io.zonky.test.postgres:embedded-postgres-binaries-linux-amd64:$postgresVersion"
141+
runtime "io.zonky.test.postgres:embedded-postgres-binaries-linux-amd64-alpine:$postgresVersion"
139142

140143
compile project(':embedded-database-spring-test-autoconfigure')
141144
compile 'org.springframework:spring-context:4.3.10.RELEASE'
@@ -150,7 +153,7 @@ project(':embedded-database-spring-test') {
150153
testCompile 'ch.qos.logback:logback-classic:1.2.3'
151154

152155
// some classes of otj-pg-embedded component are repackaged into the shadowed jar
153-
included 'com.opentable.components:otj-pg-embedded:0.9.0'
156+
included 'com.opentable.components:otj-pg-embedded:0.12.0'
154157
configurations.included.incoming.resolutionResult.allDependencies { result ->
155158
compile result.getRequested().getDisplayName()
156159
}
@@ -175,12 +178,11 @@ project(':embedded-database-spring-test') {
175178
})
176179
}
177180

178-
exclude 'com/opentable/db/postgres/embedded/BundledPostgresBinaryResolver.class'
179181
exclude 'com/opentable/db/postgres/junit/**'
180182
exclude '.repacked'
181183
exclude '*.txz'
182184

183-
relocate 'com.opentable.db.postgres.embedded', 'io.zonky.test.db.postgres.embedded'
185+
relocate 'com.opentable.db.postgres.embedded', 'io.zonky.test.db.shaded.com.opentable.db.postgres.embedded'
184186
}
185187

186188
jar {
@@ -214,6 +216,19 @@ project(':embedded-database-spring-test') {
214216
}
215217
}
216218
}
219+
220+
embeddedPostgresVersions.init().each { version ->
221+
"testRuntimeWithEmbeddedPostgres$version" {
222+
extendsFrom testRuntime
223+
resolutionStrategy {
224+
eachDependency { details ->
225+
if (details.requested.group == 'io.zonky.test.postgres') {
226+
details.useVersion "$version"
227+
}
228+
}
229+
}
230+
}
231+
}
217232
}
218233

219234
for (version in flywayCoreVersions) {
@@ -250,6 +265,16 @@ project(':embedded-database-spring-test') {
250265
check.dependsOn("testWithFlywayTestExtensions$version")
251266
}
252267

268+
embeddedPostgresVersions.init().each { version ->
269+
task "testWithEmbeddedPostgres$version"(type: Test) {
270+
dependsOn jar
271+
272+
classpath -= configurations.testRuntime
273+
classpath += configurations."testRuntimeWithEmbeddedPostgres$version"
274+
}
275+
check.dependsOn("testWithEmbeddedPostgres$version")
276+
}
277+
253278
tasks.withType(Test) {
254279
testLogging {
255280
showStandardStreams = true

embedded-database-spring-test/src/main/java/io/zonky/test/db/flyway/DefaultFlywayDataSourceContext.java

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,31 @@
1919
import com.google.common.cache.CacheBuilder;
2020
import com.google.common.cache.CacheLoader;
2121
import com.google.common.cache.LoadingCache;
22+
import com.google.common.collect.ImmutableList;
2223
import com.opentable.db.postgres.embedded.DatabasePreparer;
24+
import com.opentable.db.postgres.embedded.EmbeddedPostgres.Builder;
2325
import com.opentable.db.postgres.embedded.PreparedDbProvider;
26+
import io.zonky.test.db.postgres.embedded.DefaultPostgresBinaryResolver;
2427
import org.apache.commons.lang3.exception.ExceptionUtils;
2528
import org.flywaydb.core.Flyway;
2629
import org.postgresql.ds.PGSimpleDataSource;
30+
import org.springframework.beans.factory.annotation.Autowired;
2731
import org.springframework.core.task.TaskExecutor;
2832
import org.springframework.util.concurrent.CompletableToListenableFutureAdapter;
2933
import org.springframework.util.concurrent.ListenableFuture;
3034

3135
import javax.sql.DataSource;
3236
import java.io.IOException;
3337
import java.sql.SQLException;
38+
import java.time.Duration;
39+
import java.util.ArrayList;
40+
import java.util.List;
3441
import java.util.Objects;
3542
import java.util.concurrent.CompletableFuture;
3643
import java.util.concurrent.CompletionException;
3744
import java.util.concurrent.Executor;
3845
import java.util.concurrent.Semaphore;
46+
import java.util.function.Consumer;
3947

4048
import static com.google.common.base.Preconditions.checkState;
4149

@@ -52,19 +60,31 @@
5260
*/
5361
public class DefaultFlywayDataSourceContext implements FlywayDataSourceContext {
5462

55-
protected static final int DEFAULT_MAX_RETRY_ATTEMPTS = 3;
63+
protected static final int MAX_DATABASE_CONNECTIONS = 300;
64+
protected static final int DEFAULT_MAX_RETRY_ATTEMPTS = 1;
65+
66+
protected static final Consumer<Builder> DEFAULT_DATABASE_CONFIGURATION = builder -> {
67+
builder.setPgBinaryResolver(DefaultPostgresBinaryResolver.INSTANCE);
68+
builder.setPGStartupWait(Duration.ofSeconds(30L));
69+
};
70+
71+
protected static final Consumer<Builder> FORCED_DATABASE_CONFIGURATION =
72+
builder -> builder.setServerConfig("max_connections", String.valueOf(MAX_DATABASE_CONNECTIONS));
5673

5774
protected static final LoadingCache<Integer, Semaphore> CONNECTION_SEMAPHORES = CacheBuilder.newBuilder()
5875
.build(new CacheLoader<Integer, Semaphore>() {
5976
public Semaphore load(Integer key) {
60-
return new Semaphore(100); // the maximum number of simultaneous connections to the database
77+
return new Semaphore(MAX_DATABASE_CONNECTIONS);
6178
}
6279
});
6380

6481
protected static final ThreadLocal<DataSource> preparerDataSourceHolder = new ThreadLocal<>();
6582

6683
protected volatile CompletableFuture<DataSource> dataSourceFuture = CompletableFuture.completedFuture(null);
6784

85+
@Autowired(required = false)
86+
protected List<Consumer<Builder>> databaseCustomizers = new ArrayList<>();
87+
6888
protected int maxAttempts = DEFAULT_MAX_RETRY_ATTEMPTS;
6989

7090
protected TaskExecutor bootstrapExecutor;
@@ -104,13 +124,19 @@ public void releaseTarget(Object target) throws Exception {
104124
public synchronized ListenableFuture<Void> reload(Flyway flyway) {
105125
Executor executor = bootstrapExecutor != null ? bootstrapExecutor : Runnable::run;
106126

127+
List<Consumer<Builder>> customizers = ImmutableList.<Consumer<Builder>>builder()
128+
.add(DEFAULT_DATABASE_CONFIGURATION)
129+
.addAll(databaseCustomizers)
130+
.add(FORCED_DATABASE_CONFIGURATION)
131+
.build();
132+
107133
CompletableFuture<DataSource> reloadFuture = dataSourceFuture.thenApplyAsync(x -> {
108134
for (int current = 1; current <= maxAttempts; current++) {
109135
try {
110136
FlywayDatabasePreparer preparer = new FlywayDatabasePreparer(flyway);
111-
PreparedDbProvider provider = PreparedDbProvider.forPreparer(preparer);
137+
PreparedDbProvider provider = PreparedDbProvider.forPreparer(preparer, customizers);
112138

113-
PGSimpleDataSource dataSource = ((PGSimpleDataSource) provider.createDataSource());
139+
PGSimpleDataSource dataSource = provider.createDataSource().unwrap(PGSimpleDataSource.class);
114140
Semaphore semaphore = CONNECTION_SEMAPHORES.get(dataSource.getPortNumber());
115141
return new BlockingDataSourceWrapper(dataSource, semaphore);
116142
} catch (Exception e) {
@@ -133,8 +159,11 @@ public synchronized ListenableFuture<Void> reload(Flyway flyway) {
133159
* Includes the initial attempt before the retries begin so, generally, will be {@code >= 1}.
134160
* For example setting this property to 3 means 3 attempts total (initial + 2 retries).
135161
*
162+
* @deprecated This method is scheduled to be removed in version 2.0.0,
163+
* use {@link Builder Consumer&lt;EmbeddedPostgres.Builder&gt;} customizer and increase startup waiting time instead.
136164
* @param maxAttempts the maximum number of attempts including the initial attempt.
137165
*/
166+
@Deprecated
138167
public void setMaxAttempts(int maxAttempts) {
139168
this.maxAttempts = maxAttempts;
140169
}

embedded-database-spring-test/src/main/java/io/zonky/test/db/postgres/EmptyEmbeddedPostgresDataSourceFactoryBean.java

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,54 @@
1616

1717
package io.zonky.test.db.postgres;
1818

19+
import com.google.common.cache.CacheBuilder;
20+
import com.google.common.cache.CacheLoader;
21+
import com.google.common.cache.LoadingCache;
22+
import com.google.common.collect.ImmutableList;
1923
import com.opentable.db.postgres.embedded.DatabasePreparer;
24+
import com.opentable.db.postgres.embedded.EmbeddedPostgres.Builder;
2025
import com.opentable.db.postgres.embedded.PreparedDbProvider;
26+
import io.zonky.test.db.flyway.BlockingDataSourceWrapper;
27+
import io.zonky.test.db.postgres.embedded.DefaultPostgresBinaryResolver;
28+
import org.postgresql.ds.PGSimpleDataSource;
2129
import org.springframework.beans.factory.FactoryBean;
2230
import org.springframework.beans.factory.InitializingBean;
31+
import org.springframework.beans.factory.annotation.Autowired;
2332

2433
import javax.sql.DataSource;
2534
import java.sql.SQLException;
35+
import java.time.Duration;
36+
import java.util.ArrayList;
37+
import java.util.List;
38+
import java.util.concurrent.Semaphore;
39+
import java.util.function.Consumer;
2640

2741
/**
2842
* Implementation of the {@link org.springframework.beans.factory.FactoryBean} interface
2943
* that provides empty instances of the embedded postgres database.
3044
*/
3145
public class EmptyEmbeddedPostgresDataSourceFactoryBean implements FactoryBean<DataSource>, InitializingBean {
3246

47+
protected static final int MAX_DATABASE_CONNECTIONS = 300;
48+
49+
protected static final Consumer<Builder> DEFAULT_DATABASE_CONFIGURATION = builder -> {
50+
builder.setPgBinaryResolver(DefaultPostgresBinaryResolver.INSTANCE);
51+
builder.setPGStartupWait(Duration.ofSeconds(30L));
52+
};
53+
54+
protected static final Consumer<Builder> FORCED_DATABASE_CONFIGURATION =
55+
builder -> builder.setServerConfig("max_connections", String.valueOf(MAX_DATABASE_CONNECTIONS));
56+
57+
protected static final LoadingCache<Integer, Semaphore> CONNECTION_SEMAPHORES = CacheBuilder.newBuilder()
58+
.build(new CacheLoader<Integer, Semaphore>() {
59+
public Semaphore load(Integer key) {
60+
return new Semaphore(MAX_DATABASE_CONNECTIONS);
61+
}
62+
});
63+
64+
@Autowired(required = false)
65+
protected List<Consumer<Builder>> databaseCustomizers = new ArrayList<>();
66+
3367
private DataSource dataSource;
3468

3569
@Override
@@ -49,8 +83,16 @@ public DataSource getObject() throws Exception {
4983

5084
@Override
5185
public void afterPropertiesSet() throws Exception {
52-
PreparedDbProvider provider = PreparedDbProvider.forPreparer(EmptyDatabasePreparer.INSTANCE);
53-
dataSource = provider.createDataSource();
86+
List<Consumer<Builder>> customizers = ImmutableList.<Consumer<Builder>>builder()
87+
.add(DEFAULT_DATABASE_CONFIGURATION)
88+
.addAll(databaseCustomizers)
89+
.add(FORCED_DATABASE_CONFIGURATION)
90+
.build();
91+
92+
PreparedDbProvider provider = PreparedDbProvider.forPreparer(EmptyDatabasePreparer.INSTANCE, customizers);
93+
PGSimpleDataSource dataSource = provider.createDataSource().unwrap(PGSimpleDataSource.class);
94+
Semaphore semaphore = CONNECTION_SEMAPHORES.get(dataSource.getPortNumber());
95+
this.dataSource = new BlockingDataSourceWrapper(dataSource, semaphore);
5496
}
5597

5698
private static class EmptyDatabasePreparer implements DatabasePreparer {
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
import static java.lang.String.format;
1818
import static org.apache.commons.lang3.StringUtils.lowerCase;
1919

20-
public class BundledPostgresBinaryResolver implements PgBinaryResolver {
20+
public class DefaultPostgresBinaryResolver implements PgBinaryResolver {
2121

22-
private static final Logger logger = LoggerFactory.getLogger(BundledPostgresBinaryResolver.class);
22+
private static final Logger logger = LoggerFactory.getLogger(DefaultPostgresBinaryResolver.class);
23+
24+
public static final DefaultPostgresBinaryResolver INSTANCE = new DefaultPostgresBinaryResolver();
2325

2426
@Override
2527
public InputStream getPgBinary(String system, String machineHardware) throws IOException {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package io.zonky.test.db;
2+
3+
import com.opentable.db.postgres.embedded.EmbeddedPostgres;
4+
import org.flywaydb.core.Flyway;
5+
import org.junit.Test;
6+
import org.junit.runner.RunWith;
7+
import org.postgresql.ds.PGSimpleDataSource;
8+
import org.springframework.beans.factory.annotation.Autowired;
9+
import org.springframework.context.annotation.Bean;
10+
import org.springframework.context.annotation.Configuration;
11+
import org.springframework.test.context.ContextConfiguration;
12+
import org.springframework.test.context.junit4.SpringRunner;
13+
14+
import javax.sql.DataSource;
15+
import java.util.function.Consumer;
16+
17+
import static org.assertj.core.api.Assertions.assertThat;
18+
19+
@RunWith(SpringRunner.class)
20+
@AutoConfigureEmbeddedDatabase(beanName = "dataSource")
21+
@ContextConfiguration
22+
public class DatabaseCustomizerIntegrationTest {
23+
24+
@Configuration
25+
static class Config {
26+
27+
@Bean(initMethod = "migrate")
28+
public Flyway flyway(DataSource dataSource) {
29+
Flyway flyway = new Flyway();
30+
flyway.setDataSource(dataSource);
31+
flyway.setSchemas("test", "unique");
32+
return flyway;
33+
}
34+
35+
@Bean
36+
public Consumer<EmbeddedPostgres.Builder> embeddedPostgresCustomizer() {
37+
return builder -> builder.setPort(33333);
38+
}
39+
}
40+
41+
@Autowired
42+
private DataSource dataSource;
43+
44+
@Test
45+
public void primaryDataSourceShouldBeReplaced() throws Exception {
46+
assertThat(dataSource.unwrap(PGSimpleDataSource.class).getPortNumber()).isEqualTo(33333);
47+
}
48+
}

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

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

1717
package io.zonky.test.db;
1818

19+
import io.zonky.test.db.flyway.BlockingDataSourceWrapper;
1920
import org.assertj.core.api.Condition;
2021
import org.junit.Test;
2122
import org.junit.runner.RunWith;
2223
import org.mockito.internal.util.MockUtil;
23-
import org.postgresql.ds.PGSimpleDataSource;
2424
import org.springframework.beans.factory.annotation.Autowired;
2525
import org.springframework.context.annotation.Bean;
2626
import org.springframework.context.annotation.Configuration;
@@ -71,7 +71,7 @@ public void dataSource1ShouldBeMock() throws Exception {
7171

7272
@Test
7373
public void dataSource2ShouldBePostgresDataSource() throws Exception {
74-
assertThat(dataSource2).isExactlyInstanceOf(PGSimpleDataSource.class);
74+
assertThat(dataSource2).isExactlyInstanceOf(BlockingDataSourceWrapper.class);
7575
}
7676

7777
@Test

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,6 @@ public DataSource dataSource() {
5151

5252
@Test
5353
public void primaryDataSourceShouldBeReplaced() throws Exception {
54-
assertThat(dataSource).isExactlyInstanceOf(PGSimpleDataSource.class);
54+
assertThat(dataSource.unwrap(DataSource.class)).isExactlyInstanceOf(PGSimpleDataSource.class);
5555
}
5656
}

0 commit comments

Comments
 (0)