This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch 7.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 8ba4f4603bbf523aa912a28287f7de8e5efc843d Author: Phil Steitz <phil.ste...@gmail.com> AuthorDate: Sat Oct 19 13:41:48 2019 -0700 Add TestBasicDataSource from Commons DBCP 1.5 branch, commit fa9c1eb250c76dd9af5ee23bf2ecd5351cad4e04. --- .../tomcat/dbcp/dbcp/TestBasicDataSource.java | 592 +++++++++++++++++++++ 1 file changed, 592 insertions(+) diff --git a/test/org/apache/tomcat/dbcp/dbcp/TestBasicDataSource.java b/test/org/apache/tomcat/dbcp/dbcp/TestBasicDataSource.java new file mode 100644 index 0000000..c98e4bd --- /dev/null +++ b/test/org/apache/tomcat/dbcp/dbcp/TestBasicDataSource.java @@ -0,0 +1,592 @@ +/* + * 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.commons.dbcp; + +import java.io.IOException; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Properties; + +import javax.sql.DataSource; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * TestSuite for BasicDataSource + * + * @author Dirk Verbeeck + * @version $Revision$ $Date$ + */ +public class TestBasicDataSource extends TestConnectionPool { + public TestBasicDataSource(String testName) { + super(testName); + } + + public static Test suite() { + return new TestSuite(TestBasicDataSource.class); + } + + protected Connection getConnection() throws Exception { + return ds.getConnection(); + } + + protected BasicDataSource ds = null; + private static final String CATALOG = "test catalog"; + + public void setUp() throws Exception { + super.setUp(); + ds = createDataSource(); + ds.setDriverClassName("org.apache.commons.dbcp.TesterDriver"); + ds.setUrl("jdbc:apache:commons:testdriver"); + ds.setMaxActive(getMaxActive()); + ds.setMaxWait(getMaxWait()); + ds.setDefaultAutoCommit(true); + ds.setDefaultReadOnly(false); + ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); + ds.setDefaultCatalog(CATALOG); + ds.setUsername("username"); + ds.setPassword("password"); + ds.setValidationQuery("SELECT DUMMY FROM DUAL"); + ds.setConnectionInitSqls(Arrays.asList(new String[] { "SELECT 1", "SELECT 2"})); + ds.setDriverClassLoader(new TesterClassLoader()); + } + + protected BasicDataSource createDataSource() throws Exception { + return new BasicDataSource(); + } + + public void tearDown() throws Exception { + super.tearDown(); + ds.close(); + ds = null; + } + + public void testClose() throws Exception { + ds.setAccessToUnderlyingConnectionAllowed(true); + + // active connection is held open when ds is closed + Connection activeConnection = getConnection(); + Connection rawActiveConnection = ((DelegatingConnection) activeConnection).getInnermostDelegate(); + assertFalse(activeConnection.isClosed()); + assertFalse(rawActiveConnection.isClosed()); + + // idle connection is in pool but closed + Connection idleConnection = getConnection(); + Connection rawIdleConnection = ((DelegatingConnection) idleConnection).getInnermostDelegate(); + assertFalse(idleConnection.isClosed()); + assertFalse(rawIdleConnection.isClosed()); + + // idle wrapper should be closed but raw connection should be open + idleConnection.close(); + assertTrue(idleConnection.isClosed()); + assertFalse(rawIdleConnection.isClosed()); + + ds.close(); + + // raw idle connection should now be closed + assertTrue(rawIdleConnection.isClosed()); + + // active connection should still be open + assertFalse(activeConnection.isClosed()); + assertFalse(rawActiveConnection.isClosed()); + + // now close the active connection + activeConnection.close(); + + // both wrapper and raw active connection should be closed + assertTrue(activeConnection.isClosed()); + assertTrue(rawActiveConnection.isClosed()); + + // Verify SQLException on getConnection after close + try { + getConnection(); + fail("Expecting SQLException"); + } catch (SQLException ex) { + // Expected + } + + // Redundant close is OK + ds.close(); + + } + + public void testSetProperties() throws Exception { + // normal + ds.setConnectionProperties("name1=value1;name2=value2;name3=value3"); + assertEquals(3, ds.connectionProperties.size()); + assertEquals("value1", ds.connectionProperties.getProperty("name1")); + assertEquals("value2", ds.connectionProperties.getProperty("name2")); + assertEquals("value3", ds.connectionProperties.getProperty("name3")); + + // make sure all properties are replaced + ds.setConnectionProperties("name1=value1;name2=value2"); + assertEquals(2, ds.connectionProperties.size()); + assertEquals("value1", ds.connectionProperties.getProperty("name1")); + assertEquals("value2", ds.connectionProperties.getProperty("name2")); + assertFalse(ds.connectionProperties.containsKey("name3")); + + // no value is empty string + ds.setConnectionProperties("name1=value1;name2"); + assertEquals(2, ds.connectionProperties.size()); + assertEquals("value1", ds.connectionProperties.getProperty("name1")); + assertEquals("", ds.connectionProperties.getProperty("name2")); + + // no value (with equals) is empty string + ds.setConnectionProperties("name1=value1;name2="); + assertEquals(2, ds.connectionProperties.size()); + assertEquals("value1", ds.connectionProperties.getProperty("name1")); + assertEquals("", ds.connectionProperties.getProperty("name2")); + + // single value + ds.setConnectionProperties("name1=value1"); + assertEquals(1, ds.connectionProperties.size()); + assertEquals("value1", ds.connectionProperties.getProperty("name1")); + + // single value with trailing ; + ds.setConnectionProperties("name1=value1;"); + assertEquals(1, ds.connectionProperties.size()); + assertEquals("value1", ds.connectionProperties.getProperty("name1")); + + // single value wit no value + ds.setConnectionProperties("name1"); + assertEquals(1, ds.connectionProperties.size()); + assertEquals("", ds.connectionProperties.getProperty("name1")); + + // null should throw a NullPointerException + try { + ds.setConnectionProperties(null); + fail("Expected NullPointerException"); + } catch (NullPointerException e) { + // expected + } + } + + public void testTransactionIsolationBehavior() throws Exception { + Connection conn = getConnection(); + assertNotNull(conn); + assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn.getTransactionIsolation()); + conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); + conn.close(); + + Connection conn2 = getConnection(); + assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn2.getTransactionIsolation()); + + Connection conn3 = getConnection(); + assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn3.getTransactionIsolation()); + + conn2.close(); + + conn3.close(); + } + + public void testPooling() throws Exception { + // this also needs access to the underlying connection + ds.setAccessToUnderlyingConnectionAllowed(true); + super.testPooling(); + } + + public void testNoAccessToUnderlyingConnectionAllowed() throws Exception { + // default: false + assertEquals(false, ds.isAccessToUnderlyingConnectionAllowed()); + + Connection conn = getConnection(); + Connection dconn = ((DelegatingConnection) conn).getDelegate(); + assertNull(dconn); + + dconn = ((DelegatingConnection) conn).getInnermostDelegate(); + assertNull(dconn); + } + + public void testAccessToUnderlyingConnectionAllowed() throws Exception { + ds.setAccessToUnderlyingConnectionAllowed(true); + assertEquals(true, ds.isAccessToUnderlyingConnectionAllowed()); + + Connection conn = getConnection(); + Connection dconn = ((DelegatingConnection) conn).getDelegate(); + assertNotNull(dconn); + + dconn = ((DelegatingConnection) conn).getInnermostDelegate(); + assertNotNull(dconn); + + assertTrue(dconn instanceof TesterConnection); + } + + public void testEmptyValidationQuery() throws Exception { + assertNotNull(ds.getValidationQuery()); + + ds.setValidationQuery(""); + assertNull(ds.getValidationQuery()); + + ds.setValidationQuery(" "); + assertNull(ds.getValidationQuery()); + } + + public void testInvalidValidationQuery() { + try { + ds.setValidationQuery("invalid"); + ds.getConnection(); + fail("expected SQLException"); + } + catch (SQLException e) { + if (e.toString().indexOf("invalid") < 0) { + fail("expected detailed error message"); + } + } + } + + public void testValidationQueryTimoutFail() { + ds.setTestOnBorrow(true); + ds.setValidationQueryTimeout(3); // Too fast for TesterStatement + try { + ds.getConnection(); + fail("expected SQLException"); + } catch (SQLException ex) { + if (ex.toString().indexOf("timeout") < 0) { + fail("expected timeout error message"); + } + } + } + + public void testValidationQueryTimeoutZero() throws Exception { + ds.setTestOnBorrow(true); + ds.setTestOnReturn(true); + ds.setValidationQueryTimeout(0); + Connection con = ds.getConnection(); + con.close(); + } + + public void testValidationQueryTimeoutNegative() throws Exception { + ds.setTestOnBorrow(true); + ds.setTestOnReturn(true); + ds.setValidationQueryTimeout(-1); + Connection con = ds.getConnection(); + con.close(); + } + + public void testValidationQueryTimeoutSucceed() throws Exception { + ds.setTestOnBorrow(true); + ds.setTestOnReturn(true); + ds.setValidationQueryTimeout(100); // Works for TesterStatement + Connection con = ds.getConnection(); + con.close(); + } + + public void testEmptyInitConnectionSql() throws Exception { + ds.setConnectionInitSqls(Arrays.asList(new String[]{"", " "})); + assertNotNull(ds.getConnectionInitSqls()); + assertEquals(0, ds.getConnectionInitSqls().size()); + + ds.setConnectionInitSqls(null); + assertNotNull(ds.getConnectionInitSqls()); + assertEquals(0, ds.getConnectionInitSqls().size()); + } + + public void testInvalidConnectionInitSql() { + try { + ds.setConnectionInitSqls(Arrays.asList(new String[]{"SELECT 1","invalid"})); + ds.getConnection(); + fail("expected SQLException"); + } + catch (SQLException e) { + if (e.toString().indexOf("invalid") < 0) { + fail("expected detailed error message"); + } + } + } + + public void testSetValidationTestProperties() { + // defaults + assertEquals(true, ds.getTestOnBorrow()); + assertEquals(false, ds.getTestOnReturn()); + assertEquals(false, ds.getTestWhileIdle()); + + ds.setTestOnBorrow(true); + ds.setTestOnReturn(true); + ds.setTestWhileIdle(true); + assertEquals(true, ds.getTestOnBorrow()); + assertEquals(true, ds.getTestOnReturn()); + assertEquals(true, ds.getTestWhileIdle()); + + ds.setTestOnBorrow(false); + ds.setTestOnReturn(false); + ds.setTestWhileIdle(false); + assertEquals(false, ds.getTestOnBorrow()); + assertEquals(false, ds.getTestOnReturn()); + assertEquals(false, ds.getTestWhileIdle()); + } + + public void testNoValidationQuery() throws Exception { + ds.setTestOnBorrow(true); + ds.setTestOnReturn(true); + ds.setTestWhileIdle(true); + ds.setValidationQuery(""); + + Connection conn = ds.getConnection(); + conn.close(); + + assertEquals(false, ds.getTestOnBorrow()); + assertEquals(false, ds.getTestOnReturn()); + assertEquals(false, ds.getTestWhileIdle()); + } + + public void testDefaultCatalog() throws Exception { + Connection[] c = new Connection[getMaxActive()]; + for (int i = 0; i < c.length; i++) { + c[i] = getConnection(); + assertTrue(c[i] != null); + assertEquals(CATALOG, c[i].getCatalog()); + } + + for (int i = 0; i < c.length; i++) { + c[i].setCatalog("error"); + c[i].close(); + } + + for (int i = 0; i < c.length; i++) { + c[i] = getConnection(); + assertTrue(c[i] != null); + assertEquals(CATALOG, c[i].getCatalog()); + } + + for (int i = 0; i < c.length; i++) { + c[i].close(); + } + } + + public void testSetAutoCommitTrueOnClose() throws Exception { + ds.setAccessToUnderlyingConnectionAllowed(true); + ds.setDefaultAutoCommit(false); + + Connection conn = getConnection(); + assertNotNull(conn); + assertEquals(false, conn.getAutoCommit()); + + Connection dconn = ((DelegatingConnection) conn).getInnermostDelegate(); + assertNotNull(dconn); + assertEquals(false, dconn.getAutoCommit()); + + conn.close(); + + assertEquals(true, dconn.getAutoCommit()); + } + + public void testInitialSize() throws Exception { + ds.setMaxActive(20); + ds.setMaxIdle(20); + ds.setInitialSize(10); + + Connection conn = getConnection(); + assertNotNull(conn); + conn.close(); + + assertEquals(0, ds.getNumActive()); + assertEquals(10, ds.getNumIdle()); + } + + // Bugzilla Bug 28251: Returning dead database connections to BasicDataSource + // isClosed() failure blocks returning a connection to the pool + public void testIsClosedFailure() throws SQLException { + ds.setAccessToUnderlyingConnectionAllowed(true); + Connection conn = ds.getConnection(); + assertNotNull(conn); + assertEquals(1, ds.getNumActive()); + + // set an IO failure causing the isClosed mathod to fail + TesterConnection tconn = (TesterConnection) ((DelegatingConnection)conn).getInnermostDelegate(); + tconn.setFailure(new IOException("network error")); + + try { + conn.close(); + fail("Expected SQLException"); + } + catch(SQLException ex) { } + + assertEquals(0, ds.getNumActive()); + } + + /** + * Bugzilla Bug 29054: + * The BasicDataSource.setTestOnReturn(boolean) is not carried through to + * the GenericObjectPool variable _testOnReturn. + */ + public void testPropertyTestOnReturn() throws Exception { + ds.setValidationQuery("select 1 from dual"); + ds.setTestOnBorrow(false); + ds.setTestWhileIdle(false); + ds.setTestOnReturn(true); + + Connection conn = ds.getConnection(); + assertNotNull(conn); + + assertEquals(false, ds.connectionPool.getTestOnBorrow()); + assertEquals(false, ds.connectionPool.getTestWhileIdle()); + assertEquals(true, ds.connectionPool.getTestOnReturn()); + } + + /** + * Bugzilla Bug 29055: AutoCommit and ReadOnly + * The DaffodilDB driver throws an SQLException if + * trying to commit or rollback a readOnly connection. + */ + public void testRollbackReadOnly() throws Exception { + ds.setDefaultReadOnly(true); + ds.setDefaultAutoCommit(false); + + Connection conn = ds.getConnection(); + assertNotNull(conn); + conn.close(); + } + + /** + * Bugzilla Bug 29832: Broken behaviour for BasicDataSource.setMaxActive(0) + * MaxActive == 0 should throw SQLException on getConnection. + * Results from Bug 29863 in commons-pool. + */ + public void testMaxActiveZero() throws Exception { + ds.setMaxActive(0); + + try { + Connection conn = ds.getConnection(); + assertNotNull(conn); + fail("SQLException expected"); + + } catch (SQLException e) { + // test OK + } + } + /** + * JIRA DBCP-93: If an SQLException occurs after the GenericObjectPool is + * initialized in createDataSource, the evictor task is not cleaned up. + */ + public void testCreateDataSourceCleanupThreads() throws Exception { + ds.close(); + ds = null; + ds = createDataSource(); + ds.setDriverClassName("org.apache.commons.dbcp.TesterDriver"); + ds.setUrl("jdbc:apache:commons:testdriver"); + ds.setMaxActive(getMaxActive()); + ds.setMaxWait(getMaxWait()); + ds.setDefaultAutoCommit(true); + ds.setDefaultReadOnly(false); + ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); + ds.setDefaultCatalog(CATALOG); + ds.setUsername("username"); + // Set timeBetweenEvictionRuns > 0, so evictor is created + ds.setTimeBetweenEvictionRunsMillis(100); + // Make password incorrect, so createDataSource will throw + ds.setPassword("wrong"); + ds.setValidationQuery("SELECT DUMMY FROM DUAL"); + int threadCount = Thread.activeCount(); + for (int i = 0; i < 10; i++) { + try { + ds.getConnection(); + } catch (SQLException ex) { + // ignore + } + } + // Allow one extra thread for JRockit compatibility + assertTrue(Thread.activeCount() <= threadCount + 1); + } + + /** + * JIRA DBCP-333: Check that a custom class loader is used. + * @throws Exception + */ + public void testDriverClassLoader() throws Exception { + getConnection(); + ClassLoader cl = ds.getDriverClassLoader(); + assertNotNull(cl); + assertTrue(cl instanceof TesterClassLoader); + assertTrue(((TesterClassLoader) cl).didLoad(ds.getDriverClassName())); + } + + /** + * JIRA: DBCP-342, DBCP-93 + * Verify that when errors occur during BasicDataSource initialization, GenericObjectPool + * Evictors are cleaned up. + */ + public void testCreateDataSourceCleanupEvictor() throws Exception { + ds.close(); + ds = null; + ds = createDataSource(); + ds.setDriverClassName("org.apache.commons.dbcp.TesterConnRequestCountDriver"); + ds.setUrl("jdbc:apache:commons:testerConnRequestCountDriver"); + ds.setValidationQuery("SELECT DUMMY FROM DUAL"); + ds.setUsername("username"); + + // Make password incorrect, so createDataSource will throw + ds.setPassword("wrong"); + // Set timeBetweenEvictionRuns > 0, so evictor will be created + ds.setTimeBetweenEvictionRunsMillis(100); + // Set min idle > 0, so evictor will try to make connection as many as idle count + ds.setMinIdle(2); + + // Prevent concurrent execution of threads executing test subclasses + synchronized (TesterConnRequestCountDriver.class) { + TesterConnRequestCountDriver.initConnRequestCount(); + + // user request 10 times + for (int i=0; i<10; i++) { + try { + @SuppressWarnings("unused") + DataSource ds2 = ds.createDataSource(); + } catch (SQLException e) { + // Ignore + } + } + + // sleep 1000ms. evictor will be invoked 10 times if running. + Thread.sleep(1000); + + // Make sure there have been no Evictor-generated requests (count should be 10, from requests above) + assertEquals(10, TesterConnRequestCountDriver.getConnectionRequestCount()); + } + + // make sure cleanup is complete + assertNull(ds.connectionPool); + } +} + +/** + * TesterDriver that keeps a static count of connection requests. + */ +class TesterConnRequestCountDriver extends TesterDriver { + protected static final String CONNECT_STRING = "jdbc:apache:commons:testerConnRequestCountDriver"; + private static int connectionRequestCount = 0; + + @Override + public Connection connect(String url, Properties info) throws SQLException { + connectionRequestCount++; + return super.connect(url, info); + } + + @Override + public boolean acceptsURL(String url) throws SQLException { + return CONNECT_STRING.startsWith(url); + } + + public static int getConnectionRequestCount() { + return connectionRequestCount; + } + + public static void initConnRequestCount() { + connectionRequestCount = 0; + } +}; --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org