/*
 * 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.jdbi.v3.testing;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;

import javax.sql.DataSource;

import com.opentable.db.postgres.embedded.EmbeddedPostgres;
import org.flywaydb.core.Flyway;
import org.jdbi.v3.core.Handle;
import org.jdbi.v3.core.Jdbi;
import org.jdbi.v3.core.spi.JdbiPlugin;
import org.junit.rules.ExternalResource;

JUnit @Rule to manage a Jdbi instance pointed to a managed database.
/** * JUnit {@code @Rule} to manage a Jdbi instance pointed to a managed database. */
public abstract class JdbiRule extends ExternalResource { private final List<JdbiPlugin> plugins = new ArrayList<>(); private final ReentrantLock lock = new ReentrantLock(); private volatile DataSource dataSource; private Jdbi jdbi; private Handle handle; private Flyway flyway; private boolean installPlugins; private Migration migration; protected abstract DataSource createDataSource(); private DataSource getDataSource() { if (dataSource == null) { try { lock.lock(); if (dataSource == null) { dataSource = createDataSource(); } } finally { lock.unlock(); } } return dataSource; }
Create a JdbiRule with an embedded PostgreSQL instance. Your project must depend on the otj-pg-embedded artifact.
/** * Create a JdbiRule with an embedded PostgreSQL instance. * Your project must depend on the {@code otj-pg-embedded} artifact. */
public static JdbiRule embeddedPostgres() { return new EmbeddedPostgresJdbiRule(); }
Create a JdbiRule with an embedded PostgreSQL instance. Your project must depend on the otj-pg-embedded artifact.
Params:
  • customizer – Consumer to customize the created PostgreSQL instance.
/** * Create a JdbiRule with an embedded PostgreSQL instance. * Your project must depend on the {@code otj-pg-embedded} artifact. * * @param customizer {@link Consumer} to customize the created PostgreSQL instance. */
public static JdbiRule embeddedPostgres(Consumer<EmbeddedPostgres.Builder> customizer) { return new EmbeddedPostgresJdbiRule(customizer); }
Create a JdbiRule using an external PostgreSQL instance. Your project must depend on the postgresql driver artifact.
/** * Create a JdbiRule using an external PostgreSQL instance. * Your project must depend on the {@code postgresql} driver artifact. */
public static JdbiRule externalPostgres(final String hostname, final Integer port, // NOPMD final String username, String password, String database) { return new ExternalPostgresJdbiRule(hostname, port, username, password, database); }
Create a JdbiRule with an in-memory H2 database instance. Your project must depend on the h2 database artifact.
/** * Create a JdbiRule with an in-memory H2 database instance. * Your project must depend on the {@code h2} database artifact. */
public static JdbiRule h2() { return new EmbeddedH2JdbiRule(); }
Create a JdbiRule with an in-memory Sqlite database instance. Your project must depend on the sqlite-jdbc database artifact.
/** * Create a JdbiRule with an in-memory Sqlite database instance. * Your project must depend on the {@code sqlite-jdbc} database artifact. */
public static JdbiRule sqlite() { return new EmbeddedSqliteJdbiRule(); }
Run database migration scripts from db/migration on the classpath, using Flyway.
Deprecated:use withMigration(Migration)
Returns:this
/** * Run database migration scripts from {@code db/migration} on the classpath, using Flyway. * @deprecated use {@link #withMigration(Migration)} * @return this */
@Deprecated public JdbiRule migrateWithFlyway() { return migrateWithFlyway("db/migration"); }
Run database migration scripts from the given locations on the classpath, using Flyway.
Deprecated:use withMigration(Migration)
Returns:this
/** * Run database migration scripts from the given locations on the classpath, using Flyway. * @deprecated use {@link #withMigration(Migration)} * @return this */
@Deprecated public JdbiRule migrateWithFlyway(String... locations) { return withMigration(Migration.before().withPaths(locations)); }
Run database migration.
/** * Run database migration. */
public JdbiRule withMigration(final Migration newMigration) { this.migration = newMigration; return this; }
Discover and install plugins from the classpath.
See Also:
  • we recommend installing plugins explicitly instead
/** * Discover and install plugins from the classpath. * * @see JdbiRule#withPlugin(JdbiPlugin) we recommend installing plugins explicitly instead */
public JdbiRule withPlugins() { installPlugins = true; return this; }
Install a plugin into JdbiRule.
/** * Install a plugin into JdbiRule. */
public JdbiRule withPlugin(final JdbiPlugin plugin) { plugins.add(plugin); return this; } @Override public void before() throws Throwable { if (migration != null) { flyway = Flyway.configure() .dataSource(getDataSource()) .locations(migration.paths.toArray(new String[0])) .schemas(migration.schemas.toArray(new String[0])) .load(); flyway.migrate(); } jdbi = Jdbi.create(getDataSource()); if (installPlugins) { jdbi.installPlugins(); } plugins.forEach(jdbi::installPlugin); handle = jdbi.open(); } @Override public void after() { if (flyway != null && migration.cleanAfter) { flyway.clean(); } handle.close(); jdbi = null; dataSource = null; }
Get Jdbi, in case you want to open additional handles to the same data source.
/** * Get Jdbi, in case you want to open additional handles to the same data source. */
public Jdbi getJdbi() { return jdbi; }
Get the single Handle instance opened for the duration of this test case.
/** * Get the single Handle instance opened for the duration of this test case. */
public Handle getHandle() { return handle; }
Attach an extension (such as a SqlObject) to the managed handle.
/** * Attach an extension (such as a SqlObject) to the managed handle. */
public <T> T attach(final Class<T> extension) { return getHandle().attach(extension); } }