Skip to content

Commit

Permalink
feat(jooq): Allow to choose Flyway migrations location
Browse files Browse the repository at this point in the history
fix #11
  • Loading branch information
Marthym committed Dec 7, 2020
1 parent 8d50139 commit 786daa7
Show file tree
Hide file tree
Showing 10 changed files with 213 additions and 33 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ void setUp(@Named("my_catalog_1") DataSource dataSource1,

This extension depends on a [DatasourceExtension](https://rocket.i-run.si/javadoc/fr/irun/testy/jooq/DatasourceExtension.html) and runs a [Flyway](https://flywaydb.org/) migration on the related DB catalog.

The SQL scripts shall be located into `db.migration.<catalog>` in the classpath, where `<catalog>` is the name of DataSource catalog. The names of the SQL files shall match [Flyway naming convention](https://flywaydb.org/documentation/migrations#naming).
By default, the SQL scripts have to be located into `db.migration.<catalog>` in the classpath, where `<catalog>` is the name of DataSource catalog. The names of the SQL files shall match [Flyway naming convention](https://flywaydb.org/documentation/migrations#naming).

The SQL scripts are run **before all the test methods**. They are expected to be used to create the database schema.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
* <li>Can declare many queues with related exchanges</li>
* <li>Builds a {@link MockedSender} and a {@link MockedReceiver} to simplify the mocking of the queues.</li>
* </ul>
* <p>
* <br>
* Usage :
* <pre style="code">
* private static final String QUEUE_1 = "test-queue-1";
Expand All @@ -66,7 +66,7 @@
* .append(withRabbit)
* .register();
* </pre>
* <p>
* <br>
* Example to test a "listener" class.
* A "listener" is expected to:
* <ul>
Expand All @@ -76,7 +76,7 @@
* <li>Reply another message on the reply queue</li>
* <li>The {@link MockedSender} can be used to simplify the sending of messages on a queue.</li>
* </ul>
* <p>
* <br>
* <pre style="code">
* {@literal @}Test
* void should_consume_queue_and_reply_message(MockedSender mockedSender, ObjectMapper objectMapper) {
Expand All @@ -92,21 +92,21 @@
* assertThat(actualResponse).isEqualTo("expected message replied by tested listener");
* }
* </pre>
* <p>
* <br>
* Assert example to test an "emitter" class.
* An "emitter" is expected to:
* <ul>
* <li>Send a message on the queue/exchange</li>
* <li>Treat the response.</li>
* </ul>
* <p>
* <br>
* Note that:
* <ul>
* <li>An {@link MockedReceiver} can be injected to the test.</li>
* <li>It can consume a defined number of messages on a queue and reply defined responses.</li>
* <li>The method {@link MockedReceiver.MockedConsumerBuilder#start()} returns all the requests consumed from the queue.</li>
* </ul>
* <p>
* <br>
* <pre style="code">
* {@literal @}Test
* void should_emit_message_and_manage_response(MockedReceiver mockedReceiver,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,66 @@
package fr.irun.testy.jooq;

import lombok.AllArgsConstructor;
import org.flywaydb.core.Flyway;
import org.flywaydb.core.api.Location;
import org.flywaydb.core.api.configuration.ClassicConfiguration;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

import javax.annotation.Nullable;
import javax.sql.DataSource;
import java.util.Objects;
import java.util.Optional;

/**
* <p>This extension depends on a {@link DatasourceExtension} and runs a <a href="https://flywaydb.org/">Flyway</a>
* migration on the related DB catalog.</p>
*
* <p>By default, the SQL scripts have to be located into {@code db.migration.<catalog>} in the classpath, where {@code <catalog>}
* is the name of DataSource catalog. The names of the SQL files shall match
* <a href="https://flywaydb.org/documentation/migrations#naming">Flyway naming convention</a>.</p>
*
* <p>The SQL scripts are run **before all the test methods**. They are expected to be used to create the database schema.</p>
*
* <pre><code>
* private static final WithInMemoryDatasource wDataSource = WithInMemoryDatasource.builder()
* .setCatalog("my_catalog")
* .build();
*
* // SQL files shall be located in classpath:db.migration.my_catalog
* private static final WithDatabaseLoaded wDatabaseLoaded = WithDatabaseLoaded.builder()
* .setDatasourceExtension(wDataSource)
* .build();
*
* {@literal @}RegisterExtension
* static final ChainedExtension chain = ChainedExtension
* .outer(wDataSource)
* .append(wDatabaseLoaded)
* .register();
* </code></pre>
*/
@AllArgsConstructor
public final class WithDatabaseLoaded implements BeforeAllCallback, BeforeEachCallback {
private static final String P_LOADED = "dbLoaded_";

private final DatasourceExtension wDatasource;

private WithDatabaseLoaded(DatasourceExtension dataSourceProvider) {
this.wDatasource = dataSourceProvider;
}
@Nullable
private final Location location;

@Override
public void beforeAll(ExtensionContext context) {
String catalog = getContextCatalog(context);
DataSource dataSource = Objects.requireNonNull(wDatasource.getDataSource(context),
"DataSource not found in context Store !");

Location migrationsLocation = Optional.ofNullable(location)
.orElseGet(() -> new Location("classpath:db/migration/" + catalog));
Flyway flyway = Flyway.configure()
.dataSource(dataSource)
.schemas(catalog)
.placeholderReplacement(false)
.locations("classpath:db/migration/" + catalog)
.locations(migrationsLocation)
.load();
flyway.clean();
flyway.migrate();
Expand Down Expand Up @@ -55,17 +88,65 @@ public static WithDatabaseLoadedBuilder builder() {
return new WithDatabaseLoadedBuilder();
}

/**
* Builder for {@link WithDatabaseLoaded}
*/
public static class WithDatabaseLoadedBuilder {
private DatasourceExtension wDatasource;
private Location location = null;

/**
* <p>Allow to link the {@link DatasourceExtension} with the {@link WithDatabaseLoaded}. The Flyway migrations
* was applied to the {@link DataSource} created by this extension.</p>
* <p>This setter is mandatory.</p>
*
* @param wDatasource The linked {@link DataSource} extension
* @return The current builder
*/
public WithDatabaseLoadedBuilder setDatasourceExtension(DatasourceExtension wDatasource) {
this.wDatasource = wDatasource;
return this;
}

/**
* <p>Allow to set the migrations location. To indicate Flyway where to found SQL files.</p>
*
* <p>By default, the {@link WithDatabaseLoaded} use {@code db/migration/catalog}, where catalog was the
* schema given by the {@link DataSource} context</p>
*
* <p>This method was not compatible with {@link #useFlywayDefaultLocation()}</p>
*
* @param location The migration files location.
* @return The current builder
*/
public WithDatabaseLoadedBuilder setMigrationsLocation(String location) {
this.location = new Location(location);
return this;
}

/**
* <p>Use the Flyway default migrations location instead a migration with catalog name.</p>
*
* <p>By default, the {@link WithDatabaseLoaded} use {@code db/migration/catalog}, where catalog was the
* schema given by the {@link DataSource} context</p>
*
* <p>This method was not compatible with {@link #setMigrationsLocation(String)}</p>
*
* @return The current builder
*/
public WithDatabaseLoadedBuilder useFlywayDefaultLocation() {
this.location = new ClassicConfiguration().getLocations()[0];
return this;
}

/**
* Build the {@link WithDatabaseLoaded} extension
*
* @return The extension
*/
public WithDatabaseLoaded build() {
Objects.requireNonNull(wDatasource, "A DataSource extension was mandatory !");
return new WithDatabaseLoaded(wDatasource);
return new WithDatabaseLoaded(wDatasource, location);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ class WithDatabaseLoadedTest {
static WithDatabaseLoaded wDbLoaded = WithDatabaseLoaded.builder()
.setDatasourceExtension(wDs).build();

@RegisterExtension
static WithDatabaseLoaded wDbLoadedLocation = WithDatabaseLoaded.builder()
.setMigrationsLocation("db/migration/dummy_legacy")
.setDatasourceExtension(wDs).build();

@Test
void should_get_data_form_loaded_db(DataSource ds) throws SQLException {
List<String> actuals = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package fr.irun.testy.jooq;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class WithDatabaseLoadedWithLocationTest {
@RegisterExtension
static WithInMemoryDatasource wDs = WithInMemoryDatasource.builder()
.setCatalog("dummy").build();

@RegisterExtension
static WithDatabaseLoaded wDbLoadedLocation = WithDatabaseLoaded.builder()
.setMigrationsLocation("db/migration/dummy_legacy")
.setDatasourceExtension(wDs).build();

@Test
void should_get_data_form_loaded_db(DataSource ds) throws SQLException {
List<String> actuals = new ArrayList<>();
try (Connection conn = ds.getConnection();
Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery("SELECT * FROM GUNGAN");

while (rs.next()) {
actuals.add(rs.getString(1) + " " + rs.getString(2));
}
rs.close();
}

assertThat(actuals).contains("Jar Jar Binks");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package fr.irun.testy.jooq;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class WithDatabaseLoadedWithoutCatalogTest {
@RegisterExtension
static WithInMemoryDatasource wDs = WithInMemoryDatasource.builder().build();

@RegisterExtension
static WithDatabaseLoaded wDbLoaded = WithDatabaseLoaded.builder()
.setDatasourceExtension(wDs)
.useFlywayDefaultLocation()
.build();

@Test
void should_get_data_form_loaded_db(DataSource ds) throws SQLException {
List<String> actuals = new ArrayList<>();
try (Connection conn = ds.getConnection();
Statement stmt = conn.createStatement()) {
ResultSet rs = stmt.executeQuery("SELECT * FROM JEDI");

while (rs.next()) {
actuals.add(rs.getString(1) + " " + rs.getString(2));
}
rs.close();
}

assertThat(actuals).contains("Obiwan Kenobi", "Dark Vador");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,28 @@
class WithMultipleDataSourcesTest {
private static final String NORA_CATALOG = "dummy_nora";
private static final String LEGACY_CATALOG = "dummy_legacy";
private static final String SQL_SELECT_ALL_JEDIS = "SELECT FIRST_NAME, LAST_NAME FROM JEDI";
private static final String SQL_SELECT_ALL_GUNGANS = "SELECT FIRST_NAME, LAST_NAME FROM GUNGAN";
private static final String SQL_SELECT_ALL_MASTERS = "SELECT FIRST_NAME, LAST_NAME FROM MASTER";

private static WithInMemoryDatasource wLegacyDatasource = WithInMemoryDatasource.builder()
private final static WithInMemoryDatasource wLegacyDatasource = WithInMemoryDatasource.builder()
.setCatalog(LEGACY_CATALOG)
.setReferentialIntegrity(false)
.build();
private static WithDatabaseLoaded wLegacyDatabase = WithDatabaseLoaded.builder()
private final static WithDatabaseLoaded wLegacyDatabase = WithDatabaseLoaded.builder()
.setDatasourceExtension(wLegacyDatasource)
.build();
private static WithDslContext wLegacyContext = WithDslContext.builder()
private final static WithDslContext wLegacyContext = WithDslContext.builder()
.setDatasourceExtension(wLegacyDatasource)
.setDialect(SQLDialect.H2)
.build();

private static WithInMemoryDatasource wNoraDatasource = WithInMemoryDatasource.builder()
private final static WithInMemoryDatasource wNoraDatasource = WithInMemoryDatasource.builder()
.setCatalog(NORA_CATALOG)
.build();
private static WithDatabaseLoaded wNoraDatabase = WithDatabaseLoaded.builder()
private final static WithDatabaseLoaded wNoraDatabase = WithDatabaseLoaded.builder()
.setDatasourceExtension(wNoraDatasource)
.build();
private static WithDslContext wNoraContext = WithDslContext.builder()
private final static WithDslContext wNoraContext = WithDslContext.builder()
.setDatasourceExtension(wNoraDatasource)
.setDialect(SQLDialect.H2)
.build();
Expand All @@ -63,15 +64,15 @@ void shouldSetLegacyContext(@Named(LEGACY_CATALOG) DSLContext legacyContext,
// Check data
assertThat(legacyContext).isNotNull();

final Result<Record> actualLegacyResult = legacyContext.fetch(SQL_SELECT_ALL_JEDIS);
final Result<Record> actualLegacyResult = legacyContext.fetch(SQL_SELECT_ALL_GUNGANS);
assertThat(actualLegacyResult).isNotNull();
assertThat(actualLegacyResult).isNotEmpty();
assertThat(actualLegacyResult).hasSize(1);

final Record actualLegacyRecord = actualLegacyResult.get(0);
assertThat(actualLegacyRecord).isNotNull();
assertThat(actualLegacyRecord.get(0)).isEqualTo("Dark");
assertThat(actualLegacyRecord.get(1)).isEqualTo("Vador");
assertThat(actualLegacyRecord.get(0)).isEqualTo("Jar Jar");
assertThat(actualLegacyRecord.get(1)).isEqualTo("Binks");
}

@Test
Expand All @@ -84,7 +85,7 @@ void shouldSetNoraContext(@Named(NORA_CATALOG) DSLContext noraContext,
// Check data
assertThat(noraContext).isNotNull();

final Result<Record> actualNoraResult = noraContext.fetch(SQL_SELECT_ALL_JEDIS);
final Result<Record> actualNoraResult = noraContext.fetch(SQL_SELECT_ALL_MASTERS);
assertThat(actualNoraResult).isNotNull();
assertThat(actualNoraResult).isNotEmpty();
assertThat(actualNoraResult).hasSize(1);
Expand All @@ -107,23 +108,23 @@ void shouldSetBothContexts(@Named(LEGACY_CATALOG) DSLContext legacyContext,
// Check legacy data
assertThat(legacyContext).isNotNull();

final Result<Record> actualLegacyResult = legacyContext.fetch(SQL_SELECT_ALL_JEDIS);
final Result<Record> actualLegacyResult = legacyContext.fetch(SQL_SELECT_ALL_GUNGANS);
assertThat(actualLegacyResult).isNotNull();
assertThat(actualLegacyResult).isNotEmpty();
assertThat(actualLegacyResult).hasSize(1);

final Record actualLegacyRecord = actualLegacyResult.get(0);
assertThat(actualLegacyRecord).isNotNull();
assertThat(actualLegacyRecord.get(0)).isEqualTo("Dark");
assertThat(actualLegacyRecord.get(1)).isEqualTo("Vador");
assertThat(actualLegacyRecord.get(0)).isEqualTo("Jar Jar");
assertThat(actualLegacyRecord.get(1)).isEqualTo("Binks");

// Check nora catalog
assertThat(noraCatalog).isEqualTo(NORA_CATALOG);

// Check nora data
assertThat(noraContext).isNotNull();

final Result<Record> actualNoraResult = noraContext.fetch(SQL_SELECT_ALL_JEDIS);
final Result<Record> actualNoraResult = noraContext.fetch(SQL_SELECT_ALL_MASTERS);
assertThat(actualNoraResult).isNotNull();
assertThat(actualNoraResult).isNotEmpty();
assertThat(actualNoraResult).hasSize(1);
Expand Down
Loading

0 comments on commit 786daa7

Please sign in to comment.