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: 479137 $ $Date: 2006-11-25 08:51:48 -0700 (Sat, 25 Nov 2006) $
044: */
045: public abstract class TestConnectionPool extends TestCase {
046: public TestConnectionPool(String testName) {
047: super (testName);
048: }
049:
050: public void setUp() throws Exception {
051: super .setUp();
052: }
053:
054: public void tearDown() throws Exception {
055: super .tearDown();
056: // Close any connections opened by the test
057: while (!connections.isEmpty()) {
058: Connection conn = (Connection) connections.pop();
059: try {
060: conn.close();
061: } catch (Exception ex) {
062: // ignore
063: } finally {
064: conn = null;
065: }
066: }
067: }
068:
069: protected abstract Connection getConnection() throws Exception;
070:
071: protected int getMaxActive() {
072: return 10;
073: }
074:
075: protected long getMaxWait() {
076: return 100L;
077: }
078:
079: /** Connections opened during the course of a test */
080: protected Stack connections = new Stack();
081:
082: /** Acquire a connection and push it onto the connections stack */
083: protected Connection newConnection() throws Exception {
084: Connection connection = getConnection();
085: connections.push(connection);
086: return connection;
087: }
088:
089: // ----------- Utility Methods ---------------------------------
090:
091: protected String getUsername(Connection conn) throws SQLException {
092: Statement stmt = conn.createStatement();
093: ResultSet rs = stmt.executeQuery("select username");
094: if (rs.next()) {
095: return rs.getString(1);
096: }
097: return null;
098: }
099:
100: // ----------- tests ---------------------------------
101:
102: public void testClearWarnings() throws Exception {
103: Connection[] c = new Connection[getMaxActive()];
104: for (int i = 0; i < c.length; i++) {
105: c[i] = newConnection();
106: assertTrue(c[i] != null);
107:
108: // generate SQLWarning on connection
109: c[i].prepareCall("warning");
110: }
111:
112: for (int i = 0; i < c.length; i++) {
113: assertNotNull(c[i].getWarnings());
114: }
115:
116: for (int i = 0; i < c.length; i++) {
117: c[i].close();
118: }
119:
120: for (int i = 0; i < c.length; i++) {
121: c[i] = newConnection();
122: }
123:
124: for (int i = 0; i < c.length; i++) {
125: // warnings should have been cleared by putting the connection back in the pool
126: assertNull(c[i].getWarnings());
127: }
128:
129: for (int i = 0; i < c.length; i++) {
130: c[i].close();
131: }
132: }
133:
134: public void testIsClosed() throws Exception {
135: for (int i = 0; i < getMaxActive(); i++) {
136: Connection conn = newConnection();
137: assertTrue(null != conn);
138: assertTrue(!conn.isClosed());
139: PreparedStatement stmt = conn
140: .prepareStatement("select * from dual");
141: assertTrue(null != stmt);
142: ResultSet rset = stmt.executeQuery();
143: assertTrue(null != rset);
144: assertTrue(rset.next());
145: rset.close();
146: stmt.close();
147: conn.close();
148: assertTrue(conn.isClosed());
149: }
150: }
151:
152: public void testCantCloseConnectionTwice() throws Exception {
153: for (int i = 0; i < getMaxActive(); i++) { // loop to show we *can* close again once we've borrowed it from the pool again
154: Connection conn = newConnection();
155: assertTrue(null != conn);
156: assertTrue(!conn.isClosed());
157: conn.close();
158: assertTrue(conn.isClosed());
159: try {
160: conn.close();
161: fail("Expected SQLException on second attempt to close ("
162: + conn.getClass().getName() + ")");
163: } catch (SQLException e) {
164: // expected
165: }
166: assertTrue(conn.isClosed());
167: }
168: }
169:
170: public void testCantCloseStatementTwice() throws Exception {
171: Connection conn = newConnection();
172: assertTrue(null != conn);
173: assertTrue(!conn.isClosed());
174: for (int i = 0; i < 2; i++) { // loop to show we *can* close again once we've borrowed it from the pool again
175: PreparedStatement stmt = conn
176: .prepareStatement("select * from dual");
177: assertTrue(null != stmt);
178: stmt.close();
179: try {
180: stmt.close();
181: fail("Expected SQLException on second attempt to close ("
182: + stmt.getClass().getName() + ")");
183: } catch (SQLException e) {
184: // expected
185: }
186: }
187: conn.close();
188: }
189:
190: public void testSimple() throws Exception {
191: Connection conn = newConnection();
192: assertTrue(null != conn);
193: PreparedStatement stmt = conn
194: .prepareStatement("select * from dual");
195: assertTrue(null != stmt);
196: ResultSet rset = stmt.executeQuery();
197: assertTrue(null != rset);
198: assertTrue(rset.next());
199: rset.close();
200: stmt.close();
201: conn.close();
202: }
203:
204: public void testRepeatedBorrowAndReturn() throws Exception {
205: for (int i = 0; i < 100; i++) {
206: Connection conn = newConnection();
207: assertTrue(null != conn);
208: PreparedStatement stmt = conn
209: .prepareStatement("select * from dual");
210: assertTrue(null != stmt);
211: ResultSet rset = stmt.executeQuery();
212: assertTrue(null != rset);
213: assertTrue(rset.next());
214: rset.close();
215: stmt.close();
216: conn.close();
217: }
218: }
219:
220: public void testSimple2() throws Exception {
221: Connection conn = newConnection();
222: assertTrue(null != conn);
223: {
224: PreparedStatement stmt = conn
225: .prepareStatement("select * from dual");
226: assertTrue(null != stmt);
227: ResultSet rset = stmt.executeQuery();
228: assertTrue(null != rset);
229: assertTrue(rset.next());
230: rset.close();
231: stmt.close();
232: }
233: {
234: PreparedStatement stmt = conn
235: .prepareStatement("select * from dual");
236: assertTrue(null != stmt);
237: ResultSet rset = stmt.executeQuery();
238: assertTrue(null != rset);
239: assertTrue(rset.next());
240: rset.close();
241: stmt.close();
242: }
243: conn.close();
244: try {
245: conn.createStatement();
246: fail("Can't use closed connections");
247: } catch (SQLException e) {
248: ; // expected
249: }
250:
251: conn = newConnection();
252: assertTrue(null != conn);
253: {
254: PreparedStatement stmt = conn
255: .prepareStatement("select * from dual");
256: assertTrue(null != stmt);
257: ResultSet rset = stmt.executeQuery();
258: assertTrue(null != rset);
259: assertTrue(rset.next());
260: rset.close();
261: stmt.close();
262: }
263: {
264: PreparedStatement stmt = conn
265: .prepareStatement("select * from dual");
266: assertTrue(null != stmt);
267: ResultSet rset = stmt.executeQuery();
268: assertTrue(null != rset);
269: assertTrue(rset.next());
270: rset.close();
271: stmt.close();
272: }
273: conn.close();
274: conn = null;
275: }
276:
277: public void testPooling() throws Exception {
278: // Grab a maximal set of open connections from the pool
279: Connection[] c = new Connection[getMaxActive()];
280: Connection[] u = new Connection[getMaxActive()];
281: for (int i = 0; i < c.length; i++) {
282: c[i] = newConnection();
283: if (c[i] instanceof DelegatingConnection) {
284: u[i] = ((DelegatingConnection) c[i])
285: .getInnermostDelegate();
286: } else {
287: for (int j = 0; j <= i; j++) {
288: c[j].close();
289: }
290: return; // skip this test
291: }
292: }
293: // Close connections one at a time and get new ones, making sure
294: // the new ones come from the pool
295: for (int i = 0; i < c.length; i++) {
296: c[i].close();
297: Connection con = newConnection();
298: Connection underCon = ((DelegatingConnection) con)
299: .getInnermostDelegate();
300: assertTrue("Failed to get connection", underCon != null);
301: boolean found = false;
302: for (int j = 0; j < c.length; j++) {
303: if (underCon == u[j]) {
304: found = true;
305: break;
306: }
307: }
308: assertTrue("New connection not from pool", found);
309: con.close();
310: }
311: }
312:
313: public void testAutoCommitBehavior() throws Exception {
314: Connection conn = newConnection();
315: assertTrue(conn != null);
316: assertTrue(conn.getAutoCommit());
317: conn.setAutoCommit(false);
318: conn.close();
319:
320: Connection conn2 = newConnection();
321: assertTrue(conn2.getAutoCommit());
322:
323: Connection conn3 = newConnection();
324: assertTrue(conn3.getAutoCommit());
325:
326: conn2.close();
327:
328: conn3.close();
329: }
330:
331: /** @see http://issues.apache.org/bugzilla/show_bug.cgi?id=12400 */
332: public void testConnectionsAreDistinct() throws Exception {
333: Connection[] conn = new Connection[getMaxActive()];
334: for (int i = 0; i < conn.length; i++) {
335: conn[i] = newConnection();
336: for (int j = 0; j < i; j++) {
337: assertTrue(conn[j] != conn[i]);
338: assertTrue(!conn[j].equals(conn[i]));
339: }
340: }
341: for (int i = 0; i < conn.length; i++) {
342: conn[i].close();
343: }
344: }
345:
346: public void testOpening() throws Exception {
347: Connection[] c = new Connection[getMaxActive()];
348: // test that opening new connections is not closing previous
349: for (int i = 0; i < c.length; i++) {
350: c[i] = newConnection();
351: assertTrue(c[i] != null);
352: for (int j = 0; j <= i; j++) {
353: assertTrue(!c[j].isClosed());
354: }
355: }
356:
357: for (int i = 0; i < c.length; i++) {
358: c[i].close();
359: }
360: }
361:
362: public void testClosing() throws Exception {
363: Connection[] c = new Connection[getMaxActive()];
364: // open the maximum connections
365: for (int i = 0; i < c.length; i++) {
366: c[i] = newConnection();
367: }
368:
369: // close one of the connections
370: c[0].close();
371: assertTrue(c[0].isClosed());
372:
373: // get a new connection
374: c[0] = newConnection();
375:
376: for (int i = 0; i < c.length; i++) {
377: c[i].close();
378: }
379: }
380:
381: public void testMaxActive() throws Exception {
382: Connection[] c = new Connection[getMaxActive()];
383: for (int i = 0; i < c.length; i++) {
384: c[i] = newConnection();
385: assertTrue(c[i] != null);
386: }
387:
388: try {
389: newConnection();
390: fail("Allowed to open more than DefaultMaxActive connections.");
391: } catch (java.sql.SQLException e) {
392: // should only be able to open 10 connections, so this test should
393: // throw an exception
394: }
395:
396: for (int i = 0; i < c.length; i++) {
397: c[i].close();
398: }
399: }
400:
401: /**
402: * DBCP-128: BasicDataSource.getConnection()
403: * Connections don't work as hashtable keys
404: */
405: public void testHashing() throws Exception {
406: Connection con = getConnection();
407: Hashtable hash = new Hashtable();
408: hash.put(con, "test");
409: assertEquals("test", hash.get(con));
410: assertTrue(hash.containsKey(con));
411: assertTrue(hash.contains("test"));
412: hash.clear();
413: con.close();
414: }
415:
416: public void testThreaded() {
417: TestThread[] threads = new TestThread[getMaxActive()];
418: for (int i = 0; i < threads.length; i++) {
419: threads[i] = new TestThread(50, 50);
420: Thread t = new Thread(threads[i]);
421: t.start();
422: }
423: for (int i = 0; i < threads.length; i++) {
424: while (!(threads[i]).complete()) {
425: try {
426: Thread.sleep(100L);
427: } catch (Exception e) {
428: // ignored
429: }
430: }
431: if (threads[i].failed()) {
432: fail();
433: }
434: }
435: }
436:
437: class TestThread implements Runnable {
438: java.util.Random _random = new java.util.Random();
439: boolean _complete = false;
440: boolean _failed = false;
441: int _iter = 100;
442: int _delay = 50;
443:
444: public TestThread() {
445: }
446:
447: public TestThread(int iter) {
448: _iter = iter;
449: }
450:
451: public TestThread(int iter, int delay) {
452: _iter = iter;
453: _delay = delay;
454: }
455:
456: public boolean complete() {
457: return _complete;
458: }
459:
460: public boolean failed() {
461: return _failed;
462: }
463:
464: public void run() {
465: for (int i = 0; i < _iter; i++) {
466: try {
467: Thread.sleep((long) _random.nextInt(_delay));
468: } catch (Exception e) {
469: // ignored
470: }
471: Connection conn = null;
472: PreparedStatement stmt = null;
473: ResultSet rset = null;
474: try {
475: conn = newConnection();
476: stmt = conn
477: .prepareStatement("select 'literal', SYSDATE from dual");
478: rset = stmt.executeQuery();
479: try {
480: Thread.sleep((long) _random.nextInt(_delay));
481: } catch (Exception e) {
482: // ignored
483: }
484: } catch (Exception e) {
485: e.printStackTrace();
486: _failed = true;
487: _complete = true;
488: break;
489: } finally {
490: try {
491: rset.close();
492: } catch (Exception e) {
493: }
494: try {
495: stmt.close();
496: } catch (Exception e) {
497: }
498: try {
499: conn.close();
500: } catch (Exception e) {
501: }
502: }
503: }
504: _complete = true;
505: }
506: }
507:
508: // Bugzilla Bug 24328: PooledConnectionImpl ignores resultsetType
509: // and Concurrency if statement pooling is not enabled
510: // http://issues.apache.org/bugzilla/show_bug.cgi?id=24328
511: public void testPrepareStatementOptions() throws Exception {
512: Connection conn = newConnection();
513: assertTrue(null != conn);
514: PreparedStatement stmt = conn.prepareStatement(
515: "select * from dual", ResultSet.TYPE_SCROLL_SENSITIVE,
516: ResultSet.CONCUR_UPDATABLE);
517: assertTrue(null != stmt);
518: ResultSet rset = stmt.executeQuery();
519: assertTrue(null != rset);
520: assertTrue(rset.next());
521:
522: assertEquals(ResultSet.TYPE_SCROLL_SENSITIVE, rset.getType());
523: assertEquals(ResultSet.CONCUR_UPDATABLE, rset.getConcurrency());
524:
525: rset.close();
526: stmt.close();
527: conn.close();
528: }
529:
530: // Bugzilla Bug 24966: NullPointer with Oracle 9 driver
531: // wrong order of passivate/close when a rset isn't closed
532: public void testNoRsetClose() throws Exception {
533: Connection conn = newConnection();
534: assertNotNull(conn);
535: PreparedStatement stmt = conn.prepareStatement("test");
536: assertNotNull(stmt);
537: ResultSet rset = stmt.getResultSet();
538: assertNotNull(rset);
539: // forget to close the resultset: rset.close();
540: stmt.close();
541: conn.close();
542: }
543:
544: // Bugzilla Bug 26966: Connectionpool's connections always returns same
545: public void testHashCode() throws Exception {
546: Connection conn1 = newConnection();
547: assertNotNull(conn1);
548: Connection conn2 = newConnection();
549: assertNotNull(conn2);
550:
551: assertTrue(conn1.hashCode() != conn2.hashCode());
552: }
553: }
|