Skip to content

Commit 32f5339

Browse files
committed
make some parts of code more accessible and customizable
1 parent 3b5ba4d commit 32f5339

File tree

4 files changed

+203
-130
lines changed

4 files changed

+203
-130
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright 2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.zonky.test.db.flyway;
18+
19+
import com.google.common.cache.CacheBuilder;
20+
import com.google.common.cache.CacheLoader;
21+
import com.google.common.cache.LoadingCache;
22+
import com.opentable.db.postgres.embedded.DatabasePreparer;
23+
import com.opentable.db.postgres.embedded.PreparedDbProvider;
24+
import org.apache.commons.lang3.ArrayUtils;
25+
import org.flywaydb.core.Flyway;
26+
import org.postgresql.ds.PGSimpleDataSource;
27+
28+
import javax.sql.DataSource;
29+
import java.sql.SQLException;
30+
import java.util.Objects;
31+
import java.util.concurrent.Semaphore;
32+
33+
import static com.google.common.base.Preconditions.checkState;
34+
35+
/**
36+
* Default implementation of {@link FlywayDataSourceContext} that is used for deferred initialization of the embedded database.
37+
* Note that this target source is dynamic and supports hot reloading while the application is running.
38+
* <p/>
39+
* For the reloading of the underlying data source is used cacheable {@link com.opentable.db.postgres.embedded.DatabasePreparer},
40+
* which can utilize a special template database to effective copy data into multiple independent databases.
41+
*
42+
* @see io.zonky.test.db.postgres.FlywayEmbeddedPostgresDataSourceFactoryBean
43+
* @see OptimizedFlywayTestExecutionListener
44+
* @see <a href="https://www.postgresql.org/docs/9.6/static/manage-ag-templatedbs.html">Template Databases</a>
45+
*/
46+
public class DefaultFlywayDataSourceContext implements FlywayDataSourceContext {
47+
48+
protected static final LoadingCache<Integer, Semaphore> CONNECTION_SEMAPHORES = CacheBuilder.newBuilder()
49+
.build(new CacheLoader<Integer, Semaphore>() {
50+
public Semaphore load(Integer key) {
51+
return new Semaphore(100); // the maximum number of simultaneous connections to the database
52+
}
53+
});
54+
55+
protected static final ThreadLocal<DataSource> preparerDataSourceHolder = new ThreadLocal<>();
56+
57+
protected volatile DataSource dataSource;
58+
59+
@Override
60+
public Class<?> getTargetClass() {
61+
return DataSource.class;
62+
}
63+
64+
@Override
65+
public boolean isStatic() {
66+
return false;
67+
}
68+
69+
@Override
70+
public Object getTarget() throws Exception {
71+
DataSource dataSource = preparerDataSourceHolder.get();
72+
73+
if (dataSource == null) {
74+
dataSource = this.dataSource;
75+
}
76+
77+
checkState(dataSource != null, "dataSource is not initialized yet");
78+
return dataSource;
79+
}
80+
81+
@Override
82+
public void releaseTarget(Object target) throws Exception {
83+
// nothing to do
84+
}
85+
86+
@Override
87+
public void reload(Flyway flyway) throws Exception {
88+
FlywayDatabasePreparer preparer = new FlywayDatabasePreparer(flyway);
89+
PreparedDbProvider provider = PreparedDbProvider.forPreparer(preparer);
90+
91+
PGSimpleDataSource dataSource = ((PGSimpleDataSource) provider.createDataSource());
92+
Semaphore semaphore = CONNECTION_SEMAPHORES.get(dataSource.getPortNumber());
93+
this.dataSource = new BlockingDataSourceWrapper(dataSource, semaphore);
94+
}
95+
96+
protected FlywayConfigSnapshot createConfigSnapshot(Flyway flyway) {
97+
FlywayConfigSnapshot configSnapshot = new FlywayConfigSnapshot(flyway);
98+
checkState(ArrayUtils.isNotEmpty(configSnapshot.getSchemas()),
99+
"org.flywaydb.core.Flyway#schemaNames must be specified");
100+
return configSnapshot;
101+
}
102+
103+
protected class FlywayDatabasePreparer implements DatabasePreparer {
104+
105+
private final FlywayConfigSnapshot configSnapshot;
106+
private final Flyway flyway;
107+
108+
public FlywayDatabasePreparer(Flyway flyway) {
109+
this.configSnapshot = createConfigSnapshot(flyway);
110+
this.flyway = flyway;
111+
}
112+
113+
@Override
114+
public void prepare(DataSource ds) throws SQLException {
115+
preparerDataSourceHolder.set(ds);
116+
try {
117+
flyway.migrate();
118+
} finally {
119+
preparerDataSourceHolder.remove();
120+
}
121+
}
122+
123+
@Override
124+
public boolean equals(Object o) {
125+
if (this == o) return true;
126+
if (o == null || getClass() != o.getClass()) return false;
127+
FlywayDatabasePreparer that = (FlywayDatabasePreparer) o;
128+
return Objects.equals(configSnapshot, that.configSnapshot);
129+
}
130+
131+
@Override
132+
public int hashCode() {
133+
return Objects.hash(configSnapshot);
134+
}
135+
}
136+
}

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

Lines changed: 4 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -16,122 +16,15 @@
1616

1717
package io.zonky.test.db.flyway;
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.opentable.db.postgres.embedded.DatabasePreparer;
23-
import com.opentable.db.postgres.embedded.PreparedDbProvider;
24-
import org.apache.commons.lang3.ArrayUtils;
2519
import org.flywaydb.core.Flyway;
26-
import org.postgresql.ds.PGSimpleDataSource;
2720
import org.springframework.aop.TargetSource;
2821

29-
import javax.sql.DataSource;
30-
import java.sql.SQLException;
31-
import java.util.Objects;
32-
import java.util.concurrent.Semaphore;
33-
34-
import static com.google.common.base.Preconditions.checkState;
35-
3622
/**
37-
* Implementation of the {@link TargetSource} that is used by {@link io.zonky.test.db.postgres.FlywayEmbeddedPostgresDataSourceFactoryBean}
38-
* for deferring initialization of the embedded database until the application context is fully loaded and the flyway bean is available.
39-
* Note that this target source is dynamic and supports hot reloading while the application is running.
40-
* <p/>
41-
* For the reloading of the underlying data source is used cacheable {@link com.opentable.db.postgres.embedded.DatabasePreparer},
42-
* which can utilize a special template database to effective copy data into multiple independent databases.
43-
*
44-
* @see io.zonky.test.db.postgres.FlywayEmbeddedPostgresDataSourceFactoryBean
45-
* @see OptimizedFlywayTestExecutionListener
46-
* @see <a href="https://www.postgresql.org/docs/9.6/static/manage-ag-templatedbs.html">Template Databases</a>
23+
* Interface extending {@link TargetSource} that is used by {@link io.zonky.test.db.postgres.FlywayEmbeddedPostgresDataSourceFactoryBean}
24+
* for deferred initialization of the embedded database until the application context is fully loaded and the flyway bean is available.
4725
*/
48-
public class FlywayDataSourceContext implements TargetSource {
49-
50-
private static final LoadingCache<Integer, Semaphore> CONNECTION_SEMAPHORES = CacheBuilder.newBuilder()
51-
.build(new CacheLoader<Integer, Semaphore>() {
52-
public Semaphore load(Integer key) {
53-
return new Semaphore(100); // the maximum number of simultaneous connections to the database
54-
}
55-
});
56-
57-
private static final ThreadLocal<DataSource> preparerDataSourceHolder = new ThreadLocal<>();
58-
59-
private volatile DataSource dataSource;
60-
61-
@Override
62-
public Class<?> getTargetClass() {
63-
return DataSource.class;
64-
}
65-
66-
@Override
67-
public boolean isStatic() {
68-
return false;
69-
}
70-
71-
@Override
72-
public Object getTarget() throws Exception {
73-
DataSource dataSource = preparerDataSourceHolder.get();
74-
75-
if (dataSource == null) {
76-
dataSource = this.dataSource;
77-
}
78-
79-
checkState(dataSource != null, "dataSource is not initialized yet");
80-
return dataSource;
81-
}
82-
83-
@Override
84-
public void releaseTarget(Object target) throws Exception {
85-
// nothing to do
86-
}
87-
88-
public void reload(Flyway flyway) throws Exception {
89-
FlywayDatabasePreparer preparer = new FlywayDatabasePreparer(flyway);
90-
PreparedDbProvider provider = PreparedDbProvider.forPreparer(preparer);
91-
92-
PGSimpleDataSource dataSource = ((PGSimpleDataSource) provider.createDataSource());
93-
Semaphore semaphore = CONNECTION_SEMAPHORES.get(dataSource.getPortNumber());
94-
this.dataSource = new BlockingDataSourceWrapper(dataSource, semaphore);
95-
}
96-
97-
protected FlywayConfigSnapshot createConfigSnapshot(Flyway flyway) {
98-
FlywayConfigSnapshot configSnapshot = new FlywayConfigSnapshot(flyway);
99-
checkState(ArrayUtils.isNotEmpty(configSnapshot.getSchemas()),
100-
"org.flywaydb.core.Flyway#schemaNames must be specified");
101-
return configSnapshot;
102-
}
103-
104-
protected class FlywayDatabasePreparer implements DatabasePreparer {
105-
106-
private final FlywayConfigSnapshot configSnapshot;
107-
private final Flyway flyway;
108-
109-
private FlywayDatabasePreparer(Flyway flyway) {
110-
this.configSnapshot = createConfigSnapshot(flyway);
111-
this.flyway = flyway;
112-
}
113-
114-
@Override
115-
public void prepare(DataSource ds) throws SQLException {
116-
preparerDataSourceHolder.set(ds);
117-
try {
118-
flyway.migrate();
119-
} finally {
120-
preparerDataSourceHolder.remove();
121-
}
122-
}
26+
public interface FlywayDataSourceContext extends TargetSource {
12327

124-
@Override
125-
public boolean equals(Object o) {
126-
if (this == o) return true;
127-
if (o == null || getClass() != o.getClass()) return false;
128-
FlywayDatabasePreparer that = (FlywayDatabasePreparer) o;
129-
return Objects.equals(configSnapshot, that.configSnapshot);
130-
}
28+
void reload(Flyway flyway) throws Exception;
13129

132-
@Override
133-
public int hashCode() {
134-
return Objects.hash(configSnapshot);
135-
}
136-
}
13730
}

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public void beforeTestMethod(TestContext testContext) throws Exception {
112112
}
113113
}
114114

