/*
* Copyright 2014-2015 Groupon, Inc
* Copyright 2014-2015 The Billing Project, LLC
*
* The Billing Project licenses this file to you 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.killbill.commons.jdbi.guice;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Collections;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.logging.Logger;
import javax.sql.DataSource;
import org.skife.config.ConfigurationObjectFactory;
import org.slf4j.LoggerFactory;
import org.testng.annotations.Test;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.zaxxer.hikari.HikariDataSource;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
public class TestDataSourceProvider {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(TestDataSourceProvider.class);
private static final String TEST_POOL_PREFIX = "test-pool";
@Test(groups = "fast")
public void testDataSourceProviderHikariCP() throws Exception {
DataSourceProvider.DatabaseType databaseType;
DaoConfig daoConfig;
String poolName;
DataSourceProvider dataSourceProvider;
// H2
databaseType = DataSourceProvider.DatabaseType.H2;
daoConfig = buildDaoConfig(DataSourceConnectionPoolingType.HIKARICP, databaseType);
poolName = TEST_POOL_PREFIX + "-0-" + databaseType;
dataSourceProvider = new DataSourceProvider(daoConfig, poolName);
assertTrue(dataSourceProvider.get() instanceof HikariDataSource);
// Generic
databaseType = DataSourceProvider.DatabaseType.GENERIC;
daoConfig = buildDaoConfig(DataSourceConnectionPoolingType.HIKARICP, databaseType);
poolName = TEST_POOL_PREFIX + "-0-" + databaseType;
dataSourceProvider = new DataSourceProvider(daoConfig, poolName);
assertTrue(dataSourceProvider.get() instanceof HikariDataSource);
}
@Test(groups = "fast")
public void testDataSourceProviderHikariCPPoolSizing() {
final DataSourceConnectionPoolingType poolingType = DataSourceConnectionPoolingType.HIKARICP;
final DataSourceProvider.DatabaseType databaseType = DataSourceProvider.DatabaseType.H2;
final Properties properties = defaultDaoConfigProperties(poolingType, databaseType);
properties.put("org.killbill.dao.minIdle", "20");
properties.put("org.killbill.dao.maxActive", "50");
final DaoConfig daoConfig = buildDaoConfig(properties);
final String poolName = TEST_POOL_PREFIX + "-1";
final DataSource dataSource = new DataSourceProvider(daoConfig, poolName).get();
assertTrue(dataSource instanceof HikariDataSource);
final HikariDataSource hikariDataSource = (HikariDataSource) dataSource;
assertEquals(50, hikariDataSource.getMaximumPoolSize());
assertEquals(20, hikariDataSource.getMinimumIdle());
}
@Test(groups = "fast")
public void testDataSourceProviderHikariCPSetsInitSQL() {
final DataSourceConnectionPoolingType poolingType = DataSourceConnectionPoolingType.HIKARICP;
final DataSourceProvider.DatabaseType databaseType = DataSourceProvider.DatabaseType.H2;
final boolean shouldUseMariaDB = true;
final Properties properties = defaultDaoConfigProperties(poolingType, databaseType);
properties.put("org.killbill.dao.connectionInitSql", "SELECT 42");
final DaoConfig daoConfig = buildDaoConfig(properties);
final String poolName = TEST_POOL_PREFIX + "-2";
final DataSource dataSource = new DataSourceProvider(daoConfig, poolName, shouldUseMariaDB).get();
assertTrue(dataSource instanceof HikariDataSource);
final HikariDataSource hikariDataSource = (HikariDataSource) dataSource;
assertEquals("SELECT 42", hikariDataSource.getConnectionInitSql());
}
@Test(groups = "fast")
public void testDataSourceProviderC3P0() throws Exception {
for (final DataSourceProvider.DatabaseType databaseType : DataSourceProvider.DatabaseType.values()) {
for (final boolean shouldUseMariaDB : new boolean[]{false, true}) {
final DaoConfig daoConfig = buildDaoConfig(DataSourceConnectionPoolingType.C3P0, databaseType);
final String poolName = TEST_POOL_PREFIX + "-" + databaseType + "_C3P0";
final DataSourceProvider dataSourceProvider = new DataSourceProvider(daoConfig, poolName, shouldUseMariaDB);
final DataSource dataSource = dataSourceProvider.get();
assertTrue(dataSource instanceof ComboPooledDataSource);
}
}
}
DaoConfig buildDaoConfig(final DataSourceConnectionPoolingType poolingType, final DataSourceProvider.DatabaseType databaseType) {
return buildDaoConfig(defaultDaoConfigProperties(poolingType, databaseType));
}
DaoConfig buildDaoConfig(final Properties properties) {
return new ConfigurationObjectFactory(properties).build(DaoConfig.class);
}
private Properties defaultDaoConfigProperties(final DataSourceConnectionPoolingType poolingType, final DataSourceProvider.DatabaseType databaseType) {
final Properties properties = new Properties();
properties.put("org.killbill.dao.poolingType", poolingType.toString());
if (DataSourceProvider.DatabaseType.MYSQL.equals(databaseType)) {
properties.put("org.killbill.dao.url", "jdbc:mysql://127.0.0.1:3306/killbill");
} else if (DataSourceProvider.DatabaseType.H2.equals(databaseType)) {
properties.put("org.killbill.dao.url", "jdbc:h2:file:/var/tmp/killbill;MODE=MYSQL;DB_CLOSE_DELAY=-1;MVCC=true;DB_CLOSE_ON_EXIT=FALSE");
} else {
properties.put("org.killbill.dao.url", "jdbc:test:@myhost:1521:orcl");
logger.info("GenericDriver.class.getName() = " + GenericDriver.class.getName());
properties.put("org.killbill.dao.driverClassName", GenericDriver.class.getName());
}
return properties;
}
public static final class GenericDriver implements Driver {
static {
try {
DriverManager.registerDriver(new GenericDriver());
} catch (final SQLException e) {
throw new RuntimeException("Could not register driver", e);
}
}
public Connection connect(final String url, final Properties info) throws SQLException {
logger.info(this + " connect " + url + " " + info);
return new ConnectionStub();
}
public boolean acceptsURL(final String url) throws SQLException {
return url.contains(":test:");
}
public DriverPropertyInfo[] getPropertyInfo(final String url, final Properties info) throws SQLException {
return new DriverPropertyInfo[0];
}
public int getMajorVersion() {
return 0;
}
public int getMinorVersion() {
return 0;
}
public boolean jdbcCompliant() {
return false;
}
public Logger getParentLogger() {
return null;
}
private class ConnectionStub implements Connection {
public boolean isValid(final int timeout) throws SQLException {
return !closed;
}
private boolean closed;
public void close() throws SQLException {
closed = true;
}
public boolean isClosed() throws SQLException {
return closed;
}
public DatabaseMetaData getMetaData() throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public void setReadOnly(final boolean readOnly) throws SQLException {
}
public boolean isReadOnly() throws SQLException {
return true;
}
public void setCatalog(final String catalog) throws SQLException {
}
public String getCatalog() throws SQLException {
return null;
}
public void setTransactionIsolation(final int level) throws SQLException {
}
public int getTransactionIsolation() throws SQLException {
return 0;
}
public Statement createStatement() throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public PreparedStatement prepareStatement(final String sql) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public CallableStatement prepareCall(final String sql) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public String nativeSQL(final String sql) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public void setAutoCommit(final boolean autoCommit) throws SQLException {
}
public boolean getAutoCommit() throws SQLException {
return false;
}
public void commit() throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public void rollback() throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public SQLWarning getWarnings() throws SQLException {
return null;
}
public void clearWarnings() throws SQLException {
}
public Statement createStatement(final int resultSetType, final int resultSetConcurrency) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public Map<String, Class<?>> getTypeMap() throws SQLException {
return Collections.emptyMap();
}
public void setTypeMap(final Map<String, Class<?>> map) throws SQLException {
}
public void setHoldability(final int holdability) throws SQLException {
}
public int getHoldability() throws SQLException {
return 0;
}
public Savepoint setSavepoint() throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public Savepoint setSavepoint(final String name) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public void rollback(final Savepoint savepoint) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public void releaseSavepoint(final Savepoint savepoint) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public Statement createStatement(final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public PreparedStatement prepareStatement(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public CallableStatement prepareCall(final String sql, final int resultSetType, final int resultSetConcurrency, final int resultSetHoldability) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public PreparedStatement prepareStatement(final String sql, final int autoGeneratedKeys) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public PreparedStatement prepareStatement(final String sql, final int[] columnIndexes) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public PreparedStatement prepareStatement(final String sql, final String[] columnNames) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public Clob createClob() throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public Blob createBlob() throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public NClob createNClob() throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public SQLXML createSQLXML() throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public void setClientInfo(final String name, final String value) throws SQLClientInfoException {
throw new UnsupportedOperationException("Not supported yet.");
}
public void setClientInfo(final Properties properties) throws SQLClientInfoException {
throw new UnsupportedOperationException("Not supported yet.");
}
public String getClientInfo(final String name) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public Properties getClientInfo() throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public Array createArrayOf(final String typeName, final Object[] elements) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public Struct createStruct(final String typeName, final Object[] attributes) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public void setSchema(final String schema) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public String getSchema() throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public void abort(final Executor executor) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public void setNetworkTimeout(final Executor executor, final int milliseconds) throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
public int getNetworkTimeout() throws SQLException {
throw new UnsupportedOperationException("Not supported yet.");
}
@SuppressWarnings("unchecked")
public <T> T unwrap(final Class<T> iface) throws SQLException {
return (T) this;
}
public boolean isWrapperFor(final Class<?> iface) throws SQLException {
return iface.isInstance(this);
}
}
}
}