在Dropwizard中以编程方式运行迁移

时间:2014-05-10 09:54:31

标签: java liquibase dropwizard

我有dropwizard-application(0.7.0),我想运行集成测试。

我使用DropwizardAppRule设置了集成测试,如下所示:

@ClassRule
public static final DropwizardAppRule<MyAppConfiguration> RULE =
        new DropwizardAppRule<MyAppConfiguration>(
                MyApplication.class, Resources.getResource("testconfiguration.yml").getPath());

当我尝试使用它运行以下测试时,它不起作用,因为我没有运行我的迁移。运行迁移的最佳方法是什么?

测试:

@Test
public void fooTest() {
    Client client = new Client();
    String root = String.format("http://localhost:%d/", RULE.getLocalPort());
    URI uri = UriBuilder.fromUri(root).path("/users").build();
    client.resource(uri).accept(MediaType.APPLICATION_JSON).type(MediaType.APPLICATION_JSON).post(User.class, new LoginUserDTO("email@email.com", "password"));
}

配置:

 public class MyAppConfiguration extends Configuration {
@Valid
@NotNull
private DataSourceFactory database = new DataSourceFactory();

@JsonProperty("database")
public DataSourceFactory getDataSourceFactory() {
    return database;
}

@JsonProperty("database")
public void setDataSourceFactory(DataSourceFactory dataSourceFactory) {
    this.database = dataSourceFactory;
}

}

5 个答案:

答案 0 :(得分:8)

感谢Kimble和andersem让我走上正轨。这是我在@BeforeClass方法中提出的:

// Create the test database with the LiquiBase migrations.
@BeforeClass
public static void up() throws Exception
{
    ManagedDataSource ds = RULE.getConfiguration().getMainDataSource().build(
        RULE.getEnvironment().metrics(), "migrations");
    try (Connection connection = ds.getConnection())
    {
        Liquibase migrator = new Liquibase("migrations.xml", new ClassLoaderResourceAccessor(), new JdbcConnection(connection));
        migrator.update("");
    }
}

答案 1 :(得分:3)

在尝试将数据库迁移作为测试用例的一部分时,我遇到了一些并发问题,最终将其烘焙到应用程序本身(受配置选项保护)。

private void migrate(MyAppConfiguration configuration, Environment environment) {
    if (configuration.isMigrateSchemaOnStartup()) {
        log.info("Running schema migration");
        ManagedDataSource dataSource = createMigrationDataSource(configuration, environment);

        try (Connection connection = dataSource.getConnection()) {
            JdbcConnection conn = new JdbcConnection(connection);

            Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(conn);
            Liquibase liquibase = new Liquibase("migrations.xml", new ClassLoaderResourceAccessor(), database);
            liquibase.update("");

            log.info("Migration completed!");
        }
        catch (Exception ex) {
            throw new IllegalStateException("Unable to migrate database", ex);
        }
        finally {
            try {
                dataSource.stop();
            }
            catch (Exception ex) {
                log.error("Unable to stop data source used to execute schema migration", ex);
            }
        }
    }
    else {
        log.info("Skipping schema migration");
    }
}

private ManagedDataSource createMigrationDataSource(MyAppConfiguration configuration, Environment environment) {
    DataSourceFactory dataSourceFactory = configuration.getDataSourceFactory();

    try {
        return dataSourceFactory.build(environment.metrics(), "migration-ds");
    }
    catch (ClassNotFoundException ex) {
        throw new IllegalStateException("Unable to initialize data source for schema migration", ex);
    }
}

答案 2 :(得分:2)

另一种不依赖于直接导入Liquibase类的方法是使用RULE以与命令行相同的方式运行db migrate命令:

@Before
public void migrateDatabase() throws Exception {
    RULE.getApplication().run("db", "migrate", ResourceHelpers.resourceFilePath("testconfiguration.yml"));
}

此方法也适用于您在开始测试之前可能要运行的任何其他包中的任何其他命令。

一个小问题:使用任何扩展Dropwizards ConfiguredCommand的命令执行此操作(所有dropwizard-migrations都会执行此命令)将在命令完成时不必要地禁用logback。 要恢复它,您可以致电:

        RULE.getConfiguration().getLoggingFactory().configure(RULE.getEnvironment().metrics(),
            RULE.getApplication().getName());

答案 3 :(得分:1)

我是这样使用Liquibase的API:

private void migrate(){
    DataSourceFactory dataSourceFactory = RULE.getConfiguration().dataSourceFactory;
    Properties info = new Properties();
    info.setProperty("user", dataSourceFactory.getUser());
    info.setProperty("password", dataSourceFactory.getPassword());
    org.h2.jdbc.JdbcConnection h2Conn = new org.h2.jdbc.JdbcConnection(dataSourceFactory.getUrl(), info);
    JdbcConnection conn = new JdbcConnection(h2Conn);
    Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(conn);
    Liquibase liquibase = new Liquibase("migrations.xml", new ClassLoaderResourceAccessor(), database);
    String ctx = null;
    liquibase.update(ctx);
}

然后我把它放在一个前类中:

@BeforeClass
public void setup(){
    migrate();
}

它可能不是最终的解决方案,它在很大程度上依赖于您正在使用的数据库,但它确实有效。

答案 4 :(得分:1)

我为实现相同目标所做的是从maven中运行迁移。

将此添加到您的pom.xml

的部分
<plugin>
  <groupId>org.liquibase</groupId>
  <artifactId>liquibase-maven-plugin</artifactId>
  <version>3.0.5</version>
  <executions>
      <execution>
          <phase>process-test-resources</phase>  
          <configuration>
            <changeLogFile>PATH TO YOUR MIGRATIONS FILE</changeLogFile>
            <driver>org.h2.Driver</driver>
            <url>JDBC URL LIKE IN YOUR APP.YML</url>
            <username>USERNAME</username>
            <password>PASSWORD</password>
            <dropFirst>false</dropFirst>
            <promptOnNonLocalDatabase>false</promptOnNonLocalDatabase>
            <logging>info</logging>
          </configuration>
          <goals>
            <goal>dropAll</goal>
            <goal>update</goal>
          </goals>
      </execution>
  </executions>               
</plugin>

这将与命令行中的maven一起使用。使用此设置,maven将使用liquibase dropAll删除所有数据库对象,然后运行迁移,因此每次测试都有一个干净的新数据库。

当使用它时,我使用eclipse运行,它抱怨生命周期映射不能处理插件的执行标记。在这种情况下,您还需要将以下内容添加到构建部分,因此eclipse可以正确映射生命周期:

<pluginManagement>
  <plugins>
    <plugin>
      <groupId>org.eclipse.m2e</groupId>
      <artifactId>lifecycle-mapping</artifactId>
      <version>1.0.0</version>
      <configuration>
        <lifecycleMappingMetadata>
        <pluginExecutions>
          <pluginExecution>
            <pluginExecutionFilter>
              <groupId>org.liquibase</groupId>
              <artifactId>liquibase-maven-plugin</artifactId>
              <versionRange>[1.0,)</versionRange>
              <goals>
                <goal>dropAll</goal>
                <goal>update</goal>
              </goals>
            </pluginExecutionFilter>
            <action>
              <execute />
            </action>
          </pluginExecution>
        </pluginExecutions>
        </lifecycleMappingMetadata>
      </configuration>
    </plugin>
  </plugins>
  </pluginManagement>