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.datasources;
019:
020: import java.sql.Connection;
021: import java.sql.PreparedStatement;
022: import java.sql.ResultSet;
023: import java.sql.SQLException;
024:
025: import java.io.ByteArrayInputStream;
026: import java.io.ByteArrayOutputStream;
027: import java.io.ObjectInputStream;
028: import java.io.ObjectOutputStream;
029: import java.io.Serializable;
030:
031: import javax.sql.DataSource;
032:
033: import junit.framework.Test;
034: import junit.framework.TestSuite;
035:
036: import org.apache.commons.dbcp.TestConnectionPool;
037: import org.apache.commons.dbcp.TesterDriver;
038: import org.apache.commons.dbcp.cpdsadapter.DriverAdapterCPDS;
039:
040: /**
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 class TestPerUserPoolDataSource extends TestConnectionPool {
046: public TestPerUserPoolDataSource(String testName) {
047: super (testName);
048: }
049:
050: public static Test suite() {
051: return new TestSuite(TestPerUserPoolDataSource.class);
052: }
053:
054: protected Connection getConnection() throws Exception {
055: return ds.getConnection("foo", "bar");
056: }
057:
058: private DataSource ds;
059:
060: public void setUp() throws Exception {
061: DriverAdapterCPDS pcds = new DriverAdapterCPDS();
062: pcds.setDriver("org.apache.commons.dbcp.TesterDriver");
063: pcds.setUrl("jdbc:apache:commons:testdriver");
064: pcds.setUser("foo");
065: pcds.setPassword("bar");
066:
067: PerUserPoolDataSource tds = new PerUserPoolDataSource();
068: tds.setConnectionPoolDataSource(pcds);
069: tds.setDefaultMaxActive(getMaxActive());
070: tds.setDefaultMaxWait((int) (getMaxWait()));
071: tds.setPerUserMaxActive("foo", new Integer(getMaxActive()));
072: tds.setPerUserMaxWait("foo", new Integer((int) (getMaxWait())));
073: tds
074: .setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
075:
076: ds = tds;
077: }
078:
079: /**
080: * Switching 'u1 -> 'u2' and 'p1' -> 'p2' will
081: * exhibit the bug detailed in
082: * http://issues.apache.org/bugzilla/show_bug.cgi?id=18905
083: */
084: public void testIncorrectPassword() throws Exception {
085: try {
086: // Use bad password
087: ds.getConnection("u1", "zlsafjk").close();
088: fail("Able to retrieve connection with incorrect password");
089: } catch (SQLException e1) {
090: // should fail
091:
092: }
093:
094: // Use good password
095: ds.getConnection("u1", "p1").close();
096: try {
097: ds.getConnection("u1", "x").close();
098: fail("Able to retrieve connection with incorrect password");
099: } catch (SQLException e) {
100: if (!e.getMessage().startsWith(
101: "Given password did not match")) {
102: throw e;
103: }
104: // else the exception was expected
105: }
106:
107: // Make sure we can still use our good password.
108: ds.getConnection("u1", "p1").close();
109: }
110:
111: public void testSimple() throws Exception {
112: Connection conn = ds.getConnection();
113: assertTrue(null != conn);
114: PreparedStatement stmt = conn
115: .prepareStatement("select * from dual");
116: assertTrue(null != stmt);
117: ResultSet rset = stmt.executeQuery();
118: assertTrue(null != rset);
119: assertTrue(rset.next());
120: rset.close();
121: stmt.close();
122: conn.close();
123: }
124:
125: public void testSimpleWithUsername() throws Exception {
126: Connection conn = ds.getConnection("u1", "p1");
127: assertTrue(null != conn);
128: PreparedStatement stmt = conn
129: .prepareStatement("select * from dual");
130: assertTrue(null != stmt);
131: ResultSet rset = stmt.executeQuery();
132: assertTrue(null != rset);
133: assertTrue(rset.next());
134: rset.close();
135: stmt.close();
136: conn.close();
137: }
138:
139: public void testClosingWithUserName() throws Exception {
140: Connection[] c = new Connection[getMaxActive()];
141: // open the maximum connections
142: for (int i = 0; i < c.length; i++) {
143: c[i] = ds.getConnection("u1", "p1");
144: }
145:
146: // close one of the connections
147: c[0].close();
148: assertTrue(c[0].isClosed());
149: // get a new connection
150: c[0] = ds.getConnection("u1", "p1");
151:
152: for (int i = 0; i < c.length; i++) {
153: c[i].close();
154: }
155:
156: // open the maximum connections
157: for (int i = 0; i < c.length; i++) {
158: c[i] = ds.getConnection("u1", "p1");
159: }
160: for (int i = 0; i < c.length; i++) {
161: c[i].close();
162: }
163: }
164:
165: public void testSimple2() throws Exception {
166: Connection conn = ds.getConnection();
167: assertTrue(null != conn);
168:
169: PreparedStatement stmt = conn
170: .prepareStatement("select * from dual");
171: assertTrue(null != stmt);
172: ResultSet rset = stmt.executeQuery();
173: assertTrue(null != rset);
174: assertTrue(rset.next());
175: rset.close();
176: stmt.close();
177:
178: stmt = conn.prepareStatement("select * from dual");
179: assertTrue(null != stmt);
180: rset = stmt.executeQuery();
181: assertTrue(null != rset);
182: assertTrue(rset.next());
183: rset.close();
184: stmt.close();
185:
186: conn.close();
187: try {
188: conn.createStatement();
189: fail("Can't use closed connections");
190: } catch (SQLException e) {
191: // expected
192: }
193:
194: conn = ds.getConnection();
195: assertTrue(null != conn);
196:
197: stmt = conn.prepareStatement("select * from dual");
198: assertTrue(null != stmt);
199: rset = stmt.executeQuery();
200: assertTrue(null != rset);
201: assertTrue(rset.next());
202: rset.close();
203: stmt.close();
204:
205: stmt = conn.prepareStatement("select * from dual");
206: assertTrue(null != stmt);
207: rset = stmt.executeQuery();
208: assertTrue(null != rset);
209: assertTrue(rset.next());
210: rset.close();
211: stmt.close();
212:
213: conn.close();
214: conn = null;
215: }
216:
217: public void testOpening() throws Exception {
218: Connection[] c = new Connection[getMaxActive()];
219: // test that opening new connections is not closing previous
220: for (int i = 0; i < c.length; i++) {
221: c[i] = ds.getConnection();
222: assertTrue(c[i] != null);
223: for (int j = 0; j <= i; j++) {
224: assertTrue(!c[j].isClosed());
225: }
226: }
227:
228: for (int i = 0; i < c.length; i++) {
229: c[i].close();
230: }
231: }
232:
233: public void testClosing() throws Exception {
234: Connection[] c = new Connection[getMaxActive()];
235: // open the maximum connections
236: for (int i = 0; i < c.length; i++) {
237: c[i] = ds.getConnection();
238: }
239:
240: // close one of the connections
241: c[0].close();
242: assertTrue(c[0].isClosed());
243:
244: // get a new connection
245: c[0] = ds.getConnection();
246:
247: for (int i = 0; i < c.length; i++) {
248: c[i].close();
249: }
250: }
251:
252: public void testMaxActive() throws Exception {
253: Connection[] c = new Connection[getMaxActive()];
254: for (int i = 0; i < c.length; i++) {
255: c[i] = ds.getConnection();
256: assertTrue(c[i] != null);
257: }
258:
259: try {
260: ds.getConnection();
261: fail("Allowed to open more than DefaultMaxActive connections.");
262: } catch (java.sql.SQLException e) {
263: // should only be able to open 10 connections, so this test should
264: // throw an exception
265: }
266:
267: for (int i = 0; i < c.length; i++) {
268: c[i].close();
269: }
270: }
271:
272: public void testPerUserMethods() throws Exception {
273: PerUserPoolDataSource tds = (PerUserPoolDataSource) ds;
274:
275: // you need to set maxActive otherwise there is no accounting
276: tds.setPerUserMaxActive("u1", new Integer(5));
277: tds.setPerUserMaxActive("u2", new Integer(5));
278:
279: assertEquals(0, tds.getNumActive());
280: assertEquals(0, tds.getNumActive("u1", "p1"));
281: assertEquals(0, tds.getNumActive("u2", "p2"));
282: assertEquals(0, tds.getNumIdle());
283: assertEquals(0, tds.getNumIdle("u1", "p1"));
284: assertEquals(0, tds.getNumIdle("u2", "p2"));
285:
286: Connection conn = tds.getConnection();
287: assertNotNull(conn);
288: assertEquals(1, tds.getNumActive());
289: assertEquals(0, tds.getNumActive("u1", "p1"));
290: assertEquals(0, tds.getNumActive("u2", "p2"));
291: assertEquals(0, tds.getNumIdle());
292: assertEquals(0, tds.getNumIdle("u1", "p1"));
293: assertEquals(0, tds.getNumIdle("u2", "p2"));
294:
295: conn.close();
296: assertEquals(0, tds.getNumActive());
297: assertEquals(0, tds.getNumActive("u1", "p1"));
298: assertEquals(0, tds.getNumActive("u2", "p2"));
299: assertEquals(1, tds.getNumIdle());
300: assertEquals(0, tds.getNumIdle("u1", "p1"));
301: assertEquals(0, tds.getNumIdle("u2", "p2"));
302:
303: conn = tds.getConnection("u1", "p1");
304: assertNotNull(conn);
305: assertEquals(0, tds.getNumActive());
306: assertEquals(1, tds.getNumActive("u1", "p1"));
307: assertEquals(0, tds.getNumActive("u2", "p2"));
308: assertEquals(1, tds.getNumIdle());
309: assertEquals(0, tds.getNumIdle("u1", "p1"));
310: assertEquals(0, tds.getNumIdle("u2", "p2"));
311:
312: conn.close();
313: assertEquals(0, tds.getNumActive());
314: assertEquals(0, tds.getNumActive("u1", "p1"));
315: assertEquals(0, tds.getNumActive("u2", "p2"));
316: assertEquals(1, tds.getNumIdle());
317: assertEquals(1, tds.getNumIdle("u1", "p1"));
318: assertEquals(0, tds.getNumIdle("u2", "p2"));
319: }
320:
321: public void testMultipleThreads() throws Exception {
322: assertTrue(multipleThreads(1));
323: assertTrue(!multipleThreads(2 * (int) (getMaxWait())));
324: }
325:
326: private boolean multipleThreads(int holdTime) throws Exception {
327: long startTime = System.currentTimeMillis();
328: final boolean[] success = new boolean[1];
329: success[0] = true;
330: final PoolTest[] pts = new PoolTest[2 * getMaxActive()];
331: ThreadGroup threadGroup = new ThreadGroup("foo") {
332: public void uncaughtException(Thread t, Throwable e) {
333: /*
334: for (int i = 0; i < pts.length; i++)
335: {
336: System.out.println(i + ": " + pts[i].reportState());
337: }
338: */
339: for (int i = 0; i < pts.length; i++) {
340: pts[i].stop();
341: }
342:
343: //e.printStackTrace();
344: success[0] = false;
345: }
346: };
347:
348: for (int i = 0; i < pts.length; i++) {
349: pts[i] = new PoolTest(threadGroup, holdTime);
350: }
351: Thread.sleep(10 * holdTime);
352: for (int i = 0; i < pts.length; i++) {
353: pts[i].stop();
354: }
355: long time = System.currentTimeMillis() - startTime;
356: // - (pts.length*10*holdTime);
357: System.out.println("Multithread test time = " + time + " ms");
358:
359: Thread.sleep(holdTime);
360: return success[0];
361: }
362:
363: private static int currentThreadCount = 0;
364:
365: private class PoolTest implements Runnable {
366: /**
367: * The number of milliseconds to hold onto a database connection
368: */
369: private int connHoldTime;
370:
371: private boolean isRun;
372:
373: private String state;
374:
375: protected PoolTest(ThreadGroup threadGroup, int connHoldTime) {
376: this .connHoldTime = connHoldTime;
377: Thread thread = new Thread(threadGroup, this , "Thread+"
378: + currentThreadCount++);
379: thread.setDaemon(false);
380: thread.start();
381: }
382:
383: public void run() {
384: isRun = true;
385: while (isRun) {
386: try {
387: Connection conn = null;
388: state = "Getting Connection";
389: conn = getConnection();
390: state = "Using Connection";
391: assertTrue(null != conn);
392: PreparedStatement stmt = conn
393: .prepareStatement("select * from dual");
394: assertTrue(null != stmt);
395: ResultSet rset = stmt.executeQuery();
396: assertTrue(null != rset);
397: assertTrue(rset.next());
398: state = "Holding Connection";
399: Thread.sleep(connHoldTime);
400: state = "Returning Connection";
401: rset.close();
402: stmt.close();
403: conn.close();
404: } catch (RuntimeException e) {
405: throw e;
406: } catch (Exception e) {
407: throw new RuntimeException(e.toString());
408: }
409: }
410: }
411:
412: public void stop() {
413: isRun = false;
414: }
415:
416: public String reportState() {
417: return state;
418: }
419: }
420:
421: public void testTransactionIsolationBehavior() throws Exception {
422: Connection conn = getConnection();
423: assertTrue(conn != null);
424: assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn
425: .getTransactionIsolation());
426: conn
427: .setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
428: conn.close();
429:
430: Connection conn2 = getConnection();
431: assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn2
432: .getTransactionIsolation());
433:
434: Connection conn3 = getConnection();
435: assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn3
436: .getTransactionIsolation());
437: conn2.close();
438: conn3.close();
439: }
440:
441: public void testSerialization() throws Exception {
442: // make sure the pool has initialized
443: Connection conn = ds.getConnection();
444: conn.close();
445:
446: // serialize
447: ByteArrayOutputStream baos = new ByteArrayOutputStream();
448: ObjectOutputStream out = new ObjectOutputStream(baos);
449: out.writeObject((Serializable) ds);
450: byte[] b = baos.toByteArray();
451: out.close();
452:
453: ByteArrayInputStream bais = new ByteArrayInputStream(b);
454: ObjectInputStream in = new ObjectInputStream(bais);
455: Object obj = in.readObject();
456: in.close();
457:
458: assertEquals(1, ((PerUserPoolDataSource) obj).getNumIdle());
459: }
460:
461: // see issue http://issues.apache.org/bugzilla/show_bug.cgi?id=23843
462: // unregistered user is in the same pool as without username
463: public void testUnregisteredUser() throws Exception {
464: PerUserPoolDataSource tds = (PerUserPoolDataSource) ds;
465:
466: assertEquals(0, tds.getNumActive());
467: assertEquals(0, tds.getNumIdle());
468:
469: Connection conn = tds.getConnection();
470: assertNotNull(conn);
471: assertEquals(1, tds.getNumActive());
472: assertEquals(0, tds.getNumIdle());
473:
474: conn.close();
475: assertEquals(0, tds.getNumActive());
476: assertEquals(1, tds.getNumIdle());
477:
478: conn = tds.getConnection("u1", "p1");
479: assertNotNull(conn);
480: assertEquals(0, tds.getNumActive());
481: assertEquals(1, tds.getNumIdle());
482: assertEquals(1, tds.getNumActive("u1", "p1"));
483: assertEquals(0, tds.getNumIdle("u1", "p1"));
484:
485: conn.close();
486: assertEquals(0, tds.getNumActive());
487: assertEquals(1, tds.getNumIdle());
488: assertEquals(0, tds.getNumActive("u1", "p1"));
489: assertEquals(1, tds.getNumIdle("u1", "p1"));
490: }
491:
492: // see issue http://issues.apache.org/bugzilla/show_bug.cgi?id=23843
493: public void testDefaultUser1() throws Exception {
494: TesterDriver.addUser("mkh", "password");
495: TesterDriver.addUser("hanafey", "password");
496: TesterDriver.addUser("jsmith", "password");
497:
498: PerUserPoolDataSource puds = (PerUserPoolDataSource) ds;
499: puds.setPerUserMaxActive("jsmith", new Integer(2));
500: String[] users = { "mkh", "hanafey", "jsmith" };
501: String password = "password";
502: Connection[] c = new Connection[users.length];
503: for (int i = 0; i < users.length; i++) {
504: c[i] = puds.getConnection(users[i], password);
505: assertEquals(users[i], getUsername(c[i]));
506: }
507: for (int i = 0; i < users.length; i++) {
508: c[i].close();
509: }
510: }
511:
512: // see issue http://issues.apache.org/bugzilla/show_bug.cgi?id=23843
513: public void testDefaultUser2() throws Exception {
514: TesterDriver.addUser("mkh", "password");
515: TesterDriver.addUser("hanafey", "password");
516: TesterDriver.addUser("jsmith", "password");
517:
518: PerUserPoolDataSource puds = (PerUserPoolDataSource) ds;
519: puds.setPerUserMaxActive("jsmith", new Integer(2));
520: String[] users = { "jsmith", "hanafey", "mkh" };
521: String password = "password";
522: Connection[] c = new Connection[users.length];
523: for (int i = 0; i < users.length; i++) {
524: c[i] = puds.getConnection(users[i], password);
525: assertEquals(users[i], getUsername(c[i]));
526: }
527: for (int i = 0; i < users.length; i++) {
528: c[i].close();
529: }
530: }
531: }
|