package org.testcontainers.jdbc; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.ResultSetHandler; import org.apache.tomcat.jdbc.pool.PoolProperties; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.vibur.dbcp.ViburDBCPDataSource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; import static java.util.Arrays.asList; import static org.rnorth.visibleassertions.VisibleAssertions.assertEquals; /** * */ @RunWith(Parameterized.class) public class JDBCDriverWithPoolTest { public static final String URL = "jdbc:tc:mysql://hostname/databasename?TC_INITFUNCTION=org.testcontainers.jdbc.JDBCDriverWithPoolTest::sampleInitFunction"; private final DataSource dataSource; @Parameterized.Parameters public static Iterable<Supplier<DataSource>> dataSourceSuppliers() { return asList( JDBCDriverWithPoolTest::getTomcatDataSourceWithDriverClassName, JDBCDriverWithPoolTest::getTomcatDataSource, JDBCDriverWithPoolTest::getHikariDataSourceWithDriverClassName, JDBCDriverWithPoolTest::getHikariDataSource, JDBCDriverWithPoolTest::getViburDataSourceWithDriverClassName, JDBCDriverWithPoolTest::getViburDataSource ); } public JDBCDriverWithPoolTest(Supplier<DataSource> dataSourceSupplier) { this.dataSource = dataSourceSupplier.get(); } private ExecutorService executorService = Executors.newFixedThreadPool(5); @Test public void testMySQLWithConnectionPoolUsingSameContainer() throws SQLException, InterruptedException { // Populate the database with some data in multiple threads, so that multiple connections from the pool will be used for (int i = 0; i < 100; i++) { executorService.submit(() -> { try { new QueryRunner(dataSource).insert("INSERT INTO my_counter (n) VALUES (5)", (ResultSetHandler<Object>) rs -> true); } catch (SQLException e) { e.printStackTrace(); } }); } // Complete population of the database executorService.shutdown(); executorService.awaitTermination(5, TimeUnit.MINUTES); // compare to expected results int count = new QueryRunner(dataSource).query("SELECT COUNT(1) FROM my_counter", rs -> { rs.next(); return rs.getInt(1); }); assertEquals("Reuse of a datasource points to the same DB container", 100, count); int sum = new QueryRunner(dataSource).query("SELECT SUM(n) FROM my_counter", rs -> { rs.next(); return rs.getInt(1); }); // 100 records * 5 = 500 expected assertEquals("Reuse of a datasource points to the same DB container", 500, sum); } private static DataSource getTomcatDataSourceWithDriverClassName() { PoolProperties poolProperties = new PoolProperties(); poolProperties.setUrl(URL + ";TEST=TOMCAT_WITH_CLASSNAME"); // append a dummy URL element to ensure different DB per test poolProperties.setValidationQuery("SELECT 1"); poolProperties.setMinIdle(3); poolProperties.setMaxActive(10); poolProperties.setDriverClassName(ContainerDatabaseDriver.class.getName()); return new org.apache.tomcat.jdbc.pool.DataSource(poolProperties); } private static DataSource getTomcatDataSource() { PoolProperties poolProperties = new PoolProperties(); poolProperties.setUrl(URL + ";TEST=TOMCAT"); // append a dummy URL element to ensure different DB per test poolProperties.setValidationQuery("SELECT 1"); poolProperties.setInitialSize(3); poolProperties.setMaxActive(10); return new org.apache.tomcat.jdbc.pool.DataSource(poolProperties); } private static HikariDataSource getHikariDataSourceWithDriverClassName() { HikariConfig hikariConfig = new HikariConfig(); hikariConfig.setJdbcUrl(URL + ";TEST=HIKARI_WITH_CLASSNAME"); // append a dummy URL element to ensure different DB per test hikariConfig.setConnectionTestQuery("SELECT 1"); hikariConfig.setMinimumIdle(3); hikariConfig.setMaximumPoolSize(10); hikariConfig.setDriverClassName(ContainerDatabaseDriver.class.getName()); return new HikariDataSource(hikariConfig); } private static HikariDataSource getHikariDataSource() { HikariConfig hikariConfig = new HikariConfig(); hikariConfig.setJdbcUrl(URL + ";TEST=HIKARI"); // append a dummy URL element to ensure different DB per test hikariConfig.setConnectionTestQuery("SELECT 1"); hikariConfig.setMinimumIdle(3); hikariConfig.setMaximumPoolSize(10); return new HikariDataSource(hikariConfig); } private static DataSource getViburDataSourceWithDriverClassName() { ViburDBCPDataSource ds = new ViburDBCPDataSource(); ds.setJdbcUrl(URL + ";TEST=VIBUR_WITH_CLASSNAME"); ds.setPoolInitialSize(3); ds.setPoolMaxSize(10); ds.setTestConnectionQuery("SELECT 1"); ds.setDriverClassName(ContainerDatabaseDriver.class.getName()); ds.start(); return ds; } private static DataSource getViburDataSource() { ViburDBCPDataSource ds = new ViburDBCPDataSource(); ds.setJdbcUrl(URL + ";TEST=VIBUR"); ds.setPoolInitialSize(3); ds.setPoolMaxSize(10); ds.setTestConnectionQuery("SELECT 1"); ds.start(); return ds; } @SuppressWarnings("SqlNoDataSourceInspection") public static void sampleInitFunction(Connection connection) throws SQLException { connection.createStatement().execute("CREATE TABLE bar (\n" + " foo VARCHAR(255)\n" + ");"); connection.createStatement().execute("INSERT INTO bar (foo) VALUES ('hello world');"); connection.createStatement().execute("CREATE TABLE my_counter (\n" + " n INT\n" + ");"); } }