115-
private void optimizedDbReset(TestContext testContext, FlywayTest annotation) throws Exception {
115+
protected void optimizedDbReset(TestContext testContext, FlywayTest annotation) throws Exception {
116116
if (annotation != null && annotation.invokeCleanDB() && annotation.invokeMigrateDB() && !annotation.invokeBaselineDB()) {
117117

118118
ApplicationContext applicationContext = testContext.getApplicationContext();
@@ -133,7 +133,7 @@ private void optimizedDbReset(TestContext testContext, FlywayTest annotation) th
133133
ReflectionTestUtils.invokeMethod(this, "dbResetWithAnnotation", testContext, annotation);
134134
}
135135

136-
private static void prepareDataSourceContext(FlywayDataSourceContext dataSourceContext, Flyway flywayBean, FlywayTest annotation) throws Exception {
136+
protected static void prepareDataSourceContext(FlywayDataSourceContext dataSourceContext, Flyway flywayBean, FlywayTest annotation) throws Exception {
137137
if (isAppendable(flywayBean, annotation)) {
138138
dataSourceContext.reload(flywayBean);
139139
} else {
@@ -154,7 +154,7 @@ private static void prepareDataSourceContext(FlywayDataSourceContext dataSourceC
154154
/**
155155
* Checks if test migrations are appendable to core migrations.
156156
*/
157-
private static boolean isAppendable(Flyway flyway, FlywayTest annotation) {
157+
protected static boolean isAppendable(Flyway flyway, FlywayTest annotation) {
158158
if (annotation.overrideLocations()) {
159159
return false;
160160
}
@@ -172,7 +172,7 @@ private static boolean isAppendable(Flyway flyway, FlywayTest annotation) {
172172
return coreVersion.compareTo(testVersion) < 0;
173173
}
174174

175-
private static MigrationVersion findFirstVersion(Flyway flyway, String... locations) {
175+
protected static MigrationVersion findFirstVersion(Flyway flyway, String... locations) {
176176
CompositeMigrationResolver resolver = createMigrationResolver(flyway, locations);
177177
List<ResolvedMigration> migrations = resolver.resolveMigrations();
178178

@@ -183,7 +183,7 @@ private static MigrationVersion findFirstVersion(Flyway flyway, String... locati
183183
}
184184
}
185185

186-
private static MigrationVersion findLastVersion(Flyway flyway, String... locations) {
186+
protected static MigrationVersion findLastVersion(Flyway flyway, String... locations) {
187187
CompositeMigrationResolver resolver = createMigrationResolver(flyway, locations);
188188
List<ResolvedMigration> migrations = resolver.resolveMigrations();
189189

@@ -194,7 +194,7 @@ private static MigrationVersion findLastVersion(Flyway flyway, String... locatio
194194
}
195195
}
196196

197-
private static CompositeMigrationResolver createMigrationResolver(Flyway flyway, String... locations) {
197+
protected static CompositeMigrationResolver createMigrationResolver(Flyway flyway, String... locations) {
198198
Scanner scanner = new Scanner(flyway.getClassLoader());
199199

200200
for (MigrationResolver resolver : flyway.getResolvers()) {
@@ -205,14 +205,14 @@ private static CompositeMigrationResolver createMigrationResolver(Flyway flyway,
205205
new Locations(locations), createPlaceholderReplacer(flyway), flyway.getResolvers());
206206
}
207207

208-
private static PlaceholderReplacer createPlaceholderReplacer(Flyway flyway) {
208+
protected static PlaceholderReplacer createPlaceholderReplacer(Flyway flyway) {
209209
if (flyway.isPlaceholderReplacement()) {
210210
return new PlaceholderReplacer(flyway.getPlaceholders(), flyway.getPlaceholderPrefix(), flyway.getPlaceholderSuffix());
211211
}
212212
return PlaceholderReplacer.NO_PLACEHOLDERS;
213213
}
214214

215-
private static FlywayDataSourceContext getDataSourceContext(ApplicationContext context, Flyway flywayBean) {
215+
protected static FlywayDataSourceContext getDataSourceContext(ApplicationContext context, Flyway flywayBean) {
216216
Map<String, Flyway> flywayBeans = context.getBeansOfType(Flyway.class);
217217
String flywayBeanName = flywayBeans.entrySet().stream()
218218
.filter(e -> e.getValue() == flywayBean)

0 commit comments

Comments
 (0)