Skip to content

Commit d0572bf

Browse files
authored
Merge pull request #115 from zonkyio/flyway-6.1.0-plus
#114 Implement support for Flyway 6.1.0 and above
2 parents 050d7c0 + 8ccbea3 commit d0572bf

File tree

3 files changed

+148
-52
lines changed

3 files changed

+148
-52
lines changed

build.gradle

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,14 @@ ext {
2727
[core: '5.1.4', test: '5.1.0'],
2828
[core: '5.2.4', test: '5.2.4'],
2929
[core: '6.0.2', test: '6.0.0'],
30-
[core: '6.0.7', test: '6.0.0'],
31-
30+
[core: '6.0.8', test: '6.0.0'],
31+
[core: '6.1.4', test: '6.1.0'],
32+
[core: '6.2.4', test: '6.1.0'],
33+
[core: '6.3.2', test: '6.1.0'],
34+
[core: '6.3.3', test: '6.3.3'],
35+
[core: '6.4.4', test: '6.4.0'],
36+
[core: '6.5.3', test: '6.4.0'],
37+
3238
[core: '5.0.7', test: '5.0.0'] // default version
3339
]
3440
embeddedPostgresVersions = ['9.4.25', '9.5.20', '9.6.16', '10.11.0', '11.6.0', '12.1.0']

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

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@ public class FlywayConfigSnapshot {
3131
private final Object[] callbacks; // the callbacks are modified during the migration
3232

3333
// included in equals and hashCode methods
34-
// but it will work only for empty arrays (that is common use-case)
34+
// but it will work only for empty arrays or null values (that is common use-case)
3535
// because of missing equals and hashCode methods
3636
// on classes implementing these interfaces
3737
private final List<MigrationResolver> resolvers;
3838
private final List<Object> errorHandlers;
39+
private final Object resourceProvider;
40+
private final Object javaMigrationClassProvider;
3941

4042
// included in equals and hashCode methods
4143
private final MigrationVersion baselineVersion;
@@ -48,6 +50,7 @@ public class FlywayConfigSnapshot {
4850
private final Map<String, String> placeholders;
4951
private final String table;
5052
private final String tablespace;
53+
private final String defaultSchemaName;
5154
private final String baselineDescription;
5255
private final String undoSqlMigrationPrefix;
5356
private final String repeatableSqlMigrationPrefix;
@@ -67,10 +70,12 @@ public class FlywayConfigSnapshot {
6770
private final boolean ignoreIgnoredMigrations;
6871
private final boolean ignorePendingMigrations;
6972
private final boolean ignoreFutureMigrations;
73+
private final boolean validateMigrationNaming;
7074
private final boolean validateOnMigrate;
7175
private final boolean cleanOnValidationError;
7276
private final boolean cleanDisabled;
7377
private final boolean allowMixedMigrations;
78+
private final boolean createSchemas;
7479
private final boolean mixed;
7580
private final boolean group;
7681
private final String installedBy;
@@ -79,6 +84,7 @@ public class FlywayConfigSnapshot {
7984
private final boolean batch;
8085
private final boolean oracleSqlPlus;
8186
private final boolean oracleSqlplusWarn;
87+
private final boolean outputQueryResults;
8288
private final int connectRetries;
8389

8490
public FlywayConfigSnapshot(Flyway flyway) {
@@ -226,8 +232,32 @@ public FlywayConfigSnapshot(Flyway flyway) {
226232

227233
if (flywayVersion >= 60 && isFlywayPro) {
228234
this.oracleSqlplusWarn = getValue(config, "isOracleSqlplusWarn");
235+
this.outputQueryResults = getValue(config, "outputQueryResults");
229236
} else {
230237
this.oracleSqlplusWarn = false;
238+
this.outputQueryResults = true;
239+
}
240+
241+
if (flywayVersion >= 61) {
242+
this.defaultSchemaName = getValue(config, "getDefaultSchema");
243+
} else {
244+
this.defaultSchemaName = null;
245+
}
246+
247+
if (flywayVersion >= 62) {
248+
this.validateMigrationNaming = getValue(config, "isValidateMigrationNaming");
249+
} else {
250+
this.validateMigrationNaming = false;
251+
}
252+
253+
if (flywayVersion >= 65) {
254+
this.resourceProvider = getValue(config, "getResourceProvider");
255+
this.javaMigrationClassProvider = getValue(config, "getJavaMigrationClassProvider");
256+
this.createSchemas = getValue(config, "getCreateSchemas");
257+
} else {
258+
this.resourceProvider = null;
259+
this.javaMigrationClassProvider = null;
260+
this.createSchemas = true;
231261
}
232262
}
233263

@@ -263,6 +293,14 @@ public List<MigrationResolver> getResolvers() {
263293
return resolvers;
264294
}
265295

296+
public Object getResourceProvider() {
297+
return resourceProvider;
298+
}
299+
300+
public Object getJavaMigrationClassProvider() {
301+
return javaMigrationClassProvider;
302+
}
303+
266304
public boolean isSkipDefaultResolvers() {
267305
return skipDefaultResolvers;
268306
}
@@ -327,6 +365,10 @@ public String getTablespace() {
327365
return tablespace;
328366
}
329367

368+
public String getDefaultSchemaName() {
369+
return defaultSchemaName;
370+
}
371+
330372
public List<String> getSchemas() {
331373
return schemas;
332374
}
@@ -371,6 +413,10 @@ public boolean isIgnoreFutureMigrations() {
371413
return ignoreFutureMigrations;
372414
}
373415

416+
public boolean isValidateMigrationNaming() {
417+
return validateMigrationNaming;
418+
}
419+
374420
public boolean isValidateOnMigrate() {
375421
return validateOnMigrate;
376422
}
@@ -387,6 +433,10 @@ public boolean isAllowMixedMigrations() {
387433
return allowMixedMigrations;
388434
}
389435

436+
public boolean isCreateSchemas() {
437+
return createSchemas;
438+
}
439+
390440
public boolean isMixed() {
391441
return mixed;
392442
}
@@ -427,6 +477,10 @@ public boolean isOracleSqlplusWarn() {
427477
return oracleSqlplusWarn;
428478
}
429479

480+
public boolean isOutputQueryResults() {
481+
return outputQueryResults;
482+
}
483+
430484
public int getConnectRetries() {
431485
return connectRetries;
432486
}
@@ -445,20 +499,25 @@ public boolean equals(Object o) {
445499
ignoreIgnoredMigrations == that.ignoreIgnoredMigrations &&
446500
ignorePendingMigrations == that.ignorePendingMigrations &&
447501
ignoreFutureMigrations == that.ignoreFutureMigrations &&
502+
validateMigrationNaming == that.validateMigrationNaming &&
448503
validateOnMigrate == that.validateOnMigrate &&
449504
cleanOnValidationError == that.cleanOnValidationError &&
450505
cleanDisabled == that.cleanDisabled &&
451506
allowMixedMigrations == that.allowMixedMigrations &&
507+
createSchemas == that.createSchemas &&
452508
mixed == that.mixed &&
453509
group == that.group &&
454510
dryRun == that.dryRun &&
455511
stream == that.stream &&
456512
batch == that.batch &&
457513
oracleSqlPlus == that.oracleSqlPlus &&
458514
oracleSqlplusWarn == that.oracleSqlplusWarn &&
515+
outputQueryResults == that.outputQueryResults &&
459516
connectRetries == that.connectRetries &&
460517
Objects.equals(resolvers, that.resolvers) &&
461518
Objects.equals(errorHandlers, that.errorHandlers) &&
519+
Objects.equals(resourceProvider, that.resourceProvider) &&
520+
Objects.equals(javaMigrationClassProvider, that.javaMigrationClassProvider) &&
462521
Objects.equals(baselineVersion, that.baselineVersion) &&
463522
Objects.equals(target, that.target) &&
464523
Objects.equals(locations, that.locations) &&
@@ -469,6 +528,7 @@ public boolean equals(Object o) {
469528
Objects.equals(placeholders, that.placeholders) &&
470529
Objects.equals(table, that.table) &&
471530
Objects.equals(tablespace, that.tablespace) &&
531+
Objects.equals(defaultSchemaName, that.defaultSchemaName) &&
472532
Objects.equals(baselineDescription, that.baselineDescription) &&
473533
Objects.equals(undoSqlMigrationPrefix, that.undoSqlMigrationPrefix) &&
474534
Objects.equals(repeatableSqlMigrationPrefix, that.repeatableSqlMigrationPrefix) &&
@@ -485,16 +545,17 @@ public boolean equals(Object o) {
485545
@Override
486546
public int hashCode() {
487547
return Objects.hash(
488-
resolvers, errorHandlers,
548+
resolvers, errorHandlers, resourceProvider, javaMigrationClassProvider,
489549
baselineVersion, target, locations, schemas, sqlMigrationSuffixes,
490-
javaMigrations, errorOverrides, placeholders, table, tablespace,
550+
javaMigrations, errorOverrides, placeholders, table, tablespace, defaultSchemaName,
491551
baselineDescription, undoSqlMigrationPrefix, repeatableSqlMigrationPrefix,
492552
sqlMigrationSeparator, sqlMigrationPrefix, placeholderPrefix,
493553
placeholderSuffix, encoding, initSql, licenseKey,
494554
skipDefaultResolvers, skipDefaultCallbacks, placeholderReplacement, baselineOnMigrate,
495555
outOfOrder, ignoreMissingMigrations, ignoreIgnoredMigrations, ignorePendingMigrations,
496-
ignoreFutureMigrations, validateOnMigrate, cleanOnValidationError, cleanDisabled,
497-
allowMixedMigrations, mixed, group, installedBy, dryRun, stream, batch,
498-
oracleSqlPlus, oracleSqlplusWarn, connectRetries);
556+
ignoreFutureMigrations, validateMigrationNaming, validateOnMigrate,
557+
cleanOnValidationError, cleanDisabled, allowMixedMigrations, createSchemas,
558+
mixed, group, installedBy, dryRun, stream, batch,
559+
oracleSqlPlus, oracleSqlplusWarn, outputQueryResults, connectRetries);
499560
}
500561
}

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

Lines changed: 73 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import org.flywaydb.core.api.MigrationVersion;
2626
import org.flywaydb.core.api.resolver.MigrationResolver;
2727
import org.flywaydb.core.api.resolver.ResolvedMigration;
28-
import org.flywaydb.core.internal.database.DatabaseFactory;
2928
import org.flywaydb.core.internal.util.scanner.Scanner;
3029
import org.flywaydb.test.annotation.FlywayTest;
3130
import org.flywaydb.test.junit.FlywayTestExecutionListener;
@@ -51,7 +50,6 @@
5150
import static io.zonky.test.db.util.ReflectionUtils.getField;
5251
import static io.zonky.test.db.util.ReflectionUtils.invokeConstructor;
5352
import static io.zonky.test.db.util.ReflectionUtils.invokeMethod;
54-
import static io.zonky.test.db.util.ReflectionUtils.invokeStaticMethod;
5553

5654
/**
5755
* Optimized implementation of the {@link org.flywaydb.test.junit.FlywayTestExecutionListener}
@@ -254,41 +252,24 @@ protected static MigrationResolver createMigrationResolver(Flyway flyway, String
254252
try {
255253
setFlywayLocations(flyway, locations);
256254

257-
if (flywayVersion >= 60) {
258-
Object configuration = getField(flyway, "configuration");
259-
Object jdbcConnectionFactory = invokeConstructor("org.flywaydb.core.internal.jdbc.JdbcConnectionFactory", invokeMethod(configuration, "getDataSource"), 0);
260-
closeConnection(invokeMethod(jdbcConnectionFactory, "openConnection")); // closes an internal unused connection
261-
Object sqlScriptFactory = invokeStaticMethod(DatabaseFactory.class, "createSqlScriptFactory", jdbcConnectionFactory, configuration);
262-
Object sqlScriptExecutorFactory = invokeStaticMethod(DatabaseFactory.class, "createSqlScriptExecutorFactory", jdbcConnectionFactory);
263-
Object scanner;
264-
265-
try {
266-
scanner = invokeConstructor("org.flywaydb.core.internal.scanner.Scanner",
267-
ClassUtils.forName("org.flywaydb.core.api.migration.JavaMigration", classLoader),
268-
Arrays.asList((Object[]) invokeMethod(configuration, "getLocations")),
269-
invokeMethod(configuration, "getClassLoader"),
270-
invokeMethod(configuration, "getEncoding"));
271-
} catch (RuntimeException ex) {
272-
scanner = invokeConstructor("org.flywaydb.core.internal.scanner.Scanner",
273-
Arrays.asList((Object[]) invokeMethod(configuration, "getLocations")),
274-
invokeMethod(configuration, "getClassLoader"),
275-
invokeMethod(configuration, "getEncoding"));
276-
}
277-
255+
if (flywayVersion >= 63) {
256+
Object scanner = createScanner(flyway);
257+
Object sqlScriptFactory = createMock("org.flywaydb.core.internal.sqlscript.SqlScriptFactory");
258+
Object sqlScriptExecutorFactory = createMock("org.flywaydb.core.internal.sqlscript.SqlScriptExecutorFactory");
259+
Object parsingContext = invokeConstructor("org.flywaydb.core.internal.parser.ParsingContext");
260+
return invokeMethod(flyway, "createMigrationResolver", scanner, scanner, sqlScriptExecutorFactory, sqlScriptFactory, parsingContext);
261+
} else if (flywayVersion >= 60) {
262+
Object scanner = createScanner(flyway);
263+
Object sqlScriptFactory = createMock("org.flywaydb.core.internal.sqlscript.SqlScriptFactory");
264+
Object sqlScriptExecutorFactory = createMock("org.flywaydb.core.internal.sqlscript.SqlScriptExecutorFactory");
278265
return invokeMethod(flyway, "createMigrationResolver", scanner, scanner, sqlScriptExecutorFactory, sqlScriptFactory);
279266
} else if (flywayVersion >= 52) {
280-
Object configuration = getField(flyway, "configuration");
281-
Object database = invokeStaticMethod(DatabaseFactory.class, "createDatabase", flyway, false);
282-
closeConnection(invokeMethod(database, "getMainConnection")); // closes an internal unused connection
283-
Object factory = invokeMethod(database, "createSqlStatementBuilderFactory");
284-
Object scanner = invokeConstructor("org.flywaydb.core.internal.scanner.Scanner",
285-
Arrays.asList((Object[]) invokeMethod(configuration, "getLocations")),
286-
invokeMethod(configuration, "getClassLoader"),
287-
invokeMethod(configuration, "getEncoding"));
288-
return invokeMethod(flyway, "createMigrationResolver", database, scanner, scanner, factory);
267+
Object scanner = createScanner(flyway);
268+
Object placeholderReplacer = createMock("org.flywaydb.core.internal.placeholder.PlaceholderReplacer");
269+
Object factory = invokeConstructor("org.flywaydb.core.internal.database.postgresql.PostgreSQLSqlStatementBuilderFactory", placeholderReplacer);
270+
return invokeMethod(flyway, "createMigrationResolver", null, scanner, scanner, factory);
289271
} else if (flywayVersion >= 51) {
290-
Object configuration = getField(flyway, "configuration");
291-
Object scanner = invokeConstructor(Scanner.class, configuration);
272+
Object scanner = createScanner(flyway);
292273
Object placeholderReplacer = invokeMethod(flyway, "createPlaceholderReplacer");
293274
return invokeMethod(flyway, "createMigrationResolver", null, scanner, placeholderReplacer);
294275
} else if (flywayVersion >= 40) {
@@ -302,6 +283,64 @@ protected static MigrationResolver createMigrationResolver(Flyway flyway, String
302283
}
303284
}
304285

286+
protected static Object createScanner(Flyway flyway) throws ClassNotFoundException {
287+
Object configuration = getField(flyway, "configuration");
288+
289+
if (flywayVersion >= 63) {
290+
try {
291+
// this code is only for version 6.3.3 and above
292+
return invokeConstructor("org.flywaydb.core.internal.scanner.Scanner",
293+
ClassUtils.forName("org.flywaydb.core.api.migration.JavaMigration", classLoader),
294+
Arrays.asList((Object[]) invokeMethod(configuration, "getLocations")),
295+
invokeMethod(configuration, "getClassLoader"),
296+
invokeMethod(configuration, "getEncoding"),
297+
getField(flyway, "resourceNameCache"),
298+
getField(flyway, "locationScannerCache"));
299+
} catch (RuntimeException ex) {
300+
if (flywayVersion > 63) {
301+
throw ex;
302+
}
303+
// try next branch
304+
}
305+
}
306+
if (flywayVersion >= 61) {
307+
return invokeConstructor("org.flywaydb.core.internal.scanner.Scanner",
308+
ClassUtils.forName("org.flywaydb.core.api.migration.JavaMigration", classLoader),
309+
Arrays.asList((Object[]) invokeMethod(configuration, "getLocations")),
310+
invokeMethod(configuration, "getClassLoader"),
311+
invokeMethod(configuration, "getEncoding"),
312+
getField(flyway, "resourceNameCache"));
313+
}
314+
if (flywayVersion >= 60) {
315+
try {
316+
// this code is only for version 6.0.7 and above
317+
return invokeConstructor("org.flywaydb.core.internal.scanner.Scanner",
318+
ClassUtils.forName("org.flywaydb.core.api.migration.JavaMigration", classLoader),
319+
Arrays.asList((Object[]) invokeMethod(configuration, "getLocations")),
320+
invokeMethod(configuration, "getClassLoader"),
321+
invokeMethod(configuration, "getEncoding"));
322+
} catch (RuntimeException ex) {
323+
// try next branch
324+
}
325+
}
326+
if (flywayVersion >= 52) {
327+
return invokeConstructor("org.flywaydb.core.internal.scanner.Scanner",
328+
Arrays.asList((Object[]) invokeMethod(configuration, "getLocations")),
329+
invokeMethod(configuration, "getClassLoader"),
330+
invokeMethod(configuration, "getEncoding"));
331+
}
332+
if (flywayVersion >= 51) {
333+
return invokeConstructor(Scanner.class, configuration);
334+
}
335+
336+
throw new IllegalStateException("Unsupported flyway version: " + flywayVersion);
337+
}
338+
339+
protected static Object createMock(String className) throws ClassNotFoundException {
340+
Class<?> proxyInterface = ClassUtils.forName(className, classLoader);
341+
return ProxyFactory.getProxy(proxyInterface, (MethodInterceptor) invocation -> null);
342+
}
343+
305344
protected Flyway getFlywayBean(ApplicationContext applicationContext, FlywayTest annotation) {
306345
if (flywayNameAttributePresent) {
307346
return invokeMethod(this, "getBean", applicationContext, Flyway.class, annotation.flywayName());
@@ -348,16 +387,6 @@ protected static FlywayDataSourceContext getDataSourceContext(ApplicationContext
348387
return null;
349388
}
350389

351-
protected static void closeConnection(AutoCloseable connection) {
352-
if (connection != null) {
353-
try {
354-
connection.close();
355-
} catch (Exception e) {
356-
// ignored
357-
}
358-
}
359-
}
360-
361390
/**
362391
* Customized implementation because {@link AnnotationUtils#findAnnotation(AnnotatedElement, Class)} method
363392
* operates generically on annotated elements and not execute specialized search algorithms for classes and methods.

0 commit comments

Comments
 (0)