Skip to content

Commit e1967d6

Browse files
committed
#264 fix propagation of java migrations, callbacks, resource provider and class provider parameters to flyway preparers (flyway 9.9+)
1 parent fb00b71 commit e1967d6

File tree

5 files changed

+211
-16
lines changed

5 files changed

+211
-16
lines changed

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

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

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

19+
import com.cedarsoftware.util.DeepEquals;
1920
import com.google.common.collect.ImmutableList;
2021
import com.google.common.collect.ImmutableSet;
2122
import com.google.common.collect.Lists;
@@ -49,6 +50,12 @@ public class FlywayDescriptor {
4950
"validateOnMigrate"
5051
);
5152

53+
// these objects require deep comparison of all nested fields
54+
private static final Set<String> SPECIAL_FIELDS = ImmutableSet.of(
55+
"resourceProvider", "javaMigrationClassProvider",
56+
"javaMigrations", "callbacks"
57+
);
58+
5259
private static final Set<String> EXCLUDED_FIELDS = ImmutableSet.of(
5360
"cleanDisabled", "dbConnectionInfoPrinted", "classScanner", "pluginRegister"
5461
);
@@ -60,6 +67,7 @@ public class FlywayDescriptor {
6067
private static final FieldFilter OTHER_FIELDS =
6168
field -> !Modifier.isStatic(field.getModifiers())
6269
&& !BASIC_FIELDS.contains(field.getName())
70+
&& !SPECIAL_FIELDS.contains(field.getName())
6371
&& !EXCLUDED_FIELDS.contains(field.getName())
6472
&& !EXCLUDED_TYPES.contains(field.getType());
6573

@@ -77,6 +85,10 @@ public class FlywayDescriptor {
7785
private final boolean ignoreMissingMigrations;
7886
private final boolean ignoreFutureMigrations;
7987
private final boolean validateOnMigrate;
88+
private final Object resourceProvider;
89+
private final Object javaMigrationClassProvider;
90+
private final List<Object> javaMigrations;
91+
private final List<Object> callbacks;
8092
private final Map<Field, Object> otherFields;
8193
private final Map<Field, Object> envConfFields;
8294
private final Map<Class<?>, Map<Field, Object>> pluginsFields;
@@ -93,6 +105,11 @@ private FlywayDescriptor(FlywayWrapper wrapper) {
93105
this.ignoreFutureMigrations = wrapper.isIgnoreFutureMigrations();
94106
this.validateOnMigrate = wrapper.isValidateOnMigrate();
95107

108+
this.resourceProvider = wrapper.getResourceProvider();
109+
this.javaMigrationClassProvider = wrapper.getJavaMigrationClassProvider();
110+
this.javaMigrations = wrapper.getJavaMigration();
111+
this.callbacks = wrapper.getCallbacks();
112+
96113
this.otherFields = getFields(wrapper.getConfig(), OTHER_FIELDS);
97114
this.envConfFields = getFields(wrapper.getEnvConfig(), PLUGIN_FIELDS);
98115

@@ -121,6 +138,11 @@ public void applyTo(FlywayWrapper wrapper) {
121138
wrapper.setIgnoreFutureMigrations(ignoreFutureMigrations);
122139
wrapper.setValidateOnMigrate(validateOnMigrate);
123140

141+
wrapper.setResourceProvider(resourceProvider);
142+
wrapper.setJavaMigrationClassProvider(javaMigrationClassProvider);
143+
wrapper.setJavaMigration(javaMigrations);
144+
wrapper.setCallbacks(callbacks);
145+
124146
setFields(wrapper.getConfig(), otherFields);
125147
setFields(wrapper.getEnvConfig(), envConfFields);
126148

@@ -186,6 +208,10 @@ public boolean equals(Object o) {
186208
&& Objects.equals(repeatableSqlMigrationPrefix, that.repeatableSqlMigrationPrefix)
187209
&& Objects.equals(sqlMigrationSeparator, that.sqlMigrationSeparator)
188210
&& Objects.equals(sqlMigrationSuffixes, that.sqlMigrationSuffixes)
211+
&& DeepEquals.deepEquals(resourceProvider, that.resourceProvider)
212+
&& DeepEquals.deepEquals(javaMigrationClassProvider, that.javaMigrationClassProvider)
213+
&& DeepEquals.deepEquals(javaMigrations, that.javaMigrations)
214+
&& DeepEquals.deepEquals(callbacks, that.callbacks)
189215
&& Objects.equals(otherFields, that.otherFields)
190216
&& Objects.equals(envConfFields, that.envConfFields)
191217
&& Objects.equals(pluginsFields, that.pluginsFields);
@@ -197,7 +223,9 @@ public int hashCode() {
197223
sqlMigrationPrefix, repeatableSqlMigrationPrefix,
198224
sqlMigrationSeparator, sqlMigrationSuffixes,
199225
ignoreMissingMigrations, ignoreFutureMigrations,
200-
validateOnMigrate, otherFields, envConfFields, pluginsFields);
226+
validateOnMigrate, resourceProvider,
227+
javaMigrationClassProvider, javaMigrations, callbacks,
228+
otherFields, envConfFields, pluginsFields);
201229
}
202230

203231
private static void setCollection(Field field, Object target, Collection<?> value) {

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

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.springframework.util.ObjectUtils;
2727

2828
import javax.sql.DataSource;
29+
import java.lang.reflect.Array;
2930
import java.util.Arrays;
3031
import java.util.Collection;
3132
import java.util.List;
@@ -385,6 +386,79 @@ public void setCleanDisabled(boolean cleanDisabled) {
385386
setValue(config, "setCleanDisabled", cleanDisabled);
386387
}
387388

389+
public Object getResourceProvider() {
390+
if (flywayVersion.isGreaterThanOrEqualTo("6.5")) {
391+
return getValue(config, "getResourceProvider");
392+
} else {
393+
return null;
394+
}
395+
}
396+
397+
public void setResourceProvider(Object resourceProvider) {
398+
if (flywayVersion.isGreaterThanOrEqualTo("6.5")) {
399+
setValue(config, "setResourceProvider", resourceProvider);
400+
} else if (!Objects.equals(resourceProvider, getResourceProvider())) {
401+
throw new UnsupportedOperationException("This method is not supported in current Flyway version");
402+
}
403+
}
404+
405+
public Object getJavaMigrationClassProvider() {
406+
if (flywayVersion.isGreaterThanOrEqualTo("6.5")) {
407+
return getValue(config, "getJavaMigrationClassProvider");
408+
} else {
409+
return null;
410+
}
411+
}
412+
413+
public void setJavaMigrationClassProvider(Object javaMigrationClassProvider) {
414+
if (flywayVersion.isGreaterThanOrEqualTo("6.5")) {
415+
setValue(config, "setJavaMigrationClassProvider", javaMigrationClassProvider);
416+
} else if (!Objects.equals(javaMigrationClassProvider, getJavaMigrationClassProvider())) {
417+
throw new UnsupportedOperationException("This method is not supported in current Flyway version");
418+
}
419+
}
420+
421+
public List<Object> getJavaMigration() {
422+
if (flywayVersion.isGreaterThanOrEqualTo("6")) {
423+
return ImmutableList.copyOf(getArray(config, "getJavaMigrations"));
424+
} else {
425+
return ImmutableList.of();
426+
}
427+
}
428+
429+
public void setJavaMigration(List<Object> javaMigrations) {
430+
if (flywayVersion.isGreaterThanOrEqualTo("6")) {
431+
try {
432+
Class<?> javaMigrationType = ClassUtils.forName("org.flywaydb.core.api.migration.JavaMigration", null);
433+
Object[] javaMigrationArray = (Object[]) Array.newInstance(javaMigrationType, javaMigrations.size());
434+
setValue(config, "setJavaMigrations", javaMigrations.toArray(javaMigrationArray));
435+
} catch (ClassNotFoundException e) {
436+
throw new IllegalStateException("Class not found: " + e.getMessage());
437+
}
438+
} else if (!Objects.equals(javaMigrations, getJavaMigration())) {
439+
throw new UnsupportedOperationException("This method is not supported in current Flyway version");
440+
}
441+
}
442+
443+
public List<Object> getCallbacks() {
444+
return ImmutableList.copyOf(getArray(config, "getCallbacks"));
445+
}
446+
447+
public void setCallbacks(List<Object> callbacks) {
448+
try {
449+
final Class<?> callbackType;
450+
if (flywayVersion.isGreaterThanOrEqualTo("5.1")) {
451+
callbackType = ClassUtils.forName("org.flywaydb.core.api.callback.Callback", null);
452+
} else {
453+
callbackType = ClassUtils.forName("org.flywaydb.core.api.callback.FlywayCallback", null);
454+
}
455+
Object[] callbackArray = (Object[]) Array.newInstance(callbackType, callbacks.size());
456+
setValue(config, "setCallbacks", callbacks.toArray(callbackArray));
457+
} catch (ClassNotFoundException e) {
458+
throw new IllegalStateException("Class not found: " + e.getMessage());
459+
}
460+
}
461+
388462
public List<Object> getConfigurationExtensions() {
389463
if (flywayVersion.isGreaterThanOrEqualTo("9")) {
390464
try {

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

Lines changed: 108 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33
import com.google.common.collect.ImmutableList;
44
import com.google.common.collect.ImmutableMap;
55
import io.zonky.test.category.FlywayTestSuite;
6+
import org.flywaydb.core.api.callback.BaseCallback;
7+
import org.flywaydb.core.api.callback.Event;
8+
import org.flywaydb.core.api.migration.BaseJavaMigration;
9+
import org.flywaydb.core.api.migration.Context;
610
import org.flywaydb.core.api.resolver.MigrationResolver;
711
import org.junit.Test;
812
import org.junit.experimental.categories.Category;
913
import org.springframework.util.ClassUtils;
1014

1115
import javax.sql.DataSource;
12-
import java.lang.reflect.Array;
16+
import java.util.List;
1317

1418
import static io.zonky.test.db.util.ReflectionUtils.invokeMethod;
1519
import static io.zonky.test.db.util.ReflectionUtils.setField;
@@ -63,7 +67,7 @@ public void testBasicFields() {
6367
@Test
6468
public void testDynamicFields() throws ClassNotFoundException {
6569
Object mockResolvers = createMockResolvers();
66-
Object mockCallbacks = createMockCallbacks();
70+
List<Object> mockCallbacks = createMockCallbacks();
6771

6872
FlywayWrapper wrapper1 = FlywayWrapper.newInstance();
6973
Object config1 = wrapper1.getConfig();
@@ -72,10 +76,10 @@ public void testDynamicFields() throws ClassNotFoundException {
7276
invokeMethod(config1, "setPlaceholders", ImmutableMap.of("key1", "value1", "key2", "value2"));
7377
if (flywayVersion.isLessThan("9.9")) {
7478
invokeMethod(config1, "setResolvers", mockResolvers);
75-
invokeMethod(config1, "setCallbacks", mockCallbacks);
79+
wrapper1.setCallbacks(mockCallbacks);
7680
} else {
7781
invokeMethod(config1, "setMigrationResolvers", ImmutableList.of("resolver1", "resolver2", "resolver3"));
78-
invokeMethod(config1, "setCallbacks", ImmutableList.of("callback1", "callback2", "callback3"));
82+
invokeMethod(config1, "setCallbacks", ImmutableList.of("db/migration/beforeMigrate.sql", "db/migration/afterMigrate.sql"));
7983
}
8084

8185
FlywayWrapper wrapper2 = FlywayWrapper.newInstance();
@@ -85,10 +89,10 @@ public void testDynamicFields() throws ClassNotFoundException {
8589
invokeMethod(config2, "setPlaceholders", ImmutableMap.of("key1", "value1", "key2", "value2"));
8690
if (flywayVersion.isLessThan("9.9")) {
8791
invokeMethod(config2, "setResolvers", mockResolvers);
88-
invokeMethod(config2, "setCallbacks", mockCallbacks);
92+
wrapper2.setCallbacks(mockCallbacks);
8993
} else {
9094
invokeMethod(config2, "setMigrationResolvers", ImmutableList.of("resolver1", "resolver2", "resolver3"));
91-
invokeMethod(config2, "setCallbacks", ImmutableList.of("callback1", "callback2", "callback3"));
95+
invokeMethod(config2, "setCallbacks", ImmutableList.of("db/migration/beforeMigrate.sql", "db/migration/afterMigrate.sql"));
9296
}
9397

9498
FlywayDescriptor descriptor1 = FlywayDescriptor.from(wrapper1);
@@ -103,6 +107,53 @@ public void testDynamicFields() throws ClassNotFoundException {
103107
assertThat(descriptor1).isEqualTo(descriptor3);
104108
}
105109

110+
@Test
111+
public void testSpecialFields() throws ClassNotFoundException {
112+
List<Object> mockMigrations1 = createMockMigrations();
113+
List<Object> mockCallbacks1 = createMockCallbacks();
114+
115+
List<Object> mockMigrations2 = createMockMigrations();
116+
List<Object> mockCallbacks2 = createMockCallbacks();
117+
118+
Object resourceProvider = null;
119+
Object classProvider = null;
120+
121+
if (flywayVersion.isGreaterThanOrEqualTo("6.5")) {
122+
Class<?> resourceProviderType = ClassUtils.forName("org.flywaydb.core.api.ResourceProvider", null);
123+
Class<?> classProviderType = ClassUtils.forName("org.flywaydb.core.api.ClassProvider", null);
124+
resourceProvider = mock(resourceProviderType);
125+
classProvider = mock(classProviderType);
126+
}
127+
128+
FlywayWrapper wrapper1 = FlywayWrapper.newInstance();
129+
wrapper1.setJavaMigration(mockMigrations1);
130+
wrapper1.setCallbacks(mockCallbacks1);
131+
wrapper1.setResourceProvider(resourceProvider);
132+
wrapper1.setJavaMigrationClassProvider(classProvider);
133+
134+
FlywayWrapper wrapper2 = FlywayWrapper.newInstance();
135+
wrapper2.setJavaMigration(mockMigrations2);
136+
wrapper2.setCallbacks(mockCallbacks2);
137+
wrapper2.setResourceProvider(resourceProvider);
138+
wrapper2.setJavaMigrationClassProvider(classProvider);
139+
140+
FlywayDescriptor descriptor1 = FlywayDescriptor.from(wrapper1);
141+
FlywayDescriptor descriptor2 = FlywayDescriptor.from(wrapper2);
142+
143+
assertThat(descriptor1).isEqualTo(descriptor2);
144+
145+
FlywayWrapper wrapper3 = FlywayWrapper.newInstance();
146+
descriptor1.applyTo(wrapper3);
147+
FlywayDescriptor descriptor3 = FlywayDescriptor.from(wrapper3);
148+
149+
assertThat(descriptor1).isEqualTo(descriptor3);
150+
151+
FlywayWrapper wrapper4 = FlywayWrapper.newInstance();
152+
FlywayDescriptor descriptor4 = FlywayDescriptor.from(wrapper4);
153+
154+
assertThat(descriptor1).isNotEqualTo(descriptor4);
155+
}
156+
106157
@Test
107158
public void testEnvsFields() {
108159
FlywayWrapper wrapper1 = FlywayWrapper.newInstance();
@@ -201,18 +252,60 @@ private static Object createMockResolvers() {
201252
return resolvers;
202253
}
203254

204-
private static Object createMockCallbacks() throws ClassNotFoundException {
205-
final Class<?> callbackType;
206-
if (flywayVersion.isGreaterThanOrEqualTo("5.1")) {
207-
callbackType = ClassUtils.forName("org.flywaydb.core.api.callback.Callback", null);
255+
private static List<Object> callbacks;
256+
257+
private static List<Object> createMockCallbacks() throws ClassNotFoundException {
258+
if (flywayVersion.isGreaterThanOrEqualTo("6")) { // Flyway 6 is required for BaseCallback
259+
return ImmutableList.of(
260+
new TestCallback("1"),
261+
new TestCallback("2"),
262+
new TestCallback("3"));
208263
} else {
209-
callbackType = ClassUtils.forName("org.flywaydb.core.api.callback.FlywayCallback", null);
264+
if (callbacks == null) {
265+
Class<?> callbackType;
266+
if (flywayVersion.isGreaterThanOrEqualTo("5.1")) {
267+
callbackType = ClassUtils.forName("org.flywaydb.core.api.callback.Callback", null);
268+
} else {
269+
callbackType = ClassUtils.forName("org.flywaydb.core.api.callback.FlywayCallback", null);
270+
}
271+
callbacks = ImmutableList.of(mock(callbackType), mock(callbackType), mock(callbackType));
272+
}
273+
return callbacks;
210274
}
275+
}
276+
277+
private static class TestCallback extends BaseCallback {
278+
279+
private final String testParameter;
211280

212-
Object[] callbacks = (Object[]) Array.newInstance(callbackType, 3);
213-
for (int i = 0; i < callbacks.length; i++) {
214-
callbacks[i] = mock(callbackType);
281+
private TestCallback(String testParameter) {
282+
this.testParameter = testParameter;
215283
}
216-
return callbacks;
284+
285+
@Override
286+
public void handle(Event event, org.flywaydb.core.api.callback.Context context) {}
287+
}
288+
289+
private static List<Object> createMockMigrations() {
290+
if (flywayVersion.isGreaterThanOrEqualTo("6")) {
291+
return ImmutableList.of(
292+
new V1__TestJavaMigration("1"),
293+
new V1__TestJavaMigration("2"),
294+
new V1__TestJavaMigration("3"));
295+
} else {
296+
return ImmutableList.of();
297+
}
298+
}
299+
300+
private static class V1__TestJavaMigration extends BaseJavaMigration {
301+
302+
private final String testParameter;
303+
304+
private V1__TestJavaMigration(String testParameter) {
305+
this.testParameter = testParameter;
306+
}
307+
308+
@Override
309+
public void migrate(Context context) throws Exception {}
217310
}
218311
}

embedded-database-spring-test/src/test/resources/db/migration/afterMigrate.sql

Whitespace-only changes.

embedded-database-spring-test/src/test/resources/db/migration/beforeMigrate.sql

Whitespace-only changes.

0 commit comments

Comments
 (0)