All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kiwiproject.test.junit.jupiter.PostgresLiquibaseTestExtension Maven / Gradle / Ivy

package org.kiwiproject.test.junit.jupiter;

import static java.util.Objects.nonNull;
import static org.kiwiproject.base.KiwiStrings.f;

import io.zonky.test.db.postgres.embedded.LiquibasePreparer;
import io.zonky.test.db.postgres.junit5.EmbeddedPostgresExtension;
import io.zonky.test.db.postgres.junit5.PreparedDbExtension;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.kiwiproject.test.jdbc.JdbcTests;
import org.kiwiproject.test.jdbc.SimpleSingleConnectionDataSource;

/**
 * This JUnit Jupiter extension uses the Embedded Postgres Jupiter extension but always returns a
 * {@link SimpleSingleConnectionDataSource}. This ensures that classes under test all use the same
 * JDBC {@code Connection} which is useful when the test code executes in a transaction and thus
 * all those classes can all see the uncommitted data.
 * 

* When registering this extension, you must use a {@code static} field because both {@link BeforeAllCallback} * and {@link AfterAllCallback} must be registered at the class level. *

* Example usage showing this extension used to supply the {@code DataSource} for a {@link Jdbi3Extension}: *

 * class MyDatabaseTest {
 *
 *    {@literal @}RegisterExtension
 *     static final PostgresLiquibaseTestExtension DATABASE_EXTENSION =
 *             new PostgresLiquibaseTestExtension("migrations.xml");
 *
 *    {@literal @}RegisterExtension
 *     final Jdbi3Extension jdbi3Extension =  Jdbi3Extension.builder()
 *             .dataSource(DATABASE_EXTENSION.getDataSource())
 *             .plugin(new PostgresPlugin())
 *             .build();
 *
 *     // ...tests...
 * }
 * 
* Note in the above that the {@link PostgresLiquibaseTestExtension} is declared both static and final, while the * {@link Jdbi3Extension} is not static but is final. This configuration ensures that the embedded Postgres database * is set up only one time before all tests run. The {@link Jdbi3Extension} is initialized before each test with * a new transaction that is rolled back after each test, which again ensures code running in the transaction * participates in the same transaction and can see uncommitted data, but also ensures no data is actually committed * since the transaction is rolled back. Each test therefore does not need to worry about cleaning up any data from * previous tests. * * @see PreparedDbExtension * @see SimpleSingleConnectionDataSource */ @Slf4j public class PostgresLiquibaseTestExtension implements BeforeAllCallback, AfterAllCallback { private static final String EMPTY_PASSWORD = ""; /** * The embedded Postgres extension. Generally you should not need this directly when using this extension, but * we are exposing it just in case and because this is a testing library, not a production API. */ @Getter private final PreparedDbExtension postgres; /** * The test DataSource, which is a {@link SimpleSingleConnectionDataSource}. */ @Getter private SimpleSingleConnectionDataSource testDataSource; /** * Construct a new instance using the given classpath location of a Liquibase migrations file. * * @param migrationClassPathLocation classpath location of Liquibase migrations file */ public PostgresLiquibaseTestExtension(String migrationClassPathLocation) { LOG.trace("Constructing new instance for migration path: {}", migrationClassPathLocation); var liquibasePreparer = LiquibasePreparer.forClasspathLocation(migrationClassPathLocation); postgres = EmbeddedPostgresExtension.preparedDatabase(liquibasePreparer); } /** * Start the embedded Postgres extension and initialize a test DataSource that connects to it. This test * DataSource should be used in your tests to obtain a Connection. * * @param context the extension context * @throws Exception if any error occurs initializing the embedded Postgres or connecting to it */ @Override public void beforeAll(ExtensionContext context) throws Exception { LOG.trace("Invoke PreparedDbExtension.beforeAll() to initialize the embedded Postgres"); postgres.beforeAll(context); var connectionInfo = postgres.getConnectionInfo(); var url = f("jdbc:postgresql://localhost:{}/{}", connectionInfo.getPort(), connectionInfo.getDbName()); var user = connectionInfo.getUser(); LOG.trace("Initializing new single-connection test DataSource for URL {} and user {}", url, user); testDataSource = JdbcTests.newTestDataSource(url, user, EMPTY_PASSWORD); } /** * Closes the Connection provided by the test DataSource, then shuts down the embedded Postgres. * * @param context the extension context */ @Override public void afterAll(ExtensionContext context) { if (nonNull(testDataSource)) { LOG.trace("Closing test DataSource"); testDataSource.close(); } LOG.trace("Invoke PreparedDbExtension.afterAll() to shut down the embedded Postgres"); postgres.afterAll(context); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy