package org.springframework.cloud.service.relational;
import javax.sql.DataSource;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.cloud.ReflectionUtils;
import org.springframework.cloud.service.PooledServiceConnectorConfig.PoolConfig;
import org.springframework.cloud.service.ServiceConnectorConfig;
import org.springframework.cloud.service.common.MysqlServiceInfo;
import org.springframework.cloud.service.relational.DataSourceConfig.ConnectionConfig;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import static org.hamcrest.core.IsInstanceOf.instanceOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import static org.springframework.cloud.service.Util.hasClass;
import static org.springframework.cloud.service.relational.BasicDbcpPooledDataSourceCreator.DBCP2_BASIC_DATASOURCE;
import static org.springframework.cloud.service.relational.BasicDbcpPooledDataSourceCreator.DBCP_BASIC_DATASOURCE;
import static org.springframework.cloud.service.relational.HikariCpPooledDataSourceCreator.HIKARI_DATASOURCE;
import static org.springframework.cloud.service.relational.TomcatDbcpPooledDataSourceCreator.TOMCAT_7_DBCP;
import static org.springframework.cloud.service.relational.TomcatDbcpPooledDataSourceCreator.TOMCAT_8_DBCP;
import static org.springframework.cloud.service.relational.TomcatJdbcPooledDataSourceCreator.TOMCAT_JDBC_DATASOURCE;
public class PooledDataSourceCreatorsTest {
private static final int MIN_POOL_SIZE = 100;
private static final int MAX_POOL_SIZE = 200;
private static final int MAX_WAIT_TIME = 5;
private static final String CONNECTION_PROPERTIES_STRING = "useUnicode=true;characterEncoding=UTF-8";
private static final Properties CONNECTION_PROPERTIES = new Properties() {{
setProperty("useUnicode", "true");
setProperty("characterEncoding", "UTF-8");
}};
@Mock
private MysqlServiceInfo mockMysqlServiceInfo;
// Just to grab driver class name and validation query string
private MysqlDataSourceCreator mysqlDataSourceCreator = new MysqlDataSourceCreator();
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mockMysqlServiceInfo.getJdbcUrl()).thenReturn("jdbc:mysql://myuser:mypassword@10.20.30.40:3306/database-123");
}
@Test
public void pooledDataSourceCreationDefault() throws Exception {
PoolConfig poolConfig = new PoolConfig(MIN_POOL_SIZE, MAX_POOL_SIZE, MAX_WAIT_TIME);
ConnectionConfig connectionConfig = new ConnectionConfig(CONNECTION_PROPERTIES_STRING);
DataSourceConfig config = new DataSourceConfig(poolConfig, connectionConfig);
DataSource ds = createMysqlDataSource(config);
assertTomcatJdbcDataSource(ds);
}
@Test
public void pooledDataSourceCreationDbcp() throws Exception {
DataSource ds = createMysqlDataSourceWithPooledName("BasicDbcp");
assertBasicDbcpDataSource(ds);
ds = createMysqlDataSourceWithPooledName(BasicDbcpPooledDataSourceCreator.class.getSimpleName());
assertBasicDbcpDataSource(ds);
}
@Test
public void pooledDataSourceCreationTomcatDbcp() throws Exception {
DataSource ds = createMysqlDataSourceWithPooledName("TomcatDbcp");
assertTomcatDbcpDataSource(ds);
ds = createMysqlDataSourceWithPooledName(TomcatDbcpPooledDataSourceCreator.class.getSimpleName());
assertTomcatDbcpDataSource(ds);
}
@Test
public void pooledDataSourceCreationTomcatJdbc() throws Exception {
DataSource ds = createMysqlDataSourceWithPooledName("TomcatJdbc");
assertTomcatJdbcDataSource(ds);
ds = createMysqlDataSourceWithPooledName(TomcatJdbcPooledDataSourceCreator.class.getSimpleName());
assertTomcatJdbcDataSource(ds);
}
@Test
public void pooledDataSourceCreationHikariCP() throws Exception {
DataSource ds = createMysqlDataSourceWithPooledName("HikariCp");
assertHikariDataSource(ds);
ds = createMysqlDataSourceWithPooledName(HikariCpPooledDataSourceCreator.class.getSimpleName());
assertHikariDataSource(ds);
}
@Test
public void pooledDataSourceCreationInvalid() throws Exception {
DataSource ds = createMysqlDataSourceWithPooledName("Dummy");
assertThat(ds, instanceOf(org.springframework.jdbc.datasource.SimpleDriverDataSource.class));
}
private DataSource createMysqlDataSourceWithPooledName(String pooledDataSourceName) {
List<String> dataSourceNames = Collections.singletonList(pooledDataSourceName);
PoolConfig poolConfig =
new PoolConfig(MIN_POOL_SIZE, MAX_POOL_SIZE, MAX_WAIT_TIME);
ConnectionConfig connectionConfig = new ConnectionConfig(CONNECTION_PROPERTIES_STRING);
DataSourceConfig config = new DataSourceConfig(poolConfig, connectionConfig, dataSourceNames);
return createMysqlDataSource(config);
}
private DataSource createMysqlDataSource(ServiceConnectorConfig config) {
return mysqlDataSourceCreator.create(mockMysqlServiceInfo, config);
}
private void assertBasicDbcpDataSource(DataSource ds) throws ClassNotFoundException {
assertTrue(hasClass(DBCP2_BASIC_DATASOURCE) || hasClass(DBCP_BASIC_DATASOURCE));
if (hasClass(DBCP2_BASIC_DATASOURCE)) {
assertThat(ds, instanceOf(Class.forName(DBCP2_BASIC_DATASOURCE)));
assertEquals(MIN_POOL_SIZE, getIntValue(ds, "minIdle"));
assertEquals(MAX_POOL_SIZE, getIntValue(ds, "maxTotal"));
assertEquals(MAX_WAIT_TIME, getIntValue(ds, "maxWaitMillis"));
assertEquals(CONNECTION_PROPERTIES, getPropertiesValue(ds, "connectionProperties"));
}
if (hasClass(DBCP_BASIC_DATASOURCE) && !hasClass(DBCP2_BASIC_DATASOURCE)) {
assertThat(ds, instanceOf(Class.forName(DBCP_BASIC_DATASOURCE)));
assertEquals(MIN_POOL_SIZE, getIntValue(ds, "minIdle"));
assertEquals(MAX_POOL_SIZE, getIntValue(ds, "maxActive"));
assertEquals(MAX_WAIT_TIME, getIntValue(ds, "maxWait"));
assertEquals(CONNECTION_PROPERTIES, getPropertiesValue(ds, "connectionProperties"));
}
}
private void assertTomcatDbcpDataSource(DataSource ds) throws ClassNotFoundException {
assertTrue(hasClass(TOMCAT_7_DBCP) || hasClass(TOMCAT_8_DBCP));
if (hasClass(TOMCAT_7_DBCP)) {
assertThat(ds, instanceOf(Class.forName(TOMCAT_7_DBCP)));
assertEquals(MIN_POOL_SIZE, getIntValue(ds, "minIdle"));
assertEquals(MAX_WAIT_TIME, getIntValue(ds, "maxWait"));
assertEquals(CONNECTION_PROPERTIES, getPropertiesValue(ds, "connectionProperties"));
}
if (hasClass(TOMCAT_8_DBCP)) {
assertThat(ds, instanceOf(Class.forName(TOMCAT_8_DBCP)));
assertEquals(MIN_POOL_SIZE, getIntValue(ds, "minIdle"));
assertEquals(MAX_POOL_SIZE, getIntValue(ds, "maxTotal"));
assertEquals(MAX_WAIT_TIME, getIntValue(ds, "maxWaitMillis"));
assertEquals(CONNECTION_PROPERTIES, getPropertiesValue(ds, "connectionProperties"));
}
}
private void assertTomcatJdbcDataSource(DataSource ds) throws ClassNotFoundException {
assertThat(ds, instanceOf(Class.forName(TOMCAT_JDBC_DATASOURCE)));
assertEquals(MIN_POOL_SIZE, getIntValue(ds, "minIdle"));
assertEquals(MAX_WAIT_TIME, getIntValue(ds, "maxWait"));
// the results of setConnectionProperties are reflected by getDbProperties, not getConnectionProperties
assertEquals(CONNECTION_PROPERTIES, getPropertiesValue(ds, "dbProperties"));
}
private void assertHikariDataSource(DataSource ds) throws ClassNotFoundException {
assertThat(ds, instanceOf(Class.forName(HIKARI_DATASOURCE)));
assertEquals(MIN_POOL_SIZE, getIntValue(ds, "minimumIdle"));
assertEquals(MAX_POOL_SIZE, getIntValue(ds, "maximumPoolSize"));
}
private int getIntValue(Object target, String fieldName) {
return Integer.valueOf(getStringValue(target, fieldName));
}
private String getStringValue(Object target, String fieldName) {
return getValue(target, fieldName).toString();
}
private Properties getPropertiesValue(Object target, String fieldName) {
return (Properties) getValue(target, fieldName);
}
private Object getValue(Object target, String fieldName) {
Object value = ReflectionUtils.getValue(target, fieldName);
if (value == null) {
throw new IllegalArgumentException("Bad field name " + fieldName + " for target object " + target);
}
return value;
}
}