mirror of https://github.com/apache/nifi.git
NIFI-9673 Improved DBCP and HikariCP test reliability
- Configured tests to use random temporary directory - Added Derby shutdown handling and directory removal - Upgraded DBCPServiceTest to JUnit 5 - Added pool name to HikariCP Signed-off-by: Matthew Burgess <mattyb149@apache.org> This closes #5759
This commit is contained in:
parent
b8af44d81b
commit
9e06d13ad9
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF 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.apache.nifi.dbcp
|
||||
|
||||
import org.apache.commons.dbcp2.BasicDataSource
|
||||
import org.apache.nifi.reporting.InitializationException
|
||||
import org.apache.nifi.security.krb.KerberosKeytabUser
|
||||
import org.apache.nifi.security.krb.KerberosLoginException
|
||||
import org.apache.nifi.util.TestRunner
|
||||
import org.apache.nifi.util.TestRunners
|
||||
import org.junit.Assert
|
||||
import org.junit.BeforeClass
|
||||
import org.junit.Test
|
||||
|
||||
import java.sql.Connection
|
||||
import java.sql.SQLException
|
||||
|
||||
import static org.apache.nifi.dbcp.DBCPConnectionPool.*
|
||||
|
||||
/**
|
||||
* Groovy unit tests for the DBCPService module.
|
||||
*/
|
||||
class GroovyDBCPServiceTest {
|
||||
|
||||
final static String DB_LOCATION = "target/db"
|
||||
|
||||
@BeforeClass
|
||||
static void setup() {
|
||||
System.setProperty("derby.stream.error.file", "target/derby.log")
|
||||
}
|
||||
|
||||
/**
|
||||
* Test dynamic connection properties.
|
||||
*/
|
||||
@Test
|
||||
void testDynamicProperties() throws InitializationException, SQLException {
|
||||
final TestRunner runner = TestRunners.newTestRunner(TestProcessor)
|
||||
final DBCPConnectionPool service = new DBCPConnectionPool()
|
||||
runner.addControllerService("test-dynamic-properties", service)
|
||||
|
||||
// remove previous test database, if any
|
||||
final File dbLocation = new File(DB_LOCATION)
|
||||
dbLocation.deleteDir()
|
||||
|
||||
// set embedded Derby database connection url
|
||||
runner.setProperty(service, DATABASE_URL, "jdbc:derby:" + DB_LOCATION)
|
||||
runner.setProperty(service, DB_USER, "tester")
|
||||
runner.setProperty(service, DB_PASSWORD, "testerp")
|
||||
runner.setProperty(service, DB_DRIVERNAME, "org.apache.derby.jdbc.EmbeddedDriver")
|
||||
runner.setProperty(service, "create", "true")
|
||||
|
||||
runner.enableControllerService(service)
|
||||
|
||||
runner.assertValid(service)
|
||||
final DBCPService dbcpService = (DBCPService) runner.processContext.controllerServiceLookup.getControllerService("test-dynamic-properties")
|
||||
Assert.assertNotNull(dbcpService)
|
||||
|
||||
2.times {
|
||||
final Connection connection = dbcpService.getConnection()
|
||||
Assert.assertNotNull(connection)
|
||||
connection.close() // will return connection to pool
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = KerberosLoginException)
|
||||
void testDatasourceCloseSuccessWithKerberosUserLogoutException() {
|
||||
final DBCPConnectionPool dbcpConnectionPoolService = new DBCPConnectionPool()
|
||||
|
||||
def basicDataSource = [close: { -> }] as BasicDataSource
|
||||
dbcpConnectionPoolService.dataSource = basicDataSource
|
||||
def kerberosKeytabUser = new KerberosKeytabUser("bad@PRINCIPAL.COM", "fake.keytab") {
|
||||
@Override
|
||||
void logout() {
|
||||
throw new KerberosLoginException("fake logout exception")
|
||||
}
|
||||
}
|
||||
dbcpConnectionPoolService.kerberosUser = kerberosKeytabUser
|
||||
|
||||
dbcpConnectionPoolService.shutdown()
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = SQLException)
|
||||
void testDatasourceCloseExceptionWithKerberosUserLogoutSuccess() {
|
||||
final DBCPConnectionPool dbcpConnectionPoolService = new DBCPConnectionPool()
|
||||
|
||||
def basicDataSource = [
|
||||
close: { -> throw new SQLException("fake sql exception")
|
||||
}] as BasicDataSource
|
||||
dbcpConnectionPoolService.dataSource = basicDataSource
|
||||
def kerberosKeytabUser = new KerberosKeytabUser("bad@PRINCIPAL.COM", "fake.keytab") {
|
||||
@Override
|
||||
void logout() {
|
||||
}
|
||||
}
|
||||
dbcpConnectionPoolService.kerberosUser = kerberosKeytabUser
|
||||
|
||||
dbcpConnectionPoolService.shutdown()
|
||||
}
|
||||
|
||||
@Test(expected = SQLException)
|
||||
void testDatasourceCloseExceptionWithKerberosUserLogoutException() {
|
||||
final DBCPConnectionPool dbcpConnectionPoolService = new DBCPConnectionPool()
|
||||
|
||||
def basicDataSource = [
|
||||
close: { -> throw new SQLException("fake sql exception")
|
||||
}] as BasicDataSource
|
||||
dbcpConnectionPoolService.dataSource = basicDataSource
|
||||
def kerberosKeytabUser = new KerberosKeytabUser("bad@PRINCIPAL.COM", "fake.keytab") {
|
||||
@Override
|
||||
void logout() {
|
||||
throw new KerberosLoginException("fake logout exception")
|
||||
}
|
||||
}
|
||||
dbcpConnectionPoolService.kerberosUser = kerberosKeytabUser
|
||||
|
||||
dbcpConnectionPoolService.shutdown()
|
||||
}
|
||||
}
|
|
@ -21,57 +21,84 @@ import org.apache.nifi.kerberos.KerberosUserService;
|
|||
import org.apache.nifi.kerberos.MockKerberosCredentialsService;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.reporting.InitializationException;
|
||||
import org.apache.nifi.util.NoOpProcessor;
|
||||
import org.apache.nifi.util.TestRunner;
|
||||
import org.apache.nifi.util.TestRunners;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import org.apache.nifi.util.file.FileUtils;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class DBCPServiceTest {
|
||||
private static final String SERVICE_ID = DBCPConnectionPool.class.getName();
|
||||
|
||||
@Rule
|
||||
public TemporaryFolder tempFolder = new TemporaryFolder(new File("target"));
|
||||
private static final String DERBY_LOG_PROPERTY = "derby.stream.error.file";
|
||||
|
||||
private static final String DERBY_SHUTDOWN_STATE = "XJ015";
|
||||
|
||||
private TestRunner runner;
|
||||
|
||||
private File databaseDirectory;
|
||||
|
||||
private DBCPConnectionPool service;
|
||||
|
||||
@BeforeClass
|
||||
@BeforeAll
|
||||
public static void setDerbyLog() {
|
||||
System.setProperty("derby.stream.error.file", "target/derby.log");
|
||||
final File derbyLog = new File(getSystemTemporaryDirectory(), "derby.log");
|
||||
derbyLog.deleteOnExit();
|
||||
System.setProperty(DERBY_LOG_PROPERTY, derbyLog.getAbsolutePath());
|
||||
}
|
||||
|
||||
@Before
|
||||
@AfterAll
|
||||
public static void clearDerbyLog() {
|
||||
System.clearProperty(DERBY_LOG_PROPERTY);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setService() throws InitializationException {
|
||||
databaseDirectory = getEmptyDirectory();
|
||||
|
||||
service = new DBCPConnectionPool();
|
||||
runner = TestRunners.newTestRunner(TestProcessor.class);
|
||||
runner = TestRunners.newTestRunner(NoOpProcessor.class);
|
||||
runner.addControllerService(SERVICE_ID, service);
|
||||
|
||||
final String databasePath = new File(tempFolder.getRoot(), "db").getPath();
|
||||
final String databaseUrl = String.format("jdbc:derby:%s;create=true", databasePath);
|
||||
runner.setProperty(service, DBCPConnectionPool.DATABASE_URL, databaseUrl);
|
||||
final String url = String.format("jdbc:derby:%s;create=true", databaseDirectory);
|
||||
runner.setProperty(service, DBCPConnectionPool.DATABASE_URL, url);
|
||||
runner.setProperty(service, DBCPConnectionPool.DB_USER, String.class.getSimpleName());
|
||||
runner.setProperty(service, DBCPConnectionPool.DB_PASSWORD, String.class.getName());
|
||||
runner.setProperty(service, DBCPConnectionPool.DB_DRIVERNAME, "org.apache.derby.jdbc.EmbeddedDriver");
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void shutdown() throws IOException {
|
||||
if (databaseDirectory.exists()) {
|
||||
final SQLException exception = assertThrows(SQLException.class, () -> DriverManager.getConnection("jdbc:derby:;shutdown=true"));
|
||||
assertEquals(DERBY_SHUTDOWN_STATE, exception.getSQLState());
|
||||
FileUtils.deleteFile(databaseDirectory, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomValidateOfKerberosProperties() throws InitializationException {
|
||||
// direct principal + password and no kerberos services is valid
|
||||
|
@ -131,7 +158,7 @@ public class DBCPServiceTest {
|
|||
runner.assertValid(service);
|
||||
|
||||
try (final Connection connection = service.getConnection()) {
|
||||
Assert.assertNotNull("Connection not found", connection);
|
||||
assertNotNull(connection);
|
||||
|
||||
try (final Statement st = connection.createStatement()) {
|
||||
st.executeUpdate("create table restaurants(id integer, name varchar(20), city varchar(50))");
|
||||
|
@ -141,7 +168,7 @@ public class DBCPServiceTest {
|
|||
st.executeUpdate("insert into restaurants values (3, 'Prime Rib House', 'San Francisco')");
|
||||
|
||||
try (final ResultSet resultSet = st.executeQuery("select count(*) AS total_rows from restaurants")) {
|
||||
assertTrue("Result Set Row not found", resultSet.next());
|
||||
assertTrue(resultSet.next(), "Result Set Row not found");
|
||||
final int rows = resultSet.getInt(1);
|
||||
assertEquals(3, rows);
|
||||
}
|
||||
|
@ -171,7 +198,7 @@ public class DBCPServiceTest {
|
|||
}
|
||||
|
||||
runner.assertValid(service);
|
||||
Assert.assertThrows(ProcessException.class, service::getConnection);
|
||||
assertThrows(ProcessException.class, service::getConnection);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -181,10 +208,10 @@ public class DBCPServiceTest {
|
|||
runner.assertValid(service);
|
||||
|
||||
try (final Connection connection = service.getConnection()) {
|
||||
Assert.assertNotNull("First Connection not found", connection);
|
||||
assertNotNull(connection, "First Connection not found");
|
||||
}
|
||||
try (final Connection connection = service.getConnection()) {
|
||||
Assert.assertNotNull("Second Connection not found", connection);
|
||||
assertNotNull(connection, "Second Connection not found");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,8 +223,8 @@ public class DBCPServiceTest {
|
|||
runner.assertValid(service);
|
||||
|
||||
final Connection connection = service.getConnection();
|
||||
Assert.assertNotNull(connection);
|
||||
Assert.assertThrows(ProcessException.class, service::getConnection);
|
||||
assertNotNull(connection);
|
||||
assertThrows(ProcessException.class, service::getConnection);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -212,12 +239,12 @@ public class DBCPServiceTest {
|
|||
|
||||
runner.enableControllerService(service);
|
||||
|
||||
Assert.assertEquals(6, service.getDataSource().getMaxIdle());
|
||||
Assert.assertEquals(4, service.getDataSource().getMinIdle());
|
||||
Assert.assertEquals(1000, service.getDataSource().getMaxConnLifetimeMillis());
|
||||
Assert.assertEquals(1000, service.getDataSource().getTimeBetweenEvictionRunsMillis());
|
||||
Assert.assertEquals(1000, service.getDataSource().getMinEvictableIdleTimeMillis());
|
||||
Assert.assertEquals(1000, service.getDataSource().getSoftMinEvictableIdleTimeMillis());
|
||||
assertEquals(6, service.getDataSource().getMaxIdle());
|
||||
assertEquals(4, service.getDataSource().getMinIdle());
|
||||
assertEquals(1000, service.getDataSource().getMaxConnLifetimeMillis());
|
||||
assertEquals(1000, service.getDataSource().getTimeBetweenEvictionRunsMillis());
|
||||
assertEquals(1000, service.getDataSource().getMinEvictableIdleTimeMillis());
|
||||
assertEquals(1000, service.getDataSource().getSoftMinEvictableIdleTimeMillis());
|
||||
|
||||
service.getDataSource().close();
|
||||
}
|
||||
|
@ -249,27 +276,27 @@ public class DBCPServiceTest {
|
|||
connections.add(service.getConnection());
|
||||
}
|
||||
|
||||
Assert.assertEquals(6, service.getDataSource().getNumActive());
|
||||
assertEquals(6, service.getDataSource().getNumActive());
|
||||
|
||||
connections.get(0).close();
|
||||
Assert.assertEquals(5, service.getDataSource().getNumActive());
|
||||
Assert.assertEquals(1, service.getDataSource().getNumIdle());
|
||||
assertEquals(5, service.getDataSource().getNumActive());
|
||||
assertEquals(1, service.getDataSource().getNumIdle());
|
||||
|
||||
connections.get(1).close();
|
||||
connections.get(2).close();
|
||||
connections.get(3).close();
|
||||
//now at max idle
|
||||
Assert.assertEquals(2, service.getDataSource().getNumActive());
|
||||
Assert.assertEquals(4, service.getDataSource().getNumIdle());
|
||||
assertEquals(2, service.getDataSource().getNumActive());
|
||||
assertEquals(4, service.getDataSource().getNumIdle());
|
||||
|
||||
//now a connection should get closed for real so that numIdle does not exceed maxIdle
|
||||
connections.get(4).close();
|
||||
Assert.assertEquals(4, service.getDataSource().getNumIdle());
|
||||
Assert.assertEquals(1, service.getDataSource().getNumActive());
|
||||
assertEquals(4, service.getDataSource().getNumIdle());
|
||||
assertEquals(1, service.getDataSource().getNumActive());
|
||||
|
||||
connections.get(5).close();
|
||||
Assert.assertEquals(4, service.getDataSource().getNumIdle());
|
||||
Assert.assertEquals(0, service.getDataSource().getNumActive());
|
||||
assertEquals(4, service.getDataSource().getNumIdle());
|
||||
assertEquals(0, service.getDataSource().getNumActive());
|
||||
|
||||
service.getDataSource().close();
|
||||
}
|
||||
|
@ -304,4 +331,12 @@ public class DBCPServiceTest {
|
|||
return credentialsService;
|
||||
}
|
||||
|
||||
private File getEmptyDirectory() {
|
||||
final String randomDirectory = String.format("%s-%s", getClass().getSimpleName(), UUID.randomUUID());
|
||||
return Paths.get(getSystemTemporaryDirectory(), randomDirectory).toFile();
|
||||
}
|
||||
|
||||
private static String getSystemTemporaryDirectory() {
|
||||
return System.getProperty("java.io.tmpdir");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.apache.nifi.processor.FlowFileFilter;
|
|||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.nifi.reporting.InitializationException;
|
||||
import org.apache.nifi.util.MockFlowFile;
|
||||
import org.apache.nifi.util.NoOpProcessor;
|
||||
import org.apache.nifi.util.TestRunner;
|
||||
import org.apache.nifi.util.TestRunners;
|
||||
import org.junit.Before;
|
||||
|
@ -61,7 +62,7 @@ public class TestDBCPConnectionPoolLookup {
|
|||
|
||||
dbcpLookupService = new DBCPConnectionPoolLookup();
|
||||
|
||||
runner = TestRunners.newTestRunner(TestProcessor.class);
|
||||
runner = TestRunners.newTestRunner(NoOpProcessor.class);
|
||||
|
||||
final String dbcpServiceAIdentifier = "dbcp-a";
|
||||
runner.addControllerService(dbcpServiceAIdentifier, dbcpServiceA);
|
||||
|
@ -126,7 +127,7 @@ public class TestDBCPConnectionPoolLookup {
|
|||
@Test
|
||||
public void testCustomValidateAtLeaseOneServiceDefined() throws InitializationException {
|
||||
// enable lookup service with no services registered, verify not valid
|
||||
runner = TestRunners.newTestRunner(TestProcessor.class);
|
||||
runner = TestRunners.newTestRunner(NoOpProcessor.class);
|
||||
runner.addControllerService("dbcp-lookup", dbcpLookupService);
|
||||
runner.assertNotValid(dbcpLookupService);
|
||||
|
||||
|
@ -141,7 +142,7 @@ public class TestDBCPConnectionPoolLookup {
|
|||
|
||||
@Test
|
||||
public void testCustomValidateSelfReferenceNotAllowed() throws InitializationException {
|
||||
runner = TestRunners.newTestRunner(TestProcessor.class);
|
||||
runner = TestRunners.newTestRunner(NoOpProcessor.class);
|
||||
runner.addControllerService("dbcp-lookup", dbcpLookupService);
|
||||
runner.setProperty(dbcpLookupService, "dbcp-lookup", "dbcp-lookup");
|
||||
runner.assertNotValid(dbcpLookupService);
|
||||
|
@ -200,7 +201,7 @@ public class TestDBCPConnectionPoolLookup {
|
|||
*/
|
||||
private static class MockDBCPService extends AbstractControllerService implements DBCPService {
|
||||
|
||||
private MockConnection connection;
|
||||
private final MockConnection connection;
|
||||
|
||||
public MockDBCPService(MockConnection connection) {
|
||||
this.connection = connection;
|
||||
|
@ -225,5 +226,4 @@ public class TestDBCPConnectionPoolLookup {
|
|||
String getName();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF 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.apache.nifi.dbcp;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.nifi.components.PropertyDescriptor;
|
||||
import org.apache.nifi.processor.AbstractProcessor;
|
||||
import org.apache.nifi.processor.ProcessContext;
|
||||
import org.apache.nifi.processor.ProcessSession;
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
|
||||
public class TestProcessor extends AbstractProcessor {
|
||||
|
||||
@Override
|
||||
public void onTrigger(ProcessContext context, ProcessSession session) throws ProcessException {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
|
||||
List<PropertyDescriptor> propDescs = new ArrayList<>();
|
||||
propDescs.add(new PropertyDescriptor.Builder()
|
||||
.name("DBCPService test processor")
|
||||
.description("DBCPService test processor")
|
||||
.identifiesControllerService(DBCPService.class)
|
||||
.required(true)
|
||||
.build());
|
||||
return propDescs;
|
||||
}
|
||||
}
|
|
@ -297,7 +297,7 @@ public class HikariCPConnectionPool extends AbstractControllerService implements
|
|||
}
|
||||
});
|
||||
dataSource.setDataSourceProperties(properties);
|
||||
|
||||
dataSource.setPoolName(toString());
|
||||
}
|
||||
|
||||
private long extractMillisWithInfinite(PropertyValue prop) {
|
||||
|
|
|
@ -16,75 +16,82 @@
|
|||
*/
|
||||
package org.apache.nifi.dbcp;
|
||||
|
||||
import org.apache.nifi.processor.exception.ProcessException;
|
||||
import org.apache.derby.jdbc.EmbeddedDriver;
|
||||
import org.apache.nifi.reporting.InitializationException;
|
||||
import org.apache.nifi.util.NoOpProcessor;
|
||||
import org.apache.nifi.util.TestRunner;
|
||||
import org.apache.nifi.util.TestRunners;
|
||||
import org.apache.nifi.util.file.FileUtils;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
public class HikariCPConnectionPoolTest {
|
||||
private final static String DB_LOCATION = "target/db";
|
||||
private final static String GOOD_CS_NAME = "test-good1";
|
||||
private final static String BAD_CS_NAME = "test-bad1";
|
||||
private final static String EXHAUST_CS_NAME = "test-exhaust";
|
||||
private final static String SERVICE_ID = HikariCPConnectionPoolTest.class.getSimpleName();
|
||||
|
||||
private static String originalDerbyStreamErrorFile;
|
||||
private static final String DERBY_LOG_PROPERTY = "derby.stream.error.file";
|
||||
|
||||
private static final String DERBY_SHUTDOWN_STATE = "XJ015";
|
||||
|
||||
private TestRunner runner;
|
||||
|
||||
private File databaseDirectory;
|
||||
|
||||
@BeforeAll
|
||||
public static void setupBeforeClass() {
|
||||
originalDerbyStreamErrorFile = System.getProperty("derby.stream.error.file");
|
||||
System.setProperty("derby.stream.error.file", "target/derby.log");
|
||||
public static void setDerbyLog() {
|
||||
final File derbyLog = new File(getSystemTemporaryDirectory(), "derby.log");
|
||||
derbyLog.deleteOnExit();
|
||||
System.setProperty(DERBY_LOG_PROPERTY, derbyLog.getAbsolutePath());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void shutdownAfterClass() {
|
||||
if (originalDerbyStreamErrorFile != null) {
|
||||
System.setProperty("derby.stream.error.file", originalDerbyStreamErrorFile);
|
||||
}
|
||||
public static void clearDerbyLog() {
|
||||
System.clearProperty(DERBY_LOG_PROPERTY);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void setup() {
|
||||
// remove previous test database, if any
|
||||
final File dbLocation = new File(DB_LOCATION);
|
||||
dbLocation.delete();
|
||||
|
||||
runner = TestRunners.newTestRunner(NoOpProcessor.class);
|
||||
databaseDirectory = getEmptyDirectory();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void shutdown() throws IOException {
|
||||
if (databaseDirectory.exists()) {
|
||||
final SQLException exception = assertThrows(SQLException.class, () -> DriverManager.getConnection("jdbc:derby:;shutdown=true"));
|
||||
assertEquals(DERBY_SHUTDOWN_STATE, exception.getSQLState());
|
||||
FileUtils.deleteFile(databaseDirectory, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Missing property values.
|
||||
*/
|
||||
@Test
|
||||
public void testMissingPropertyValues() throws InitializationException {
|
||||
final HikariCPConnectionPool service = new HikariCPConnectionPool();
|
||||
final Map<String, String> properties = new HashMap<>();
|
||||
runner.addControllerService(BAD_CS_NAME, service, properties);
|
||||
runner.addControllerService(SERVICE_ID, service);
|
||||
runner.assertNotValid(service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Max wait set to -1
|
||||
*/
|
||||
@Test
|
||||
public void testMaxWait() throws InitializationException {
|
||||
public void testConnectionTimeoutZero() throws InitializationException {
|
||||
final HikariCPConnectionPool service = new HikariCPConnectionPool();
|
||||
runner.addControllerService(GOOD_CS_NAME, service);
|
||||
runner.addControllerService(SERVICE_ID, service);
|
||||
|
||||
setDerbyProperties(service);
|
||||
runner.setProperty(service, HikariCPConnectionPool.MAX_WAIT_TIME, "0 millis");
|
||||
|
@ -93,16 +100,12 @@ public class HikariCPConnectionPoolTest {
|
|||
runner.assertValid(service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks validity of idle limit and time settings including a default
|
||||
*/
|
||||
@Test
|
||||
public void testIdleConnectionsSettings() throws InitializationException {
|
||||
public void testMaxConnectionLifetime() throws InitializationException {
|
||||
final HikariCPConnectionPool service = new HikariCPConnectionPool();
|
||||
runner.addControllerService(GOOD_CS_NAME, service);
|
||||
runner.addControllerService(SERVICE_ID, service);
|
||||
|
||||
setDerbyProperties(service);
|
||||
runner.setProperty(service, HikariCPConnectionPool.MAX_WAIT_TIME, "0 millis");
|
||||
runner.setProperty(service, HikariCPConnectionPool.MAX_CONN_LIFETIME, "1 secs");
|
||||
|
||||
runner.enableControllerService(service);
|
||||
|
@ -112,25 +115,20 @@ public class HikariCPConnectionPoolTest {
|
|||
@Test
|
||||
public void testMinIdleCannotBeNegative() throws InitializationException {
|
||||
final HikariCPConnectionPool service = new HikariCPConnectionPool();
|
||||
runner.addControllerService(GOOD_CS_NAME, service);
|
||||
runner.addControllerService(SERVICE_ID, service);
|
||||
|
||||
setDerbyProperties(service);
|
||||
runner.setProperty(service, HikariCPConnectionPool.MAX_WAIT_TIME, "0 millis");
|
||||
runner.setProperty(service, HikariCPConnectionPool.MIN_IDLE, "-1");
|
||||
|
||||
runner.assertNotValid(service);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to ensure that settings have been passed down into the HikariCP
|
||||
*/
|
||||
@Test
|
||||
public void testIdleSettingsAreSet() throws InitializationException {
|
||||
final HikariCPConnectionPool service = new HikariCPConnectionPool();
|
||||
runner.addControllerService(GOOD_CS_NAME, service);
|
||||
runner.addControllerService(SERVICE_ID, service);
|
||||
|
||||
setDerbyProperties(service);
|
||||
runner.setProperty(service, HikariCPConnectionPool.MAX_WAIT_TIME, "0 millis");
|
||||
runner.setProperty(service, HikariCPConnectionPool.MIN_IDLE, "4");
|
||||
runner.setProperty(service, HikariCPConnectionPool.MAX_CONN_LIFETIME, "1 secs");
|
||||
|
||||
|
@ -142,81 +140,38 @@ public class HikariCPConnectionPoolTest {
|
|||
service.getDataSource().close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test database connection using Derby. Connect, create table, insert, select, drop table.
|
||||
*/
|
||||
@Test
|
||||
public void testCreateInsertSelect() throws InitializationException, SQLException {
|
||||
public void testGetConnection() throws SQLException, InitializationException {
|
||||
final HikariCPConnectionPool service = new HikariCPConnectionPool();
|
||||
runner.addControllerService(GOOD_CS_NAME, service);
|
||||
|
||||
runner.addControllerService(SERVICE_ID, service);
|
||||
setDerbyProperties(service);
|
||||
|
||||
runner.setProperty(service, HikariCPConnectionPool.MAX_TOTAL_CONNECTIONS, "2");
|
||||
runner.enableControllerService(service);
|
||||
|
||||
runner.assertValid(service);
|
||||
final DBCPService dbcpService = (DBCPService) runner.getProcessContext().getControllerServiceLookup().getControllerService(GOOD_CS_NAME);
|
||||
Assertions.assertNotNull(dbcpService);
|
||||
final Connection connection = dbcpService.getConnection();
|
||||
Assertions.assertNotNull(connection);
|
||||
|
||||
createInsertSelectDrop(connection);
|
||||
try (final Connection connection = service.getConnection()) {
|
||||
assertNotNull(connection, "First Connection not found");
|
||||
|
||||
connection.close(); // return to pool
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get database connection using Derby. Get many times, after a while pool should not contain any available connection and getConnection should fail.
|
||||
*/
|
||||
@Test
|
||||
public void testExhaustPool() throws InitializationException {
|
||||
final HikariCPConnectionPool service = new HikariCPConnectionPool();
|
||||
runner.addControllerService(EXHAUST_CS_NAME, service);
|
||||
|
||||
setDerbyProperties(service);
|
||||
|
||||
runner.enableControllerService(service);
|
||||
|
||||
runner.assertValid(service);
|
||||
Assertions.assertDoesNotThrow(() -> {
|
||||
runner.getProcessContext().getControllerServiceLookup().getControllerService(EXHAUST_CS_NAME);
|
||||
});
|
||||
final DBCPService dbcpService = (DBCPService) runner.getProcessContext().getControllerServiceLookup().getControllerService(EXHAUST_CS_NAME);
|
||||
Assertions.assertNotNull(dbcpService);
|
||||
|
||||
try {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
final Connection connection = dbcpService.getConnection();
|
||||
Assertions.assertNotNull(connection);
|
||||
try (final Connection secondConnection = service.getConnection()) {
|
||||
assertNotNull(secondConnection, "Second Connection not found");
|
||||
}
|
||||
Assertions.fail("Should have exhausted the pool and thrown a ProcessException");
|
||||
} catch (ProcessException pe) {
|
||||
// Do nothing, this is expected
|
||||
} catch (Throwable t) {
|
||||
Assertions.fail("Should have exhausted the pool and thrown a ProcessException but threw " + t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get database connection using Derby. Get many times, release immediately and getConnection should not fail.
|
||||
*/
|
||||
@Test
|
||||
public void testGetManyNormal() throws InitializationException, SQLException {
|
||||
public void testCreateInsertSelect() throws InitializationException, SQLException {
|
||||
final HikariCPConnectionPool service = new HikariCPConnectionPool();
|
||||
runner.addControllerService(EXHAUST_CS_NAME, service);
|
||||
runner.addControllerService(SERVICE_ID, service);
|
||||
|
||||
setDerbyProperties(service);
|
||||
|
||||
runner.enableControllerService(service);
|
||||
|
||||
runner.assertValid(service);
|
||||
final DBCPService dbcpService = (DBCPService) runner.getProcessContext().getControllerServiceLookup().getControllerService(EXHAUST_CS_NAME);
|
||||
Assertions.assertNotNull(dbcpService);
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
final Connection connection = dbcpService.getConnection();
|
||||
try (final Connection connection = service.getConnection()) {
|
||||
Assertions.assertNotNull(connection);
|
||||
connection.close(); // will return connection to pool
|
||||
createInsertSelectDrop(connection);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -249,9 +204,20 @@ public class HikariCPConnectionPoolTest {
|
|||
}
|
||||
|
||||
private void setDerbyProperties(final HikariCPConnectionPool service) {
|
||||
runner.setProperty(service, HikariCPConnectionPool.DATABASE_URL, "jdbc:derby:" + DB_LOCATION + ";create=true");
|
||||
runner.setProperty(service, HikariCPConnectionPool.DB_DRIVERNAME, "org.apache.derby.jdbc.EmbeddedDriver");
|
||||
runner.setProperty(service, HikariCPConnectionPool.DB_USER, "tester");
|
||||
runner.setProperty(service, HikariCPConnectionPool.DB_PASSWORD, "testerp");
|
||||
final String url = String.format("jdbc:derby:%s;create=true", databaseDirectory);
|
||||
runner.setProperty(service, HikariCPConnectionPool.DATABASE_URL, url);
|
||||
runner.setProperty(service, HikariCPConnectionPool.DB_DRIVERNAME, EmbeddedDriver.class.getName());
|
||||
runner.setProperty(service, HikariCPConnectionPool.MAX_WAIT_TIME, "5 s");
|
||||
runner.setProperty(service, HikariCPConnectionPool.DB_USER, String.class.getSimpleName());
|
||||
runner.setProperty(service, HikariCPConnectionPool.DB_PASSWORD, String.class.getName());
|
||||
}
|
||||
|
||||
private File getEmptyDirectory() {
|
||||
final String randomDirectory = String.format("%s-%s", getClass().getSimpleName(), UUID.randomUUID());
|
||||
return Paths.get(getSystemTemporaryDirectory(), randomDirectory).toFile();
|
||||
}
|
||||
|
||||
private static String getSystemTemporaryDirectory() {
|
||||
return System.getProperty("java.io.tmpdir");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue