001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.commons.dbcp;
019
020 import java.sql.Connection;
021 import java.sql.PreparedStatement;
022 import java.sql.ResultSet;
023 import java.sql.SQLException;
024 import java.sql.Statement;
025 import java.util.Hashtable;
026 import java.util.Stack;
027
028 import junit.framework.TestCase;
029
030 // XXX FIX ME XXX
031 // this class still needs some cleanup, but at least
032 // this consolidates most of the relevant test code
033 // in a fairly re-usable fashion
034 // XXX FIX ME XXX
035
036 /**
037 * Base test suite for DBCP pools.
038 *
039 * @author Rodney Waldhoff
040 * @author Sean C. Sullivan
041 * @author John McNally
042 * @author Dirk Verbeeck
043 * @version $Revision: 1023401 $ $Date: 2010-10-16 21:54:24 -0400 (Sat, 16 Oct 2010) $
044 */
045 public abstract class TestConnectionPool extends TestCase {
046 public TestConnectionPool(String testName) {
047 super(testName);
048 }
049
050 public void tearDown() throws Exception {
051 super.tearDown();
052 // Close any connections opened by the test
053 while (!connections.isEmpty()) {
054 Connection conn = (Connection) connections.pop();
055 try {
056 conn.close();
057 } catch (Exception ex) {
058 // ignore
059 } finally {
060 conn = null;
061 }
062 }
063 }
064
065 protected abstract Connection getConnection() throws Exception;
066
067 protected int getMaxActive() {
068 return 10;
069 }
070
071 protected long getMaxWait() {
072 return 100L;
073 }
074
075 /** Connections opened during the course of a test */
076 protected Stack connections = new Stack();
077
078 /** Acquire a connection and push it onto the connections stack */
079 protected Connection newConnection() throws Exception {
080 Connection connection = getConnection();
081 connections.push(connection);
082 return connection;
083 }
084
085 // ----------- Utility Methods ---------------------------------
086
087 protected String getUsername(Connection conn) throws SQLException {
088 Statement stmt = conn.createStatement();
089 ResultSet rs = stmt.executeQuery("select username");
090 if (rs.next()) {
091 return rs.getString(1);
092 }
093 return null;
094 }
095
096 // ----------- tests ---------------------------------
097
098 public void testClearWarnings() throws Exception {
099 Connection[] c = new Connection[getMaxActive()];
100 for (int i = 0; i < c.length; i++) {
101 c[i] = newConnection();
102 assertTrue(c[i] != null);
103
104 // generate SQLWarning on connection
105 c[i].prepareCall("warning");
106 }
107
108 for (int i = 0; i < c.length; i++) {
109 assertNotNull(c[i].getWarnings());
110 }
111
112 for (int i = 0; i < c.length; i++) {
113 c[i].close();
114 }
115
116 for (int i = 0; i < c.length; i++) {
117 c[i] = newConnection();
118 }
119
120 for (int i = 0; i < c.length; i++) {
121 // warnings should have been cleared by putting the connection back in the pool
122 assertNull(c[i].getWarnings());
123 }
124
125 for (int i = 0; i < c.length; i++) {
126 c[i].close();
127 }
128 }
129
130 public void testIsClosed() throws Exception {
131 for(int i=0;i<getMaxActive();i++) {
132 Connection conn = newConnection();
133 assertNotNull(conn);
134 assertTrue(!conn.isClosed());
135 PreparedStatement stmt = conn.prepareStatement("select * from dual");
136 assertNotNull(stmt);
137 ResultSet rset = stmt.executeQuery();
138 assertNotNull(rset);
139 assertTrue(rset.next());
140 rset.close();
141 stmt.close();
142 conn.close();
143 assertTrue(conn.isClosed());
144 }
145 }
146
147 /**
148 * Verify the close method can be called multiple times on a single connection without
149 * an exception being thrown.
150 */
151 public void testCanCloseConnectionTwice() throws Exception {
152 for (int i = 0; i < getMaxActive(); i++) { // loop to show we *can* close again once we've borrowed it from the pool again
153 Connection conn = newConnection();
154 assertNotNull(conn);
155 assertTrue(!conn.isClosed());
156 conn.close();
157 assertTrue(conn.isClosed());
158 conn.close();
159 assertTrue(conn.isClosed());
160 }
161 }
162
163 public void testCanCloseStatementTwice() throws Exception {
164 Connection conn = newConnection();
165 assertNotNull(conn);
166 assertTrue(!conn.isClosed());
167 for(int i=0;i<2;i++) { // loop to show we *can* close again once we've borrowed it from the pool again
168 Statement stmt = conn.createStatement();
169 assertNotNull(stmt);
170 assertFalse(isClosed(stmt));
171 stmt.close();
172 assertTrue(isClosed(stmt));
173 stmt.close();
174 assertTrue(isClosed(stmt));
175 stmt.close();
176 assertTrue(isClosed(stmt));
177 }
178 conn.close();
179 }
180
181 public void testCanClosePreparedStatementTwice() throws Exception {
182 Connection conn = newConnection();
183 assertNotNull(conn);
184 assertTrue(!conn.isClosed());
185 for(int i=0;i<2;i++) { // loop to show we *can* close again once we've borrowed it from the pool again
186 PreparedStatement stmt = conn.prepareStatement("select * from dual");
187 assertNotNull(stmt);
188 assertFalse(isClosed(stmt));
189 stmt.close();
190 assertTrue(isClosed(stmt));
191 stmt.close();
192 assertTrue(isClosed(stmt));
193 stmt.close();
194 assertTrue(isClosed(stmt));
195 }
196 conn.close();
197 }
198
199 public void testCanCloseCallableStatementTwice() throws Exception {
200 Connection conn = newConnection();
201 assertNotNull(conn);
202 assertTrue(!conn.isClosed());
203 for(int i=0;i<2;i++) { // loop to show we *can* close again once we've borrowed it from the pool again
204 PreparedStatement stmt = conn.prepareCall("select * from dual");
205 assertNotNull(stmt);
206 assertFalse(isClosed(stmt));
207 stmt.close();
208 assertTrue(isClosed(stmt));
209 stmt.close();
210 assertTrue(isClosed(stmt));
211 stmt.close();
212 assertTrue(isClosed(stmt));
213 }
214 conn.close();
215 }
216
217 public void testCanCloseResultSetTwice() throws Exception {
218 Connection conn = newConnection();
219 assertNotNull(conn);
220 assertTrue(!conn.isClosed());
221 for(int i=0;i<2;i++) { // loop to show we *can* close again once we've borrowed it from the pool again
222 PreparedStatement stmt = conn.prepareStatement("select * from dual");
223 assertNotNull(stmt);
224 ResultSet rset = stmt.executeQuery();
225 assertNotNull(rset);
226 assertFalse(isClosed(rset));
227 rset.close();
228 assertTrue(isClosed(rset));
229 rset.close();
230 assertTrue(isClosed(rset));
231 rset.close();
232 assertTrue(isClosed(rset));
233 }
234 conn.close();
235 }
236
237 public void testBackPointers() throws Exception {
238 // normal statement
239 Connection conn = newConnection();
240 assertBackPointers(conn, conn.createStatement());
241 conn = newConnection();
242 assertBackPointers(conn, conn.createStatement(0, 0));
243 conn = newConnection();
244 assertBackPointers(conn, conn.createStatement(0, 0, 0));
245
246 // prepared statement
247 conn = newConnection();
248 assertBackPointers(conn, conn.prepareStatement("select * from dual"));
249 conn = newConnection();
250 assertBackPointers(conn, conn.prepareStatement("select * from dual", 0));
251 conn = newConnection();
252 assertBackPointers(conn, conn.prepareStatement("select * from dual", 0, 0));
253 conn = newConnection();
254 assertBackPointers(conn, conn.prepareStatement("select * from dual", 0, 0, 0));
255 conn = newConnection();
256 assertBackPointers(conn, conn.prepareStatement("select * from dual", new int[0]));
257 conn = newConnection();
258 assertBackPointers(conn, conn.prepareStatement("select * from dual", new String[0]));
259
260 // callable statement
261 conn = newConnection();
262 assertBackPointers(conn, conn.prepareCall("select * from dual"));
263 conn = newConnection();
264 assertBackPointers(conn, conn.prepareCall("select * from dual", 0, 0));
265 conn = newConnection();
266 assertBackPointers(conn, conn.prepareCall("select * from dual", 0, 0, 0));
267 }
268
269 protected void assertBackPointers(Connection conn, Statement statement) throws SQLException {
270 assertFalse(conn.isClosed());
271 assertFalse(isClosed(statement));
272
273 assertSame("statement.getConnection() should return the exact same connection instance that was used to create the statement",
274 conn, statement.getConnection());
275
276 ResultSet resultSet = statement.getResultSet();
277 assertFalse(isClosed(resultSet));
278 assertSame("resultSet.getStatement() should return the exact same statement instance that was used to create the result set",
279 statement, resultSet.getStatement());
280
281 ResultSet executeResultSet = statement.executeQuery("select * from dual");
282 assertFalse(isClosed(executeResultSet));
283 assertSame("resultSet.getStatement() should return the exact same statement instance that was used to create the result set",
284 statement, executeResultSet.getStatement());
285
286 ResultSet keysResultSet = statement.getGeneratedKeys();
287 assertFalse(isClosed(keysResultSet));
288 assertSame("resultSet.getStatement() should return the exact same statement instance that was used to create the result set",
289 statement, keysResultSet.getStatement());
290
291 ResultSet preparedResultSet = null;
292 if (statement instanceof PreparedStatement) {
293 PreparedStatement preparedStatement = (PreparedStatement) statement;
294 preparedResultSet = preparedStatement.executeQuery();
295 assertFalse(isClosed(preparedResultSet));
296 assertSame("resultSet.getStatement() should return the exact same statement instance that was used to create the result set",
297 statement, preparedResultSet.getStatement());
298 }
299
300
301 resultSet.getStatement().getConnection().close();
302 assertTrue(conn.isClosed());
303 assertTrue(isClosed(statement));
304 assertTrue(isClosed(resultSet));
305 assertTrue(isClosed(executeResultSet));
306 assertTrue(isClosed(keysResultSet));
307 if (preparedResultSet != null) {
308 assertTrue(isClosed(preparedResultSet));
309 }
310 }
311
312 public void testSimple() throws Exception {
313 Connection conn = newConnection();
314 assertNotNull(conn);
315 PreparedStatement stmt = conn.prepareStatement("select * from dual");
316 assertNotNull(stmt);
317 ResultSet rset = stmt.executeQuery();
318 assertNotNull(rset);
319 assertTrue(rset.next());
320 rset.close();
321 stmt.close();
322 conn.close();
323 }
324
325 public void testRepeatedBorrowAndReturn() throws Exception {
326 for(int i=0;i<100;i++) {
327 Connection conn = newConnection();
328 assertNotNull(conn);
329 PreparedStatement stmt = conn.prepareStatement("select * from dual");
330 assertNotNull(stmt);
331 ResultSet rset = stmt.executeQuery();
332 assertNotNull(rset);
333 assertTrue(rset.next());
334 rset.close();
335 stmt.close();
336 conn.close();
337 }
338 }
339
340 public void testSimple2() throws Exception {
341 Connection conn = newConnection();
342 assertNotNull(conn);
343 {
344 PreparedStatement stmt = conn.prepareStatement("select * from dual");
345 assertNotNull(stmt);
346 ResultSet rset = stmt.executeQuery();
347 assertNotNull(rset);
348 assertTrue(rset.next());
349 rset.close();
350 stmt.close();
351 }
352 {
353 PreparedStatement stmt = conn.prepareStatement("select * from dual");
354 assertNotNull(stmt);
355 ResultSet rset = stmt.executeQuery();
356 assertNotNull(rset);
357 assertTrue(rset.next());
358 rset.close();
359 stmt.close();
360 }
361 conn.close();
362 try {
363 conn.createStatement();
364 fail("Can't use closed connections");
365 } catch(SQLException e) {
366 // expected
367 }
368
369 conn = newConnection();
370 assertNotNull(conn);
371 {
372 PreparedStatement stmt = conn.prepareStatement("select * from dual");
373 assertNotNull(stmt);
374 ResultSet rset = stmt.executeQuery();
375 assertNotNull(rset);
376 assertTrue(rset.next());
377 rset.close();
378 stmt.close();
379 }
380 {
381 PreparedStatement stmt = conn.prepareStatement("select * from dual");
382 assertNotNull(stmt);
383 ResultSet rset = stmt.executeQuery();
384 assertNotNull(rset);
385 assertTrue(rset.next());
386 rset.close();
387 stmt.close();
388 }
389 conn.close();
390 conn = null;
391 }
392
393 public void testPooling() throws Exception {
394 // Grab a maximal set of open connections from the pool
395 Connection[] c = new Connection[getMaxActive()];
396 Connection[] u = new Connection[getMaxActive()];
397 for (int i = 0; i < c.length; i++) {
398 c[i] = newConnection();
399 if (c[i] instanceof DelegatingConnection) {
400 u[i] = ((DelegatingConnection) c[i]).getInnermostDelegate();
401 } else {
402 for (int j = 0; j <= i; j++) {
403 c[j].close();
404 }
405 return; // skip this test
406 }
407 }
408 // Close connections one at a time and get new ones, making sure
409 // the new ones come from the pool
410 for (int i = 0; i < c.length; i++) {
411 c[i].close();
412 Connection con = newConnection();
413 Connection underCon =
414 ((DelegatingConnection) con).getInnermostDelegate();
415 assertTrue("Failed to get connection", underCon != null);
416 boolean found = false;
417 for (int j = 0; j < c.length; j++) {
418 if (underCon == u[j]) {
419 found = true;
420 break;
421 }
422 }
423 assertTrue("New connection not from pool", found);
424 con.close();
425 }
426 }
427
428 public void testAutoCommitBehavior() throws Exception {
429 Connection conn = newConnection();
430 assertNotNull(conn);
431 assertTrue(conn.getAutoCommit());
432 conn.setAutoCommit(false);
433 conn.close();
434
435 Connection conn2 = newConnection();
436 assertTrue( conn2.getAutoCommit() );
437
438 Connection conn3 = newConnection();
439 assertTrue( conn3.getAutoCommit() );
440
441 conn2.close();
442
443 conn3.close();
444 }
445
446 /** @see "http://issues.apache.org/bugzilla/show_bug.cgi?id=12400" */
447 public void testConnectionsAreDistinct() throws Exception {
448 Connection[] conn = new Connection[getMaxActive()];
449 for(int i=0;i<conn.length;i++) {
450 conn[i] = newConnection();
451 for(int j=0;j<i;j++) {
452 assertTrue(conn[j] != conn[i]);
453 assertTrue(!conn[j].equals(conn[i]));
454 }
455 }
456 for(int i=0;i<conn.length;i++) {
457 conn[i].close();
458 }
459 }
460
461
462 public void testOpening() throws Exception {
463 Connection[] c = new Connection[getMaxActive()];
464 // test that opening new connections is not closing previous
465 for (int i = 0; i < c.length; i++) {
466 c[i] = newConnection();
467 assertTrue(c[i] != null);
468 for (int j = 0; j <= i; j++) {
469 assertTrue(!c[j].isClosed());
470 }
471 }
472
473 for (int i = 0; i < c.length; i++) {
474 c[i].close();
475 }
476 }
477
478 public void testClosing() throws Exception {
479 Connection[] c = new Connection[getMaxActive()];
480 // open the maximum connections
481 for (int i = 0; i < c.length; i++) {
482 c[i] = newConnection();
483 }
484
485 // close one of the connections
486 c[0].close();
487 assertTrue(c[0].isClosed());
488
489 // get a new connection
490 c[0] = newConnection();
491
492 for (int i = 0; i < c.length; i++) {
493 c[i].close();
494 }
495 }
496
497 public void testMaxActive() throws Exception {
498 Connection[] c = new Connection[getMaxActive()];
499 for (int i = 0; i < c.length; i++) {
500 c[i] = newConnection();
501 assertTrue(c[i] != null);
502 }
503
504 try {
505 newConnection();
506 fail("Allowed to open more than DefaultMaxActive connections.");
507 } catch (java.sql.SQLException e) {
508 // should only be able to open 10 connections, so this test should
509 // throw an exception
510 }
511
512 for (int i = 0; i < c.length; i++) {
513 c[i].close();
514 }
515 }
516
517 /**
518 * DBCP-128: BasicDataSource.getConnection()
519 * Connections don't work as hashtable keys
520 */
521 public void testHashing() throws Exception {
522 Connection con = getConnection();
523 Hashtable hash = new Hashtable();
524 hash.put(con, "test");
525 assertEquals("test", hash.get(con));
526 assertTrue(hash.containsKey(con));
527 assertTrue(hash.contains("test"));
528 hash.clear();
529 con.close();
530 }
531
532 public void testThreaded() {
533 TestThread[] threads = new TestThread[getMaxActive()];
534 for(int i=0;i<threads.length;i++) {
535 threads[i] = new TestThread(50,50);
536 Thread t = new Thread(threads[i]);
537 t.start();
538 }
539 for(int i=0;i<threads.length;i++) {
540 while(!(threads[i]).complete()) {
541 try {
542 Thread.sleep(100L);
543 } catch(Exception e) {
544 // ignored
545 }
546 }
547 if(threads[i].failed()) {
548 fail();
549 }
550 }
551 }
552
553 class TestThread implements Runnable {
554 java.util.Random _random = new java.util.Random();
555 boolean _complete = false;
556 boolean _failed = false;
557 int _iter = 100;
558 int _delay = 50;
559
560 public TestThread() {
561 }
562
563 public TestThread(int iter) {
564 _iter = iter;
565 }
566
567 public TestThread(int iter, int delay) {
568 _iter = iter;
569 _delay = delay;
570 }
571
572 public boolean complete() {
573 return _complete;
574 }
575
576 public boolean failed() {
577 return _failed;
578 }
579
580 public void run() {
581 for(int i=0;i<_iter;i++) {
582 try {
583 Thread.sleep(_random.nextInt(_delay));
584 } catch(Exception e) {
585 // ignored
586 }
587 Connection conn = null;
588 PreparedStatement stmt = null;
589 ResultSet rset = null;
590 try {
591 conn = newConnection();
592 stmt = conn.prepareStatement("select 'literal', SYSDATE from dual");
593 rset = stmt.executeQuery();
594 try {
595 Thread.sleep(_random.nextInt(_delay));
596 } catch(Exception e) {
597 // ignored
598 }
599 } catch(Exception e) {
600 e.printStackTrace();
601 _failed = true;
602 _complete = true;
603 break;
604 } finally {
605 try { if (rset != null) rset.close(); } catch(Exception e) { }
606 try { if (stmt != null) stmt.close(); } catch(Exception e) { }
607 try { if (conn != null) conn.close(); } catch(Exception e) { }
608 }
609 }
610 _complete = true;
611 }
612 }
613
614 // Bugzilla Bug 24328: PooledConnectionImpl ignores resultsetType
615 // and Concurrency if statement pooling is not enabled
616 // http://issues.apache.org/bugzilla/show_bug.cgi?id=24328
617 public void testPrepareStatementOptions() throws Exception
618 {
619 Connection conn = newConnection();
620 assertNotNull(conn);
621 PreparedStatement stmt = conn.prepareStatement("select * from dual",
622 ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
623 assertNotNull(stmt);
624 ResultSet rset = stmt.executeQuery();
625 assertNotNull(rset);
626 assertTrue(rset.next());
627
628 assertEquals(ResultSet.TYPE_SCROLL_SENSITIVE, rset.getType());
629 assertEquals(ResultSet.CONCUR_UPDATABLE, rset.getConcurrency());
630
631 rset.close();
632 stmt.close();
633 conn.close();
634 }
635
636 // Bugzilla Bug 24966: NullPointer with Oracle 9 driver
637 // wrong order of passivate/close when a rset isn't closed
638 public void testNoRsetClose() throws Exception {
639 Connection conn = newConnection();
640 assertNotNull(conn);
641 PreparedStatement stmt = conn.prepareStatement("test");
642 assertNotNull(stmt);
643 ResultSet rset = stmt.getResultSet();
644 assertNotNull(rset);
645 // forget to close the resultset: rset.close();
646 stmt.close();
647 conn.close();
648 }
649
650 // Bugzilla Bug 26966: Connectionpool's connections always returns same
651 public void testHashCode() throws Exception {
652 Connection conn1 = newConnection();
653 assertNotNull(conn1);
654 Connection conn2 = newConnection();
655 assertNotNull(conn2);
656
657 assertTrue(conn1.hashCode() != conn2.hashCode());
658 }
659
660 protected boolean isClosed(Statement statement) {
661 try {
662 statement.getWarnings();
663 return false;
664 } catch (SQLException e) {
665 // getWarnings throws an exception if the statement is
666 // closed, but could throw an exception for other reasons
667 // in this case it is good enought to assume the statement
668 // is closed
669 return true;
670 }
671 }
672
673 protected boolean isClosed(ResultSet resultSet) {
674 try {
675 resultSet.getWarnings();
676 return false;
677 } catch (SQLException e) {
678 // getWarnings throws an exception if the statement is
679 // closed, but could throw an exception for other reasons
680 // in this case it is good enought to assume the result set
681 // is closed
682 return true;
683 }
684 }
685
686 private static final boolean DISPLAY_THREAD_DETAILS=
687 Boolean.valueOf(System.getProperty("TestConnectionPool.display.thread.details", "false")).booleanValue();
688 // To pass this to a Maven test, use:
689 // mvn test -DargLine="-DTestConnectionPool.display.thread.details=true"
690 // @see http://jira.codehaus.org/browse/SUREFIRE-121
691
692 /**
693 * Launches a group of 2 * getMaxActive() threads, each of which will attempt to obtain a connection
694 * from the pool, hold it for <holdTime> ms, and then return it to the pool. If <loopOnce> is false,
695 * threads will continue this process indefinitely. If <expectError> is true, exactly 1/2 of the
696 * threads are expected to either throw exceptions or fail to complete. If <expectError> is false,
697 * all threads are expected to complete successfully.
698 *
699 * @param holdTime time in ms that a thread holds a connection before returning it to the pool
700 * @param expectError whether or not an error is expected
701 * @param loopOnce whether threads should complete the borrow - hold - return cycle only once, or loop indefinitely
702 * @param maxWait passed in by client - has no impact on the test itself, but does get reported
703 *
704 * @throws Exception
705 */
706 protected void multipleThreads(final int holdTime, final boolean expectError, final boolean loopOnce, final long maxWait)
707 throws Exception {
708 long startTime = timeStamp();
709 final PoolTest[] pts = new PoolTest[2 * getMaxActive()];
710 // Catch Exception so we can stop all threads if one fails
711 ThreadGroup threadGroup = new ThreadGroup("foo") {
712 public void uncaughtException(Thread t, Throwable e) {
713 for (int i = 0; i < pts.length; i++) {
714 pts[i].stop();
715 }
716 }
717 };
718 // Create all the threads
719 for (int i = 0; i < pts.length; i++) {
720 pts[i] = new PoolTest(threadGroup, holdTime, expectError, loopOnce);
721 }
722 // Start all the threads
723 for (int i = 0; i < pts.length; i++) {
724 pts[i].start();
725 }
726
727 // Give all threads a chance to start and succeed
728 Thread.sleep(300L);
729
730 // Stop threads
731 for (int i = 0; i < pts.length; i++) {
732 pts[i].stop();
733 }
734
735 /*
736 * Wait for all threads to terminate.
737 * This is essential to ensure that all threads have a chance to update success[0]
738 * and to ensure that the variable is published correctly.
739 */
740 int done=0;
741 int failed=0;
742 int didNotRun = 0;
743 int loops=0;
744 for (int i = 0; i < pts.length; i++) {
745 final PoolTest poolTest = pts[i];
746 poolTest.thread.join();
747 loops += poolTest.loops;
748 final String state = poolTest.state;
749 if (DONE.equals(state)){
750 done++;
751 }
752 if (poolTest.loops == 0){
753 didNotRun++;
754 }
755 final Throwable thrown = poolTest.thrown;
756 if (thrown != null) {
757 failed++;
758 if (!expectError || !(thrown instanceof SQLException)){
759 System.out.println("Unexpected error: "+thrown.getMessage());
760 }
761 }
762 }
763
764 long time = timeStamp() - startTime;
765 System.out.println("Multithread test time = " + time
766 + " ms. Threads: " + pts.length
767 + ". Loops: " + loops
768 + ". Hold time: " + holdTime
769 + ". Maxwait: " + maxWait
770 + ". Done: " + done
771 + ". Did not run: " + didNotRun
772 + ". Failed: " + failed
773 + ". expectError: " + expectError
774 );
775 if (expectError) {
776 if (DISPLAY_THREAD_DETAILS || (pts.length/2 != failed)){
777 long offset = pts[0].created - 1000; // To reduce size of output numbers, but ensure they have 4 digits
778 System.out.println("Offset: "+offset);
779 for (int i = 0; i < pts.length; i++) {
780 PoolTest pt = pts[i];
781 System.out.println(
782 "Pre: " + (pt.preconnected-offset) // First, so can sort on this easily
783 + ". Post: " + (pt.postconnected != 0 ? Long.toString(pt.postconnected-offset): "-")
784 + ". Hash: " + pt.connHash
785 + ". Startup: " + (pt.started-pt.created)
786 + ". getConn(): " + (pt.connected != 0 ? Long.toString(pt.connected-pt.preconnected) : "-")
787 + ". Runtime: " + (pt.ended-pt.started)
788 + ". IDX: " + i
789 + ". Loops: " + pt.loops
790 + ". State: " + pt.state
791 + ". thrown: "+ pt.thrown
792 + "."
793 );
794 }
795 }
796 if (didNotRun > 0){
797 System.out.println("NOTE: some threads did not run the code: "+didNotRun);
798 }
799 // Perform initial sanity check:
800 assertTrue("Expected some of the threads to fail",failed > 0);
801 // Assume that threads that did not run would have timed out.
802 assertEquals("WARNING: Expected half the threads to fail",pts.length/2,failed+didNotRun);
803 } else {
804 assertEquals("Did not expect any threads to fail",0,failed);
805 }
806 }
807 private static int currentThreadCount = 0;
808
809 private static final String DONE = "Done";
810
811 protected class PoolTest implements Runnable {
812 /**
813 * The number of milliseconds to hold onto a database connection
814 */
815 private final int connHoldTime;
816
817 private volatile boolean isRun;
818
819 private String state; // No need to be volatile if it is read after the thread finishes
820
821 private final Thread thread;
822
823 private Throwable thrown;
824
825 // Debug for DBCP-318
826 private final long created; // When object was created
827 private long started; // when thread started
828 private long ended; // when thread ended
829 private long preconnected; // just before connect
830 private long connected; // when thread last connected
831 private long postconnected; // when thread released connection
832 private int loops = 0;
833 private int connHash = 0; // Connection identity hashCode (to see which one is reused)
834
835 private final boolean stopOnException; // If true, don't rethrow Exception
836
837 private final boolean loopOnce; // If true, don't repeat loop
838
839 public PoolTest(ThreadGroup threadGroup, int connHoldTime, boolean isStopOnException) {
840 this(threadGroup, connHoldTime, isStopOnException, false);
841 }
842
843 private PoolTest(ThreadGroup threadGroup, int connHoldTime, boolean isStopOnException, boolean once) {
844 this.loopOnce = once;
845 this.connHoldTime = connHoldTime;
846 stopOnException = isStopOnException;
847 isRun = true; // Must be done here so main thread is guaranteed to be able to set it false
848 thrown = null;
849 thread =
850 new Thread(threadGroup, this, "Thread+" + currentThreadCount++);
851 thread.setDaemon(false);
852 created = timeStamp();
853 }
854
855 public void start(){
856 thread.start();
857 }
858
859 public void run() {
860 started = timeStamp();
861 try {
862 while (isRun) {
863 loops++;
864 state = "Getting Connection";
865 preconnected = timeStamp();
866 Connection conn = getConnection();
867 connHash = System.identityHashCode(((DelegatingConnection)conn).getInnermostDelegate());
868 connected = timeStamp();
869 state = "Using Connection";
870 assertNotNull(conn);
871 PreparedStatement stmt =
872 conn.prepareStatement("select * from dual");
873 assertNotNull(stmt);
874 ResultSet rset = stmt.executeQuery();
875 assertNotNull(rset);
876 assertTrue(rset.next());
877 state = "Holding Connection";
878 Thread.sleep(connHoldTime);
879 state = "Closing ResultSet";
880 rset.close();
881 state = "Closing Statement";
882 stmt.close();
883 state = "Closing Connection";
884 conn.close();
885 postconnected = timeStamp();
886 state = "Closed";
887 if (loopOnce){
888 break; // Or could set isRun=false
889 }
890 }
891 state = DONE;
892 } catch (Throwable t) {
893 thrown = t;
894 if (!stopOnException) {
895 throw new RuntimeException();
896 }
897 } finally {
898 ended = timeStamp();
899 }
900 }
901
902 public void stop() {
903 isRun = false;
904 }
905
906 public Thread getThread() {
907 return thread;
908 }
909 }
910
911 long timeStamp() {
912 return System.currentTimeMillis();// JVM 1.5+ System.nanoTime() / 1000000;
913 }
914 }