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 9480651047c408bcf931612b68c8319145b31e89
Author: Phil Steitz <phil.ste...@gmail.com>
AuthorDate: Sat Oct 19 14:49:54 2019 -0700

    Add TestConnectionPool from Commons DBCP 1.5 branch, commit 
fa9c1eb250c76dd9af5ee23bf2ecd5351cad4e04.
---
 .../tomcat/dbcp/dbcp/TestConnectionPool.java       | 914 +++++++++++++++++++++
 1 file changed, 914 insertions(+)

diff --git a/test/org/apache/tomcat/dbcp/dbcp/TestConnectionPool.java 
b/test/org/apache/tomcat/dbcp/dbcp/TestConnectionPool.java
new file mode 100644
index 0000000..004a054
--- /dev/null
+++ b/test/org/apache/tomcat/dbcp/dbcp/TestConnectionPool.java
@@ -0,0 +1,914 @@
+/*
+ * 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.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Hashtable;
+import java.util.Stack;
+
+import junit.framework.TestCase;
+
+// XXX FIX ME XXX
+// this class still needs some cleanup, but at least
+// this consolidates most of the relevant test code
+// in a fairly re-usable fashion
+// XXX FIX ME XXX
+
+/**
+ * Base test suite for DBCP pools.
+ * 
+ * @author Rodney Waldhoff
+ * @author Sean C. Sullivan
+ * @author John McNally
+ * @author Dirk Verbeeck
+ * @version $Revision$ $Date$
+ */
+public abstract class TestConnectionPool extends TestCase {
+    public TestConnectionPool(String testName) {
+        super(testName);
+    }
+
+    public void tearDown() throws Exception {
+        super.tearDown();
+        // Close any connections opened by the test
+        while (!connections.isEmpty()) {
+            Connection conn = (Connection) connections.pop();
+            try {
+                conn.close();
+            } catch (Exception ex) { 
+                // ignore
+            } finally {
+                conn = null;
+            }
+        }
+    }
+
+    protected abstract Connection getConnection() throws Exception;
+    
+    protected int getMaxActive() {
+        return 10;
+    }
+    
+    protected long getMaxWait() {
+        return 100L;
+    }
+    
+    /** Connections opened during the course of a test */
+    protected Stack connections = new Stack();
+    
+    /** Acquire a connection and push it onto the connections stack */
+    protected Connection newConnection() throws Exception {
+        Connection connection = getConnection();
+        connections.push(connection);
+        return connection;
+    }
+
+    // ----------- Utility Methods --------------------------------- 
+
+    protected String getUsername(Connection conn) throws SQLException {
+        Statement stmt = conn.createStatement();
+        ResultSet rs = stmt.executeQuery("select username");
+        if (rs.next()) {
+            return rs.getString(1);
+        }
+        return null;
+    }
+
+    // ----------- tests --------------------------------- 
+
+    public void testClearWarnings() throws Exception {
+        Connection[] c = new Connection[getMaxActive()];
+        for (int i = 0; i < c.length; i++) {
+            c[i] = newConnection();
+            assertTrue(c[i] != null);
+            
+            // generate SQLWarning on connection
+            c[i].prepareCall("warning");
+        }
+
+        for (int i = 0; i < c.length; i++) {
+            assertNotNull(c[i].getWarnings());
+        }
+
+        for (int i = 0; i < c.length; i++) {
+            c[i].close();
+        }
+        
+        for (int i = 0; i < c.length; i++) {
+            c[i] = newConnection();
+        }        
+
+        for (int i = 0; i < c.length; i++) {
+            // warnings should have been cleared by putting the connection 
back in the pool
+            assertNull(c[i].getWarnings());
+        }
+
+        for (int i = 0; i < c.length; i++) {
+            c[i].close();
+        }
+    }
+
+    public void testIsClosed() throws Exception {
+        for(int i=0;i<getMaxActive();i++) {
+            Connection conn = newConnection();
+            assertNotNull(conn);
+            assertTrue(!conn.isClosed());
+            PreparedStatement stmt = conn.prepareStatement("select * from 
dual");
+            assertNotNull(stmt);
+            ResultSet rset = stmt.executeQuery();
+            assertNotNull(rset);
+            assertTrue(rset.next());
+            rset.close();
+            stmt.close();
+            conn.close();
+            assertTrue(conn.isClosed());
+        }
+    }
+
+    /**
+     * Verify the close method can be called multiple times on a single 
connection without
+     * an exception being thrown.
+     */
+    public void testCanCloseConnectionTwice() throws Exception {
+        for (int i = 0; i < getMaxActive(); i++) { // loop to show we *can* 
close again once we've borrowed it from the pool again
+            Connection conn = newConnection();
+            assertNotNull(conn);
+            assertTrue(!conn.isClosed());
+            conn.close();
+            assertTrue(conn.isClosed());
+            conn.close();
+            assertTrue(conn.isClosed());
+        }
+    }
+
+    public void testCanCloseStatementTwice() throws Exception {
+        Connection conn = newConnection();
+        assertNotNull(conn);
+        assertTrue(!conn.isClosed());
+        for(int i=0;i<2;i++) { // loop to show we *can* close again once we've 
borrowed it from the pool again
+            Statement stmt = conn.createStatement();
+            assertNotNull(stmt);
+            assertFalse(isClosed(stmt));
+            stmt.close();
+            assertTrue(isClosed(stmt));
+            stmt.close();
+            assertTrue(isClosed(stmt));
+            stmt.close();
+            assertTrue(isClosed(stmt));
+        }
+        conn.close();
+    }
+
+    public void testCanClosePreparedStatementTwice() throws Exception {
+        Connection conn = newConnection();
+        assertNotNull(conn);
+        assertTrue(!conn.isClosed());
+        for(int i=0;i<2;i++) { // loop to show we *can* close again once we've 
borrowed it from the pool again
+            PreparedStatement stmt = conn.prepareStatement("select * from 
dual");
+            assertNotNull(stmt);
+            assertFalse(isClosed(stmt));
+            stmt.close();
+            assertTrue(isClosed(stmt));
+            stmt.close();
+            assertTrue(isClosed(stmt));
+            stmt.close();
+            assertTrue(isClosed(stmt));
+        }
+        conn.close();
+    }
+
+    public void testCanCloseCallableStatementTwice() throws Exception {
+        Connection conn = newConnection();
+        assertNotNull(conn);
+        assertTrue(!conn.isClosed());
+        for(int i=0;i<2;i++) { // loop to show we *can* close again once we've 
borrowed it from the pool again
+            PreparedStatement stmt = conn.prepareCall("select * from dual");
+            assertNotNull(stmt);
+            assertFalse(isClosed(stmt));
+            stmt.close();
+            assertTrue(isClosed(stmt));
+            stmt.close();
+            assertTrue(isClosed(stmt));
+            stmt.close();
+            assertTrue(isClosed(stmt));
+        }
+        conn.close();
+    }
+
+    public void testCanCloseResultSetTwice() throws Exception {
+        Connection conn = newConnection();
+        assertNotNull(conn);
+        assertTrue(!conn.isClosed());
+        for(int i=0;i<2;i++) { // loop to show we *can* close again once we've 
borrowed it from the pool again
+            PreparedStatement stmt = conn.prepareStatement("select * from 
dual");
+            assertNotNull(stmt);
+            ResultSet rset = stmt.executeQuery();
+            assertNotNull(rset);
+            assertFalse(isClosed(rset));
+            rset.close();
+            assertTrue(isClosed(rset));
+            rset.close();
+            assertTrue(isClosed(rset));
+            rset.close();
+            assertTrue(isClosed(rset));
+        }
+        conn.close();
+    }
+
+    public void testBackPointers() throws Exception {
+        // normal statement
+        Connection conn = newConnection();
+        assertBackPointers(conn, conn.createStatement());
+        conn = newConnection();
+        assertBackPointers(conn, conn.createStatement(0, 0));
+        conn = newConnection();
+        assertBackPointers(conn, conn.createStatement(0, 0, 0));
+
+        // prepared statement
+        conn = newConnection();
+        assertBackPointers(conn, conn.prepareStatement("select * from dual"));
+        conn = newConnection();
+        assertBackPointers(conn, conn.prepareStatement("select * from dual", 
0));
+        conn = newConnection();
+        assertBackPointers(conn, conn.prepareStatement("select * from dual", 
0, 0));
+        conn = newConnection();
+        assertBackPointers(conn, conn.prepareStatement("select * from dual", 
0, 0, 0));
+        conn = newConnection();
+        assertBackPointers(conn, conn.prepareStatement("select * from dual", 
new int[0]));
+        conn = newConnection();
+        assertBackPointers(conn, conn.prepareStatement("select * from dual", 
new String[0]));
+
+        // callable statement
+        conn = newConnection();
+        assertBackPointers(conn, conn.prepareCall("select * from dual"));
+        conn = newConnection();
+        assertBackPointers(conn, conn.prepareCall("select * from dual", 0, 0));
+        conn = newConnection();
+        assertBackPointers(conn, conn.prepareCall("select * from dual", 0, 0, 
0));
+    }
+
+    protected void assertBackPointers(Connection conn, Statement statement) 
throws SQLException {
+        assertFalse(conn.isClosed());
+        assertFalse(isClosed(statement));
+
+        assertSame("statement.getConnection() should return the exact same 
connection instance that was used to create the statement",
+                conn, statement.getConnection());
+
+        ResultSet resultSet = statement.getResultSet();
+        assertFalse(isClosed(resultSet));
+        assertSame("resultSet.getStatement() should return the exact same 
statement instance that was used to create the result set",
+                statement, resultSet.getStatement());
+
+        ResultSet executeResultSet = statement.executeQuery("select * from 
dual");
+        assertFalse(isClosed(executeResultSet));
+        assertSame("resultSet.getStatement() should return the exact same 
statement instance that was used to create the result set",
+                statement, executeResultSet.getStatement());
+
+        ResultSet keysResultSet = statement.getGeneratedKeys();
+        assertFalse(isClosed(keysResultSet));
+        assertSame("resultSet.getStatement() should return the exact same 
statement instance that was used to create the result set",
+                statement, keysResultSet.getStatement());
+
+        ResultSet preparedResultSet = null;
+        if (statement instanceof PreparedStatement) {
+            PreparedStatement preparedStatement = (PreparedStatement) 
statement;
+            preparedResultSet = preparedStatement.executeQuery();
+            assertFalse(isClosed(preparedResultSet));
+            assertSame("resultSet.getStatement() should return the exact same 
statement instance that was used to create the result set",
+                    statement, preparedResultSet.getStatement());
+        }
+
+
+        resultSet.getStatement().getConnection().close();
+        assertTrue(conn.isClosed());
+        assertTrue(isClosed(statement));
+        assertTrue(isClosed(resultSet));
+        assertTrue(isClosed(executeResultSet));
+        assertTrue(isClosed(keysResultSet));
+        if (preparedResultSet != null) {
+            assertTrue(isClosed(preparedResultSet));
+        }
+    }
+
+    public void testSimple() throws Exception {
+        Connection conn = newConnection();
+        assertNotNull(conn);
+        PreparedStatement stmt = conn.prepareStatement("select * from dual");
+        assertNotNull(stmt);
+        ResultSet rset = stmt.executeQuery();
+        assertNotNull(rset);
+        assertTrue(rset.next());
+        rset.close();
+        stmt.close();
+        conn.close();
+    }
+
+    public void testRepeatedBorrowAndReturn() throws Exception {
+        for(int i=0;i<100;i++) {
+            Connection conn = newConnection();
+            assertNotNull(conn);
+            PreparedStatement stmt = conn.prepareStatement("select * from 
dual");
+            assertNotNull(stmt);
+            ResultSet rset = stmt.executeQuery();
+            assertNotNull(rset);
+            assertTrue(rset.next());
+            rset.close();
+            stmt.close();
+            conn.close();
+        }
+    }
+
+    public void testSimple2() throws Exception {
+        Connection conn = newConnection();
+        assertNotNull(conn);
+        {
+            PreparedStatement stmt = conn.prepareStatement("select * from 
dual");
+            assertNotNull(stmt);
+            ResultSet rset = stmt.executeQuery();
+            assertNotNull(rset);
+            assertTrue(rset.next());
+            rset.close();
+            stmt.close();
+        }
+        {
+            PreparedStatement stmt = conn.prepareStatement("select * from 
dual");
+            assertNotNull(stmt);
+            ResultSet rset = stmt.executeQuery();
+            assertNotNull(rset);
+            assertTrue(rset.next());
+            rset.close();
+            stmt.close();
+        }
+        conn.close();
+        try {
+            conn.createStatement();
+            fail("Can't use closed connections");
+        } catch(SQLException e) {
+            // expected
+        }
+
+        conn = newConnection();
+        assertNotNull(conn);
+        {
+            PreparedStatement stmt = conn.prepareStatement("select * from 
dual");
+            assertNotNull(stmt);
+            ResultSet rset = stmt.executeQuery();
+            assertNotNull(rset);
+            assertTrue(rset.next());
+            rset.close();
+            stmt.close();
+        }
+        {
+            PreparedStatement stmt = conn.prepareStatement("select * from 
dual");
+            assertNotNull(stmt);
+            ResultSet rset = stmt.executeQuery();
+            assertNotNull(rset);
+            assertTrue(rset.next());
+            rset.close();
+            stmt.close();
+        }
+        conn.close();
+        conn = null;
+    }
+
+    public void testPooling() throws Exception {  
+        // Grab a maximal set of open connections from the pool
+        Connection[] c = new Connection[getMaxActive()];
+        Connection[] u = new Connection[getMaxActive()];
+        for (int i = 0; i < c.length; i++) {
+            c[i] = newConnection();
+            if (c[i] instanceof DelegatingConnection) {
+                u[i] = ((DelegatingConnection) c[i]).getInnermostDelegate();
+            } else {
+                for (int j = 0; j <= i; j++) {
+                    c[j].close();
+                }
+                return; // skip this test   
+            }
+        }        
+        // Close connections one at a time and get new ones, making sure
+        // the new ones come from the pool
+        for (int i = 0; i < c.length; i++) {
+            c[i].close();
+            Connection con = newConnection();
+            Connection underCon = 
+                ((DelegatingConnection) con).getInnermostDelegate();
+            assertTrue("Failed to get connection", underCon != null);
+            boolean found = false;
+            for (int j = 0; j < c.length; j++) {
+                if (underCon == u[j]) {
+                    found = true;
+                    break;
+                }
+            }
+            assertTrue("New connection not from pool", found);
+            con.close();
+        }
+    }
+    
+    public void testAutoCommitBehavior() throws Exception {
+        Connection conn = newConnection();
+        assertNotNull(conn);
+        assertTrue(conn.getAutoCommit());
+        conn.setAutoCommit(false);
+        conn.close();
+        
+        Connection conn2 = newConnection();
+        assertTrue( conn2.getAutoCommit() );
+        
+        Connection conn3 = newConnection();
+        assertTrue( conn3.getAutoCommit() );
+
+        conn2.close();
+        
+        conn3.close();
+    }
+    
+    /** @see "http://issues.apache.org/bugzilla/show_bug.cgi?id=12400"; */
+    public void testConnectionsAreDistinct() throws Exception {
+        Connection[] conn = new Connection[getMaxActive()];
+        for(int i=0;i<conn.length;i++) {
+            conn[i] = newConnection();
+            for(int j=0;j<i;j++) {
+                assertTrue(conn[j] != conn[i]);
+                assertTrue(!conn[j].equals(conn[i]));
+            }
+        }
+        for(int i=0;i<conn.length;i++) {
+            conn[i].close();
+        }
+    }
+
+
+    public void testOpening() throws Exception {
+        Connection[] c = new Connection[getMaxActive()];
+        // test that opening new connections is not closing previous
+        for (int i = 0; i < c.length; i++) {
+            c[i] = newConnection();
+            assertTrue(c[i] != null);
+            for (int j = 0; j <= i; j++) {
+                assertTrue(!c[j].isClosed());
+            }
+        }
+
+        for (int i = 0; i < c.length; i++) {
+            c[i].close();
+        }
+    }
+
+    public void testClosing() throws Exception {
+        Connection[] c = new Connection[getMaxActive()];
+        // open the maximum connections
+        for (int i = 0; i < c.length; i++) {
+            c[i] = newConnection();
+        }
+
+        // close one of the connections
+        c[0].close();
+        assertTrue(c[0].isClosed());
+
+        // get a new connection
+        c[0] = newConnection();
+
+        for (int i = 0; i < c.length; i++) {
+            c[i].close();
+        }
+    }
+
+    public void testMaxActive() throws Exception {
+        Connection[] c = new Connection[getMaxActive()];
+        for (int i = 0; i < c.length; i++) {
+            c[i] = newConnection();
+            assertTrue(c[i] != null);
+        }
+
+        try {
+            newConnection();
+            fail("Allowed to open more than DefaultMaxActive connections.");
+        } catch (java.sql.SQLException e) {
+            // should only be able to open 10 connections, so this test should
+            // throw an exception
+        }
+
+        for (int i = 0; i < c.length; i++) {
+            c[i].close();
+        }
+    }
+    
+    /**
+     * DBCP-128: BasicDataSource.getConnection()
+     * Connections don't work as hashtable keys 
+     */
+    public void testHashing() throws Exception {
+        Connection con = getConnection();
+        Hashtable hash = new Hashtable();
+        hash.put(con, "test");
+        assertEquals("test", hash.get(con));
+        assertTrue(hash.containsKey(con));
+        assertTrue(hash.contains("test")); 
+        hash.clear();
+        con.close();
+    }
+
+    public void testThreaded() {
+        TestThread[] threads = new TestThread[getMaxActive()];
+        for(int i=0;i<threads.length;i++) {
+            threads[i] = new TestThread(50,50);
+            Thread t = new Thread(threads[i]);
+            t.start();
+        }
+        for(int i=0;i<threads.length;i++) {
+            while(!(threads[i]).complete()) {
+                try {
+                    Thread.sleep(100L);
+                } catch(Exception e) {
+                    // ignored
+                }
+            }
+            if(threads[i].failed()) {
+                fail("Thread failed: " + i);
+            }
+        }
+    }
+
+    class TestThread implements Runnable {
+        java.util.Random _random = new java.util.Random();
+        boolean _complete = false;
+        boolean _failed = false;
+        int _iter = 100;
+        int _delay = 50;
+
+        public TestThread() {
+        }
+
+        public TestThread(int iter) {
+            _iter = iter;
+        }
+
+        public TestThread(int iter, int delay) {
+            _iter = iter;
+            _delay = delay;
+        }
+
+        public boolean complete() {
+            return _complete;
+        }
+
+        public boolean failed() {
+            return _failed;
+        }
+
+        public void run() {
+            for(int i=0;i<_iter;i++) {
+                try {
+                    Thread.sleep(_random.nextInt(_delay));
+                } catch(Exception e) {
+                    // ignored
+                }
+                Connection conn = null;
+                PreparedStatement stmt = null;
+                ResultSet rset = null;
+                try {
+                    conn = newConnection();
+                    stmt = conn.prepareStatement("select 'literal', SYSDATE 
from dual");
+                    rset = stmt.executeQuery();
+                    try {
+                        Thread.sleep(_random.nextInt(_delay));
+                    } catch(Exception e) {
+                        // ignored
+                    }
+                } catch(Exception e) {
+                    e.printStackTrace();
+                    _failed = true;
+                    _complete = true;
+                    break;
+                } finally {
+                    try { if (rset != null) rset.close(); } catch(Exception e) 
{ }
+                    try { if (stmt != null) stmt.close(); } catch(Exception e) 
{ }
+                    try { if (conn != null) conn.close(); } catch(Exception e) 
{ }
+                }
+            }
+            _complete = true;
+        }
+    }
+
+    // Bugzilla Bug 24328: PooledConnectionImpl ignores resultsetType 
+    // and Concurrency if statement pooling is not enabled
+    // http://issues.apache.org/bugzilla/show_bug.cgi?id=24328
+    public void testPrepareStatementOptions() throws Exception 
+    {
+        Connection conn = newConnection();
+        assertNotNull(conn);
+        PreparedStatement stmt = conn.prepareStatement("select * from dual", 
+            ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
+        assertNotNull(stmt);
+        ResultSet rset = stmt.executeQuery();
+        assertNotNull(rset);
+        assertTrue(rset.next());
+        
+        assertEquals(ResultSet.TYPE_SCROLL_SENSITIVE, rset.getType());
+        assertEquals(ResultSet.CONCUR_UPDATABLE, rset.getConcurrency());
+        
+        rset.close();
+        stmt.close();
+        conn.close();
+    }
+
+    // Bugzilla Bug 24966: NullPointer with Oracle 9 driver
+    // wrong order of passivate/close when a rset isn't closed
+    public void testNoRsetClose() throws Exception {
+        Connection conn = newConnection();
+        assertNotNull(conn);
+        PreparedStatement stmt = conn.prepareStatement("test");
+        assertNotNull(stmt);
+        ResultSet rset = stmt.getResultSet();
+        assertNotNull(rset);
+        // forget to close the resultset: rset.close();
+        stmt.close();
+        conn.close();
+    }
+    
+    // Bugzilla Bug 26966: Connectionpool's connections always returns same
+    public void testHashCode() throws Exception {
+        Connection conn1 = newConnection();
+        assertNotNull(conn1);
+        Connection conn2 = newConnection();
+        assertNotNull(conn2);
+
+        assertTrue(conn1.hashCode() != conn2.hashCode());
+    }
+
+    protected boolean isClosed(Statement statement) {
+        try {
+            statement.getWarnings();
+            return false;
+        } catch (SQLException e) {
+            // getWarnings throws an exception if the statement is
+            // closed, but could throw an exception for other reasons
+            // in this case it is good enought to assume the statement
+            // is closed
+            return true;
+        }
+    }
+
+    protected boolean isClosed(ResultSet resultSet) {
+        try {
+            resultSet.getWarnings();
+            return false;
+        } catch (SQLException e) {
+            // getWarnings throws an exception if the statement is
+            // closed, but could throw an exception for other reasons
+            // in this case it is good enought to assume the result set
+            // is closed
+            return true;
+        }
+    }
+
+    private static final boolean DISPLAY_THREAD_DETAILS=
+        
Boolean.valueOf(System.getProperty("TestConnectionPool.display.thread.details", 
"false")).booleanValue();
+    // To pass this to a Maven test, use:
+    // mvn test -DargLine="-DTestConnectionPool.display.thread.details=true"
+    // @see http://jira.codehaus.org/browse/SUREFIRE-121
+    
+    /**
+     * Launches a group of 2 * getMaxActive() threads, each of which will 
attempt to obtain a connection
+     * from the pool, hold it for <holdTime> ms, and then return it to the 
pool.  If <loopOnce> is false,
+     * threads will continue this process indefinitely.  If <expectError> is 
true, exactly 1/2 of the
+     * threads are expected to either throw exceptions or fail to complete. If 
<expectError> is false,
+     * all threads are expected to complete successfully.
+     * 
+     * @param holdTime time in ms that a thread holds a connection before 
returning it to the pool
+     * @param expectError whether or not an error is expected
+     * @param loopOnce whether threads should complete the borrow - hold - 
return cycle only once, or loop indefinitely
+     * @param maxWait passed in by client - has no impact on the test itself, 
but does get reported
+     * 
+     * @throws Exception
+     */
+    protected void multipleThreads(final int holdTime, final boolean 
expectError, final boolean loopOnce, final long maxWait)
+            throws Exception {
+                long startTime = timeStamp();
+                final PoolTest[] pts = new PoolTest[2 * getMaxActive()];
+                // Catch Exception so we can stop all threads if one fails
+                ThreadGroup threadGroup = new ThreadGroup("foo") {
+                    public void uncaughtException(Thread t, Throwable e) {
+                        for (int i = 0; i < pts.length; i++) {
+                            pts[i].stop();
+                        }
+                    }
+                };
+                // Create all the threads
+                for (int i = 0; i < pts.length; i++) {
+                    pts[i] = new PoolTest(threadGroup, holdTime, expectError, 
loopOnce);    
+                }
+                // Start all the threads
+                for (int i = 0; i < pts.length; i++) {
+                    pts[i].start();    
+                }
+
+                // Give all threads a chance to start and succeed
+                Thread.sleep(300L);
+
+                // Stop threads
+                for (int i = 0; i < pts.length; i++) {
+                    pts[i].stop();
+                }   
+                
+                /*
+                 * Wait for all threads to terminate.
+                 * This is essential to ensure that all threads have a chance 
to update success[0]
+                 * and to ensure that the variable is published correctly.
+                 */
+                int done=0;
+                int failed=0;
+                int didNotRun = 0;
+                int loops=0;
+                for (int i = 0; i < pts.length; i++) {
+                    final PoolTest poolTest = pts[i];
+                    poolTest.thread.join();
+                    loops += poolTest.loops;
+                    final String state = poolTest.state;
+                    if (DONE.equals(state)){
+                        done++;
+                    }
+                    if (poolTest.loops == 0){
+                        didNotRun++;
+                    }
+                    final Throwable thrown = poolTest.thrown;
+                    if (thrown != null) {
+                        failed++;
+                        if (!expectError || !(thrown instanceof SQLException)){
+                            System.out.println("Unexpected error: 
"+thrown.getMessage());
+                        }
+                    }
+                }
+            
+                long time = timeStamp() - startTime;
+                System.out.println("Multithread test time = " + time
+                        + " ms. Threads: " + pts.length
+                        + ". Loops: " + loops
+                        + ". Hold time: " + holdTime
+                        + ". Maxwait: " + maxWait
+                        + ". Done: " + done
+                        + ". Did not run: " + didNotRun
+                        + ". Failed: " + failed
+                        + ". expectError: " + expectError
+                        );
+                if (expectError) {
+                    if (DISPLAY_THREAD_DETAILS || (pts.length/2 != failed)){
+                        long offset = pts[0].created - 1000; // To reduce size 
of output numbers, but ensure they have 4 digits
+                        System.out.println("Offset: "+offset);
+                        for (int i = 0; i < pts.length; i++) {
+                            PoolTest pt = pts[i];
+                            System.out.println(
+                                    "Pre: " + (pt.preconnected-offset) // 
First, so can sort on this easily
+                                    + ". Post: " + (pt.postconnected != 0 ? 
Long.toString(pt.postconnected-offset): "-")
+                                    + ". Hash: " + pt.connHash
+                                    + ". Startup: " + (pt.started-pt.created)
+                                    + ". getConn(): " + (pt.connected != 0 ? 
Long.toString(pt.connected-pt.preconnected) : "-")
+                                    + ". Runtime: " + (pt.ended-pt.started)
+                                    + ". IDX: " + i
+                                    + ". Loops: " + pt.loops
+                                    + ". State: " + pt.state
+                                    + ". thrown: "+ pt.thrown
+                                    + "."
+                                    );
+                        }                        
+                    }
+                    if (didNotRun > 0){
+                        System.out.println("NOTE: some threads did not run the 
code: "+didNotRun);
+                    }
+                    // Perform initial sanity check:
+                    assertTrue("Expected some of the threads to fail",failed > 
0);
+                    // Assume that threads that did not run would have timed 
out.
+                    assertEquals("WARNING: Expected half the threads to 
fail",pts.length/2,failed+didNotRun);
+                } else {
+                    assertEquals("Did not expect any threads to 
fail",0,failed);
+                }
+            }
+    private static int currentThreadCount = 0;
+
+    private static final String DONE = "Done";
+
+    protected class PoolTest implements Runnable {
+        /**
+         * The number of milliseconds to hold onto a database connection
+         */
+        private final int connHoldTime;
+
+        private volatile boolean isRun;
+
+        private String state; // No need to be volatile if it is read after 
the thread finishes
+
+        private final Thread thread;
+
+        private Throwable thrown;
+
+        // Debug for DBCP-318
+        private final long created; // When object was created
+        private long started; // when thread started
+        private long ended; // when thread ended
+        private long preconnected; // just before connect
+        private long connected; // when thread last connected
+        private long postconnected; // when thread released connection
+        private int loops = 0;
+        private int connHash = 0; // Connection identity hashCode (to see 
which one is reused)
+
+        private final boolean stopOnException; // If true, don't rethrow 
Exception
+        
+        private final boolean loopOnce; // If true, don't repeat loop
+
+        public PoolTest(ThreadGroup threadGroup, int connHoldTime, boolean 
isStopOnException) {
+            this(threadGroup, connHoldTime, isStopOnException, false);
+        }
+
+        private PoolTest(ThreadGroup threadGroup, int connHoldTime, boolean 
isStopOnException, boolean once) {
+            this.loopOnce = once;
+            this.connHoldTime = connHoldTime;
+            stopOnException = isStopOnException;
+            isRun = true; // Must be done here so main thread is guaranteed to 
be able to set it false
+            thrown = null;
+            thread =
+                new Thread(threadGroup, this, "Thread+" + 
currentThreadCount++);
+            thread.setDaemon(false);
+            created = timeStamp();
+        }
+
+        public void start(){
+            thread.start();
+        }
+
+        public void run() {
+            started = timeStamp();
+            try {
+                while (isRun) {
+                    loops++;
+                    state = "Getting Connection";
+                    preconnected = timeStamp();
+                    Connection conn = getConnection();
+                    connHash = 
System.identityHashCode(((DelegatingConnection)conn).getInnermostDelegate());
+                    connected = timeStamp();
+                    state = "Using Connection";
+                    assertNotNull(conn);
+                    PreparedStatement stmt =
+                        conn.prepareStatement("select * from dual");
+                    assertNotNull(stmt);
+                    ResultSet rset = stmt.executeQuery();
+                    assertNotNull(rset);
+                    assertTrue(rset.next());
+                    state = "Holding Connection";
+                    Thread.sleep(connHoldTime);
+                    state = "Closing ResultSet";
+                    rset.close();
+                    state = "Closing Statement";
+                    stmt.close();
+                    state = "Closing Connection";
+                    conn.close();
+                    postconnected = timeStamp();
+                    state = "Closed";
+                    if (loopOnce){
+                        break; // Or could set isRun=false
+                    }
+                }
+                state = DONE;
+            } catch (Throwable t) {
+                thrown = t;
+                if (!stopOnException) {
+                    throw new RuntimeException();
+                }
+            } finally {
+                ended = timeStamp();                
+            }
+        }
+
+        public void stop() {
+            isRun = false;
+        }
+
+        public Thread getThread() {
+            return thread;
+        }
+    }
+
+    long timeStamp() {
+        return System.currentTimeMillis();// JVM 1.5+ System.nanoTime() / 
1000000; 
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to