2014-05-10 10 views
5

Ho un'applicazione dropwizard (0.7.0) per la quale voglio eseguire i test di integrazione.Eseguire le migrazioni al livello di programmazione in Dropwizard

Ho creato un test di integrazione utilizzando DropwizardAppRule, in questo modo:

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

Quando provo ad eseguire i test di seguito utilizzando esso, non funziona perché non ho eseguito i miei migrazioni. Qual è il modo migliore per eseguire le migrazioni?

prova:

@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 protected]", "password")); 
} 

Configurazione:

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; 
} 

}

risposta

8

Grazie a Kimble e andersem per avermi messo sulla strada giusta. Ecco quello che mi è venuta nel mio metodo @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

ho fatto in questo modo utilizzando API Liquibase:

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); 
} 

E poi ho messo questo in un beforeclass:

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

Probabilmente non è la soluzione definitiva e dipende molto dal database che si sta utilizzando, ma funziona.

3

Mi sono imbattuto in alcuni problemi di concorrenza durante il tentativo di eseguire la migrazione del database come parte del test case e ho finito per cuocerlo nell'applicazione stessa (protetto da un'opzione di configurazione).

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); 
    } 
} 
1

Quello che faccio per raggiungere lo stesso obiettivo è eseguire la migrazione dall'interno di Maven.

Aggiungere questo alla sezione nel sction di vostro 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> 

Questo funziona con Maven da linea di comando. Con questa impostazione, maven userà liquibase dropAll per eliminare tutti gli oggetti del database, quindi eseguirà una migrazione, quindi con ogni test si avrà un nuovo database pulito.

Quando l'ho utilizzato, mi sono imbattuto in eclissi, lamentava la mappatura del ciclo di vita che non funzionava sul tag di esecuzione del plugin. In questo caso, è necessario aggiungere il seguente alla sezione di accumulo e, in modo Eclipse può mappare correttamente i cicli di vita:

<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> 
2

Un altro approccio che non si basa sull'importazione di classi di Liquibase direttamente è quello di eseguire il comando DB migrazione nello stesso modo in cui si potrebbe dalla riga di comando, usando la regola:

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

Questo approccio funziona anche per altri comandi da qualsiasi altro bundle che si potrebbe desiderare di eseguire prima di iniziare i test.

Una piccola strizzatina d'occhio: facendo questo con qualsiasi comando che estende Dropwizards ConfiguredCommand (che fanno tutte le migrazioni di dropwizard) disabiliterà inutilmente il logback al termine del comando. Per ripristinarlo, è possibile chiamare:

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