/*
* Copyright 2010-2017 Boxfuse GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.flywaydb.core;
import org.flywaydb.core.api.FlywayException;
import org.flywaydb.core.api.MigrationInfo;
import org.flywaydb.core.api.MigrationState;
import org.flywaydb.core.api.MigrationType;
import org.flywaydb.core.api.MigrationVersion;
import org.flywaydb.core.internal.dbsupport.JdbcTemplate;
import org.flywaydb.core.internal.dbsupport.Schema;
import org.flywaydb.core.internal.dbsupport.h2.H2DbSupport;
import org.flywaydb.core.internal.util.ClassUtils;
import org.flywaydb.core.internal.util.jdbc.DriverDataSource;
import org.flywaydb.core.internal.util.logging.LogFactory;
import org.flywaydb.core.internal.util.logging.StringLogCreator;
import org.flywaydb.core.internal.util.scanner.classpath.ClassPathResource;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.*;
/**
* Medium tests for the main Flyway class.
*/
@SuppressWarnings({"JavaDoc"})
public class FlywayMediumTest {
/**
* The old classloader, to be restored after a test completes.
*/
private static ClassLoader oldClassLoader;
@BeforeClass
public static void setUp() throws IOException {
oldClassLoader = getClassLoader();
String jar = new ClassPathResource("no-directory-entries.jar", getClassLoader()).getLocationOnDisk();
assertTrue(new File(jar).isFile());
ClassUtils.addJarOrDirectoryToClasspath(jar);
}
private static ClassLoader getClassLoader() {
return Thread.currentThread().getContextClassLoader();
}
@AfterClass
public static void tearDown() {
Thread.currentThread().setContextClassLoader(oldClassLoader);
}
@Test
public void multipleSetDataSourceCalls() throws Exception {
DriverDataSource dataSource1 =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_1;DB_CLOSE_DELAY=-1", "sa", "", null);
DriverDataSource dataSource2 =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_2;DB_CLOSE_DELAY=-1", "sa", "", null);
Connection connection1 = dataSource1.getConnection();
Connection connection2 = dataSource2.getConnection();
Schema schema1 = new H2DbSupport(connection1).getSchema("PUBLIC");
Schema schema2 = new H2DbSupport(connection2).getSchema("PUBLIC");
assertTrue(schema1.empty());
assertTrue(schema2.empty());
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource1);
flyway.setDataSource(dataSource2);
flyway.setLocations("migration/sql");
flyway.migrate();
assertTrue(schema1.empty());
assertFalse(schema2.empty());
connection1.close();
connection2.close();
}
@Test
public void info() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_info;DB_CLOSE_DELAY=-1", "sa", null, null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setLocations("migration/sql");
assertEquals(4, flyway.info().all().length);
assertEquals(4, flyway.info().pending().length);
flyway.setTarget(MigrationVersion.fromVersion("1.1"));
assertEquals(4, flyway.info().all().length);
assertEquals(2, flyway.info().pending().length);
assertEquals(MigrationState.ABOVE_TARGET, flyway.info().all()[2].getState());
assertEquals(MigrationState.ABOVE_TARGET, flyway.info().all()[3].getState());
flyway.migrate();
assertEquals(-133051733, flyway.info().current().getChecksum().intValue());
assertEquals("1.1", flyway.info().current().getVersion().toString());
assertEquals(MigrationState.SUCCESS, flyway.info().current().getState());
assertEquals(4, flyway.info().all().length);
assertEquals(0, flyway.info().pending().length);
flyway.setTarget(MigrationVersion.LATEST);
assertEquals(4, flyway.info().all().length);
assertEquals(2, flyway.info().pending().length);
flyway.migrate();
assertEquals("2.0", flyway.info().current().getVersion().toString());
assertEquals(MigrationState.SUCCESS, flyway.info().current().getState());
assertEquals(4, flyway.info().all().length);
assertEquals(0, flyway.info().pending().length);
}
@Test
public void infoPending() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_info_pending;DB_CLOSE_DELAY=-1", "sa", null, null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
assertEquals(2, flyway.info().pending().length);
}
@Test
public void noDescription() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_no_description;DB_CLOSE_DELAY=-1", "sa", "", null, "SET AUTOCOMMIT OFF");
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setSqlMigrationSeparator(".sql");
flyway.setSqlMigrationSuffix("");
flyway.setLocations("migration/no_description");
flyway.migrate();
MigrationInfo current = flyway.info().current();
assertEquals("1.1", current.getVersion().toString());
assertEquals(MigrationState.SUCCESS, current.getState());
}
@Test
public void callback() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_callback;DB_CLOSE_DELAY=-1", "sa", "", null, "SET AUTOCOMMIT OFF");
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setSqlMigrationPrefix("");
flyway.setLocations("migration/callback");
flyway.migrate();
assertEquals("1", flyway.info().current().getVersion().toString());
assertEquals(MigrationState.SUCCESS, flyway.info().current().getState());
assertEquals("Mr Callback", new JdbcTemplate(dataSource.getConnection(), 0).queryForString("SELECT name FROM test_user"));
}
@Test
public void repairFirst() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_repair;DB_CLOSE_DELAY=-1", "sa", "", null, "SET AUTOCOMMIT OFF");
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
Map<String, String> placeholders = new HashMap<String, String>();
placeholders.put("tableName", "aaa");
flyway.setPlaceholders(placeholders);
flyway.setLocations("migration/failed");
assertEquals(1, flyway.info().all().length);
try {
flyway.migrate();
} catch (FlywayException e) {
//Should happen
}
assertEquals("1", flyway.info().current().getVersion().toString());
assertEquals(MigrationState.FAILED, flyway.info().current().getState());
flyway.repair();
assertNull(flyway.info().current());
}
@Test
public void repairDescription() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_repair_description;DB_CLOSE_DELAY=-1", "sa", "", null, "SET AUTOCOMMIT OFF");
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setLocations("migration/quote");
assertEquals(1, flyway.migrate());
// Switch out V1 for a different migration with a new description and checksum
flyway.setLocations("migration/placeholder");
try {
flyway.validate();
fail();
} catch (FlywayException e) {
//Should happen
}
flyway.repair();
assertEquals(0, flyway.migrate());
}
@Test
public void infoBaseline() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_info_init;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.baseline();
flyway.setLocations();
assertEquals(1, flyway.info().all().length);
assertEquals("1", flyway.info().current().getVersion().toString());
assertEquals(MigrationState.BASELINE, flyway.info().current().getState());
}
@Test
public void baselineAgainWithSameVersion() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_init_same;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setLocations("migration/sql");
flyway.setBaselineVersionAsString("0.5");
flyway.baseline();
flyway.baseline();
assertEquals(1, flyway.info().applied().length);
MigrationInfo current = flyway.info().current();
assertEquals("0.5", current.getVersion().toString());
assertEquals(MigrationType.BASELINE, current.getType());
assertEquals(MigrationState.BASELINE, current.getState());
}
@Test(expected = FlywayException.class)
public void baselineAgainWithDifferentVersion() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_init_different;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.baseline();
flyway.setBaselineVersionAsString("2");
flyway.baseline();
}
@Test(expected = FlywayException.class)
public void cleanDisabled() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_clean_disabled;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
try {
flyway.clean();
} catch (FlywayException e) {
fail("clean should succeed when cleanDisabled is false");
}
flyway.setCleanDisabled(true);
flyway.clean();
}
@Test
public void cleanOnValidate() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_clean_validate;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setSchemas("new1");
flyway.setLocations("migration/validate");
flyway.migrate();
flyway.setCleanOnValidationError(true);
flyway.setValidateOnMigrate(true);
flyway.setSqlMigrationPrefix("CheckValidate");
flyway.migrate();
assertEquals("1", flyway.info().current().getVersion().toString());
}
@Test
public void baselineAfterInit() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_baseline_init;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setSchemas("new1");
flyway.setLocations("migration/validate");
flyway.baseline();
new JdbcTemplate(dataSource.getConnection(), 0).executeStatement("UPDATE \"new1\".\"schema_version\" SET \"type\"='BASELINE' WHERE \"type\"='BASELINE'");
assertEquals("1", flyway.info().current().getVersion().toString());
assertEquals(MigrationType.BASELINE, flyway.info().current().getType());
flyway.baseline();
assertEquals("1", flyway.info().current().getVersion().toString());
assertEquals(MigrationType.BASELINE, flyway.info().current().getType());
}
@Test
public void baselineOnMigrate() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_baseline_migrate;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setSchemas("new1");
flyway.setLocations("migration/sql");
flyway.setBaselineVersionAsString("3");
flyway.migrate();
assertEquals("2.0", flyway.info().current().getVersion().toString());
assertEquals(MigrationType.SQL, flyway.info().current().getType());
flyway.setTable("other_metadata");
flyway.setBaselineOnMigrate(true);
flyway.migrate();
assertEquals("3", flyway.info().current().getVersion().toString());
assertEquals(MigrationType.BASELINE, flyway.info().current().getType());
}
@Test
public void baselineRepair() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_baseline_repair;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setSchemas("new1");
flyway.setLocations("migration/sql");
flyway.setBaselineVersionAsString("2");
flyway.baseline();
assertEquals("2", flyway.info().current().getVersion().toString());
assertEquals(MigrationType.BASELINE, flyway.info().current().getType());
flyway.repair();
assertEquals("2", flyway.info().current().getVersion().toString());
assertEquals(MigrationType.BASELINE, flyway.info().current().getType());
flyway.migrate();
assertEquals("2", flyway.info().current().getVersion().toString());
assertEquals(MigrationType.BASELINE, flyway.info().current().getType());
}
@Test
public void baselineOnMigrateCheck() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_baseline_migrate_check;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setSchemas("new1");
flyway.setLocations("migration/sql");
flyway.setBaselineVersionAsString("3");
flyway.setBaselineOnMigrate(true);
flyway.migrate();
assertEquals("2.0", flyway.info().current().getVersion().toString());
assertEquals(MigrationType.SQL, flyway.info().current().getType());
}
@Test
public void baselineOnMigrateSkipFailed() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_baseline_migrate_failed;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setSchemas("new1");
flyway.setLocations("migration/sql");
flyway.setBaselineVersionAsString("3");
flyway.migrate();
assertEquals("2.0", flyway.info().current().getVersion().toString());
assertEquals(MigrationType.SQL, flyway.info().current().getType());
flyway.setTable("other_metadata");
flyway.setLocations("migration/failed");
flyway.setBaselineOnMigrate(true);
flyway.migrate();
assertEquals("3", flyway.info().current().getVersion().toString());
assertEquals(MigrationType.BASELINE, flyway.info().current().getType());
}
@Test
public void cleanUnknownSchema() throws Exception {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_clean_unknown;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setSchemas("new1");
flyway.clean();
flyway.clean();
}
@Test
public void outOfOrder() {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_out_of_order;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setLocations("migration/sql");
flyway.setTarget(MigrationVersion.fromVersion("1.2"));
assertEquals(4, flyway.info().all().length);
assertEquals(3, flyway.info().pending().length);
flyway.clean();
assertEquals(3, flyway.migrate());
assertEquals("1.2", flyway.info().current().getVersion().getVersion());
assertEquals(0, flyway.info().pending().length);
flyway.setTarget(MigrationVersion.LATEST);
assertEquals(1, flyway.migrate());
assertEquals("2.0", flyway.info().current().getVersion().getVersion());
flyway.setLocations("migration/sql", "migration/outoforder");
assertEquals(5, flyway.info().all().length);
assertEquals(MigrationState.IGNORED, flyway.info().all()[2].getState());
flyway.setValidateOnMigrate(false);
assertEquals(0, flyway.migrate());
flyway.setValidateOnMigrate(true);
flyway.setOutOfOrder(true);
assertEquals(MigrationState.PENDING, flyway.info().all()[4].getState());
assertEquals(1, flyway.migrate());
assertEquals("2.0", flyway.info().current().getVersion().getVersion());
MigrationInfo[] all = flyway.info().all();
assertEquals(MigrationState.SUCCESS, all[3].getState());
assertEquals(MigrationState.OUT_OF_ORDER, all[4].getState());
}
@Test
public void outOfOrderInOrder() {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_out_of_order_in_order;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setLocations("migration/sql");
flyway.migrate();
MigrationVersion highest = null;
for (MigrationInfo migrationInfo : flyway.info().applied()) {
assertEquals(MigrationState.SUCCESS, migrationInfo.getState());
if (highest == null) {
highest = migrationInfo.getVersion();
} else {
assertTrue(migrationInfo.getVersion().compareTo(highest) > 0);
highest = migrationInfo.getVersion();
}
}
assertEquals(MigrationVersion.fromVersion("2.0"), highest);
}
@Test
public void repeatable() {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_repeatable;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setTargetAsString("1.1");
flyway.setLocations("migration/sql", "migration/repeatable");
assertEquals(4, flyway.migrate());
assertEquals(0, flyway.info().pending().length);
MigrationInfo[] all = flyway.info().all();
assertEquals(MigrationState.SUCCESS, all[0].getState());
assertEquals(MigrationState.SUCCESS, all[1].getState());
assertEquals(MigrationState.SUCCESS, all[2].getState());
assertEquals(MigrationState.SUCCESS, all[3].getState());
assertEquals(MigrationState.ABOVE_TARGET, all[4].getState());
assertEquals(MigrationState.ABOVE_TARGET, all[5].getState());
flyway.setTarget(MigrationVersion.LATEST);
flyway.setLocations("migration/sql", "migration/repeatable2");
all = flyway.info().all();
assertEquals(MigrationState.SUCCESS, all[0].getState());
assertEquals(MigrationState.SUCCESS, all[1].getState());
assertEquals(MigrationState.OUTDATED, all[2].getState());
assertEquals(MigrationState.OUTDATED, all[3].getState());
assertEquals(MigrationState.PENDING, all[4].getState());
assertEquals(MigrationState.PENDING, all[5].getState());
assertEquals(MigrationState.PENDING, all[6].getState());
assertEquals(MigrationState.PENDING, all[7].getState());
assertNotNull(all[0].getVersion());
assertNotNull(all[1].getVersion());
assertNull(all[2].getVersion());
assertNull(all[3].getVersion());
assertNotNull(all[4].getVersion());
assertNotNull(all[5].getVersion());
assertNull(all[6].getVersion());
assertNull(all[7].getVersion());
assertEquals(4, flyway.info().pending().length);
assertEquals(4, flyway.migrate());
assertEquals(0, flyway.info().pending().length);
all = flyway.info().all();
assertEquals(MigrationState.SUCCESS, all[0].getState());
assertEquals(MigrationState.SUCCESS, all[1].getState());
assertEquals(MigrationState.SUPERSEEDED, all[2].getState());
assertEquals(MigrationState.SUPERSEEDED, all[3].getState());
assertEquals(MigrationState.SUCCESS, all[4].getState());
assertEquals(MigrationState.SUCCESS, all[5].getState());
assertEquals(MigrationState.SUCCESS, all[6].getState());
assertEquals(MigrationState.SUCCESS, all[7].getState());
assertNotNull(all[0].getVersion());
assertNotNull(all[1].getVersion());
assertNull(all[2].getVersion());
assertNull(all[3].getVersion());
assertNotNull(all[4].getVersion());
assertNotNull(all[5].getVersion());
assertNull(all[6].getVersion());
assertNull(all[7].getVersion());
assertEquals(0, flyway.migrate());
// Revert to original repeatable migrations, which should now be reapplied
flyway.setLocations("migration/sql", "migration/repeatable");
all = flyway.info().all();
assertEquals(MigrationState.SUCCESS, all[0].getState());
assertEquals(MigrationState.SUCCESS, all[1].getState());
assertEquals(MigrationState.SUPERSEEDED, all[2].getState());
assertEquals(MigrationState.SUPERSEEDED, all[3].getState());
assertEquals(MigrationState.SUCCESS, all[4].getState());
assertEquals(MigrationState.SUCCESS, all[5].getState());
assertEquals(MigrationState.OUTDATED, all[6].getState());
assertEquals(MigrationState.OUTDATED, all[7].getState());
assertEquals(MigrationState.PENDING, all[8].getState());
assertEquals(MigrationState.PENDING, all[9].getState());
assertEquals(2, flyway.migrate());
assertEquals(0, flyway.info().pending().length);
all = flyway.info().all();
assertEquals(MigrationState.SUCCESS, all[0].getState());
assertEquals(MigrationState.SUCCESS, all[1].getState());
assertEquals(MigrationState.SUPERSEEDED, all[2].getState());
assertEquals(MigrationState.SUPERSEEDED, all[3].getState());
assertEquals(MigrationState.SUCCESS, all[4].getState());
assertEquals(MigrationState.SUCCESS, all[5].getState());
assertEquals(MigrationState.SUPERSEEDED, all[6].getState());
assertEquals(MigrationState.SUPERSEEDED, all[7].getState());
assertEquals(MigrationState.SUCCESS, all[8].getState());
assertEquals(MigrationState.SUCCESS, all[9].getState());
assertNotNull(all[0].getVersion());
assertNotNull(all[1].getVersion());
assertNull(all[2].getVersion());
assertNull(all[3].getVersion());
assertNotNull(all[4].getVersion());
assertNotNull(all[5].getVersion());
assertNull(all[6].getVersion());
assertNull(all[7].getVersion());
assertNull(all[8].getVersion());
assertNull(all[9].getVersion());
}
@Test
public void repeatableFailed() {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_repeatable_failed;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setLocations("migration/repeatable_failed");
try {
flyway.migrate();
fail();
} catch (FlywayException e) {
assertEquals(e.getMessage(), MigrationState.FAILED, flyway.info().current().getState());
}
try {
flyway.validate();
fail();
} catch (FlywayException e) {
assertTrue(e.getMessage(), e.getMessage().contains("failed repeatable migration"));
}
flyway.setLocations("migration/repeatable");
try {
flyway.migrate();
fail();
} catch (FlywayException e) {
assertTrue(e.getMessage(), e.getMessage().contains("failed repeatable migration"));
}
}
@Test
public void repeatableOnly() {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_repeatable_only;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setLocations("migration/repeatable");
assertEquals(2, flyway.migrate());
}
@Test(expected = FlywayException.class)
public void repeatableVersion() {
DriverDataSource dataSource =
new DriverDataSource(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_repeatable_version;DB_CLOSE_DELAY=-1", "sa", "", null);
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setLocations("migration/repeatable_version");
assertEquals(0, flyway.migrate());
}
@Test
public void currentEmpty() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_current_empty;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setTargetAsString("current");
assertEquals(0, flyway.migrate());
// Used to fail with NPE
}
@Test
public void emptyLocations() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_empty;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/empty");
assertEquals(0, flyway.migrate());
// Used to fail with exception due to non-empty schema and empty metadata table.
assertEquals(0, flyway.migrate());
}
@Test
public void noPlaceholderReplacement() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_no_placeholder_replacement;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.setPlaceholderReplacement(false);
assertEquals(4, flyway.migrate());
}
@Test
public void missingMigrations() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_missing;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.migrate();
flyway.setLocations("migration/missing");
flyway.setIgnoreMissingMigrations(true);
flyway.migrate();
assertEquals(MigrationState.MISSING_SUCCESS, flyway.info().applied()[1].getState());
}
@Test(expected = FlywayException.class)
public void missingMigrationsNotAllowed() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_missing_not_allowed;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.migrate();
flyway.setLocations("migration/missing");
flyway.setIgnoreMissingMigrations(false);
flyway.migrate();
}
@Test
public void futureMigrations() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_future;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.migrate();
flyway.setLocations("migration/empty");
flyway.setValidateOnMigrate(true);
flyway.migrate();
assertEquals(MigrationState.FUTURE_SUCCESS, flyway.info().applied()[0].getState());
}
@Test(expected = FlywayException.class)
public void futureMigrationsNotAllowed() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_future_not_allowed;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.migrate();
flyway.setLocations("migration/empty");
flyway.setIgnoreFutureMigrations(false);
flyway.migrate();
}
@Test
public void validateApplied() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_validate_applied;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.migrate();
flyway.validate();
}
@Test
public void installedBy() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_installed_by;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.setTarget(MigrationVersion.fromVersion("1"));
flyway.migrate();
flyway.setTarget(MigrationVersion.fromVersion("1.1"));
flyway.setInstalledBy("abc");
flyway.migrate();
flyway.setTarget(MigrationVersion.LATEST);
flyway.setInstalledBy(null);
flyway.migrate();
assertEquals("SA", flyway.info().applied()[0].getInstalledBy());
assertEquals("abc", flyway.info().applied()[1].getInstalledBy());
assertEquals("SA", flyway.info().applied()[2].getInstalledBy());
}
@Test(expected = FlywayException.class)
public void validateMissing() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_validate_missing;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql", "migration/outoforder");
flyway.migrate();
flyway.setLocations("migration/sql");
flyway.migrate();
}
@Test
public void placeholderDisabled() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_placeholder;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/placeholder");
flyway.setPlaceholderReplacement(false);
flyway.migrate();
}
@Test
public void noLocations() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_locations;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations();
flyway.migrate();
}
@Test
public void invalidLocations() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_invalid;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("abcd", "efgh");
flyway.migrate();
}
@Test
public void validateOutOfOrder() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_validate_outoforder;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.migrate();
flyway.validate();
flyway.setLocations("migration/sql", "migration/outoforder");
try {
flyway.validate();
fail();
} catch (FlywayException e) {
assertTrue(e.getMessage().contains("not applied"));
}
flyway.setOutOfOrder(true);
try {
flyway.validate();
fail();
} catch (FlywayException e) {
assertTrue(e.getMessage().contains("not applied"));
}
flyway.migrate();
flyway.validate();
}
@Test
public void validateEmpty() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_validate_empty;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/empty");
flyway.validate();
}
@Test(expected = FlywayException.class)
public void validateNotApplied() {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_validate_pending;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.validate();
}
@Test(expected = FlywayException.class)
public void validateWithPendingWithoutTarget() {
// Populate database up to version 1.2
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_validate_pending;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.setTarget(MigrationVersion.fromVersion("1.2"));
flyway.migrate();
// Validate migrations with pending migration 2.0 on classpath
flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_validate_pending;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.validate();
}
@Test
public void validateWithPendingWithTarget() {
// Populate database up to version 1.2
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_validate_pending;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.setTarget(MigrationVersion.fromVersion("1.2"));
flyway.migrate();
// Validate migrations with pending migration 2.0 on classpath
flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_validate_pending;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.setTarget(MigrationVersion.CURRENT);
flyway.validate();
}
@Test
public void migrateWithTargetCurrent() {
// Populate database up to version 1.2
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_validate_pending;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.setTarget(MigrationVersion.fromVersion("1.2"));
flyway.migrate();
assertEquals(4, flyway.info().all().length);
assertEquals(3, flyway.info().applied().length);
assertEquals(0, flyway.info().pending().length);
assertEquals(MigrationState.ABOVE_TARGET, flyway.info().all()[3].getState());
// This should be a no-op as target=current will ignore future migrations
flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_validate_pending;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/sql");
flyway.setTarget(MigrationVersion.CURRENT);
flyway.migrate();
assertEquals(4, flyway.info().all().length);
assertEquals(3, flyway.info().applied().length);
assertEquals(0, flyway.info().pending().length);
assertEquals(MigrationState.ABOVE_TARGET, flyway.info().all()[3].getState());
}
@Test
public void failed() {
StringLogCreator logCreator = new StringLogCreator();
LogFactory.setLogCreator(logCreator);
try {
Flyway flyway = new Flyway();
flyway.setDataSource("jdbc:h2:mem:flyway_failed;DB_CLOSE_DELAY=-1", "sa", "");
flyway.setLocations("migration/failed");
flyway.migrate();
fail();
} catch (FlywayException e) {
System.out.println(logCreator.getOutput());
} finally {
LogFactory.setLogCreator(null);
}
}
@Test
public void noConnectionLeak() {
OpenConnectionCountDriverDataSource dataSource = new OpenConnectionCountDriverDataSource();
assertEquals(0, dataSource.getOpenConnectionCount());
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setLocations("migration/sql");
flyway.clean();
assertEquals(0, dataSource.getOpenConnectionCount());
assertEquals(4, flyway.migrate());
assertEquals(0, dataSource.getOpenConnectionCount());
}
@Test
public void noConnectionLeakWithException() {
OpenConnectionCountDriverDataSource dataSource = new OpenConnectionCountDriverDataSource();
assertEquals(0, dataSource.getOpenConnectionCount());
Flyway flyway = new Flyway();
flyway.setDataSource(dataSource);
flyway.setLocations("migration/failed");
try {
flyway.clean();
assertEquals(0, dataSource.getOpenConnectionCount());
flyway.migrate();
fail();
} catch (FlywayException e) {
//Expected -> Ignore
}
assertEquals(0, dataSource.getOpenConnectionCount());
}
/**
* Tests the functionality of the OpenConnectionCountDriverDataSource.
*/
@Test
public void connectionCount() throws Exception {
OpenConnectionCountDriverDataSource dataSource = new OpenConnectionCountDriverDataSource();
assertEquals(0, dataSource.getOpenConnectionCount());
Connection connection = dataSource.getConnection();
assertEquals(1, dataSource.getOpenConnectionCount());
connection.close();
assertEquals(0, dataSource.getOpenConnectionCount());
Connection connection2 = dataSource.getConnection();
assertEquals(1, dataSource.getOpenConnectionCount());
Connection connection3 = dataSource.getConnection();
assertEquals(2, dataSource.getOpenConnectionCount());
connection2.close();
assertEquals(1, dataSource.getOpenConnectionCount());
connection3.close();
assertEquals(0, dataSource.getOpenConnectionCount());
}
private static class OpenConnectionCountDriverDataSource extends DriverDataSource {
/**
* The number of connections currently open.
*/
private int openConnectionCount = 0;
public OpenConnectionCountDriverDataSource() {
super(Thread.currentThread().getContextClassLoader(), null, "jdbc:h2:mem:flyway_db_open_connection;DB_CLOSE_DELAY=-1", "sa", "", null);
}
/**
* @return The number of connections currently open.
*/
public int getOpenConnectionCount() {
return openConnectionCount;
}
@Override
protected Connection getConnectionFromDriver(String username, String password) throws SQLException {
final Connection connection = super.getConnectionFromDriver(username, password);
openConnectionCount++;
return (Connection) Proxy.newProxyInstance(getClass().getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("close".equals(method.getName())) {
openConnectionCount--;
}
return method.invoke(connection, args);
}
});
}
}
}