1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.dbcp2.datasources;
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertFalse;
22 import static org.junit.jupiter.api.Assertions.assertNotNull;
23 import static org.junit.jupiter.api.Assertions.assertThrows;
24 import static org.junit.jupiter.api.Assertions.assertTrue;
25 import static org.junit.jupiter.api.Assertions.fail;
26
27 import java.sql.CallableStatement;
28 import java.sql.Connection;
29 import java.sql.PreparedStatement;
30 import java.sql.ResultSet;
31 import java.sql.SQLException;
32 import java.sql.Statement;
33 import java.time.Duration;
34 import java.util.ArrayList;
35
36 import javax.sql.DataSource;
37
38 import org.apache.commons.dbcp2.DelegatingStatement;
39 import org.apache.commons.dbcp2.TestConnectionPool;
40 import org.apache.commons.dbcp2.TesterDriver;
41 import org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS;
42 import org.apache.commons.lang3.ArrayUtils;
43 import org.junit.jupiter.api.BeforeEach;
44 import org.junit.jupiter.api.Test;
45
46
47
48 public class TestSharedPoolDataSource extends TestConnectionPool {
49
50
51
52
53
54 private static abstract class AbstractPrepareCallCallback {
55 protected Connection conn;
56
57 abstract CallableStatement getCallableStatement() throws SQLException;
58
59 void setConnection(final Connection conn) {
60 this.conn = conn;
61 }
62 }
63
64
65
66
67
68 private static abstract class AbstractPrepareStatementCallback {
69 protected Connection conn;
70
71 abstract PreparedStatement prepareStatement() throws SQLException;
72
73 void setConnection(final Connection conn) {
74 this.conn = conn;
75 }
76 }
77
78 private static final class CscbString extends AbstractPrepareCallCallback {
79 @Override
80 CallableStatement getCallableStatement() throws SQLException {
81 return conn.prepareCall("{call home()}");
82 }
83 }
84
85 private static final class CscbStringIntInt extends AbstractPrepareCallCallback {
86 @Override
87 CallableStatement getCallableStatement() throws SQLException {
88 return conn.prepareCall("{call home()}", 0, 0);
89 }
90 }
91
92 private static final class CscbStringIntIntInt extends AbstractPrepareCallCallback {
93 @Override
94 CallableStatement getCallableStatement() throws SQLException {
95 return conn.prepareCall("{call home()}", 0, 0, 0);
96 }
97 }
98
99 private static final class PscbString extends AbstractPrepareStatementCallback {
100 @Override
101 PreparedStatement prepareStatement() throws SQLException {
102 return conn.prepareStatement("select * from dual");
103 }
104 }
105
106 private static final class PscbStringInt extends AbstractPrepareStatementCallback {
107 @Override
108 PreparedStatement prepareStatement() throws SQLException {
109 return conn.prepareStatement("select * from dual", 0);
110 }
111 }
112
113 private static final class PscbStringIntArray extends AbstractPrepareStatementCallback {
114 @Override
115 PreparedStatement prepareStatement() throws SQLException {
116 return conn.prepareStatement("select * from dual", ArrayUtils.EMPTY_INT_ARRAY);
117 }
118 }
119
120 private static final class PscbStringIntInt extends AbstractPrepareStatementCallback {
121 @Override
122 PreparedStatement prepareStatement() throws SQLException {
123 return conn.prepareStatement("select * from dual", 0, 0);
124 }
125 }
126
127 private static final class PscbStringIntIntInt extends AbstractPrepareStatementCallback {
128 @Override
129 PreparedStatement prepareStatement() throws SQLException {
130 return conn.prepareStatement("select * from dual", 0, 0, 0);
131 }
132 }
133
134 private static final class PscbStringStringArray extends AbstractPrepareStatementCallback {
135 @Override
136 PreparedStatement prepareStatement() throws SQLException {
137 return conn.prepareStatement("select * from dual", ArrayUtils.EMPTY_STRING_ARRAY);
138 }
139 }
140
141 private DriverAdapterCPDS pcds;
142
143 private DataSource ds;
144
145 private void doTestPoolCallableStatements(final AbstractPrepareCallCallback callBack)
146 throws Exception {
147 final DriverAdapterCPDS myPcds = new DriverAdapterCPDS();
148 myPcds.setDriver("org.apache.commons.dbcp2.TesterDriver");
149 myPcds.setUrl("jdbc:apache:commons:testdriver");
150 myPcds.setUser("foo");
151 myPcds.setPassword("bar");
152 myPcds.setPoolPreparedStatements(true);
153 myPcds.setMaxPreparedStatements(10);
154
155 try (final SharedPoolDataSource spDs = new SharedPoolDataSource()) {
156 spDs.setConnectionPoolDataSource(myPcds);
157 spDs.setMaxTotal(getMaxTotal());
158 spDs.setDefaultMaxWait(getMaxWaitDuration());
159 spDs.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
160
161 @SuppressWarnings("resource")
162 final DataSource myDs = spDs;
163
164 try (Connection conn = ds.getConnection()) {
165 callBack.setConnection(conn);
166
167 assertNotNull(conn);
168 final long l1HashCode;
169 final long l2HashCode;
170 try (CallableStatement stmt = callBack.getCallableStatement()) {
171 assertNotNull(stmt);
172 l1HashCode = getDelegateHashCode(stmt);
173 try (ResultSet rset = stmt.executeQuery()) {
174 assertNotNull(rset);
175 assertTrue(rset.next());
176 }
177 }
178
179 try (CallableStatement stmt = callBack.getCallableStatement()) {
180 assertNotNull(stmt);
181 l2HashCode = getDelegateHashCode(stmt);
182 try (ResultSet rset = stmt.executeQuery()) {
183 assertNotNull(rset);
184 assertTrue(rset.next());
185 }
186 }
187
188
189 assertTrue(l1HashCode != l2HashCode);
190 }
191
192 try (Connection conn = myDs.getConnection()) {
193 callBack.setConnection(conn);
194
195 final long l3HashCode;
196 final long l4HashCode;
197 try (CallableStatement stmt = callBack.getCallableStatement()) {
198 assertNotNull(stmt);
199 l3HashCode = getDelegateHashCode(stmt);
200 try (ResultSet rset = stmt.executeQuery()) {
201 assertNotNull(rset);
202 assertTrue(rset.next());
203 }
204 }
205
206 try (CallableStatement stmt = callBack.getCallableStatement()) {
207 assertNotNull(stmt);
208 l4HashCode = getDelegateHashCode(stmt);
209 try (ResultSet rset = stmt.executeQuery()) {
210 assertNotNull(rset);
211 assertTrue(rset.next());
212 }
213 }
214
215
216 assertEquals(l3HashCode, l4HashCode);
217 }
218 }
219 }
220
221 private void doTestPoolPreparedStatements(final AbstractPrepareStatementCallback psCallBack) throws Exception {
222 final DriverAdapterCPDS mypcds = new DriverAdapterCPDS();
223 mypcds.setDriver("org.apache.commons.dbcp2.TesterDriver");
224 mypcds.setUrl("jdbc:apache:commons:testdriver");
225 mypcds.setUser("foo");
226 mypcds.setPassword("bar");
227 mypcds.setPoolPreparedStatements(true);
228 mypcds.setMaxPreparedStatements(10);
229
230 try (final SharedPoolDataSource tds = new SharedPoolDataSource()) {
231 tds.setConnectionPoolDataSource(mypcds);
232 tds.setMaxTotal(getMaxTotal());
233 tds.setDefaultMaxWait(getMaxWaitDuration());
234 tds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
235
236 @SuppressWarnings("resource")
237 final
238 DataSource myDs = tds;
239
240 try (Connection conn = ds.getConnection()) {
241 final long l1HashCode;
242 final long l2HashCode;
243 assertNotNull(conn);
244 psCallBack.setConnection(conn);
245 try (PreparedStatement stmt = psCallBack.prepareStatement()) {
246 assertNotNull(stmt);
247 l1HashCode = getDelegateHashCode(stmt);
248 try (ResultSet resultSet = stmt.executeQuery()) {
249 assertNotNull(resultSet);
250 assertTrue(resultSet.next());
251 }
252 }
253
254 try (PreparedStatement stmt = psCallBack.prepareStatement()) {
255 assertNotNull(stmt);
256 l2HashCode = getDelegateHashCode(stmt);
257 try (ResultSet resultSet = stmt.executeQuery()) {
258 assertNotNull(resultSet);
259 assertTrue(resultSet.next());
260 }
261 }
262
263
264 assertTrue(l1HashCode != l2HashCode);
265 }
266
267 try (Connection conn = myDs.getConnection()) {
268 final long l3HashCode;
269 final long l4HashCode;
270
271 assertNotNull(conn);
272 psCallBack.setConnection(conn);
273 try (PreparedStatement stmt = psCallBack.prepareStatement()) {
274 assertNotNull(stmt);
275 l3HashCode = getDelegateHashCode(stmt);
276 try (ResultSet resultSet = stmt.executeQuery()) {
277 assertNotNull(resultSet);
278 assertTrue(resultSet.next());
279 }
280 }
281
282 try (PreparedStatement stmt = psCallBack.prepareStatement()) {
283 assertNotNull(stmt);
284 l4HashCode = getDelegateHashCode(stmt);
285 try (ResultSet resultSet = stmt.executeQuery()) {
286 assertNotNull(resultSet);
287 assertTrue(resultSet.next());
288 }
289 }
290
291
292 assertEquals(l3HashCode, l4HashCode);
293 }
294 }
295 }
296
297 @Override
298 protected Connection getConnection() throws Exception {
299 return ds.getConnection("foo","bar");
300 }
301
302 @SuppressWarnings("resource")
303 private int getDelegateHashCode(final Statement stmt) {
304 return ((DelegatingStatement) stmt).getDelegate().hashCode();
305 }
306
307 @BeforeEach
308 public void setUp() throws Exception {
309 pcds = new DriverAdapterCPDS();
310 pcds.setDriver("org.apache.commons.dbcp2.TesterDriver");
311 pcds.setUrl("jdbc:apache:commons:testdriver");
312 pcds.setUser("foo");
313 pcds.setPassword("bar");
314 pcds.setPoolPreparedStatements(false);
315 pcds.setAccessToUnderlyingConnectionAllowed(true);
316
317 final SharedPoolDataSource tds = new SharedPoolDataSource();
318 tds.setConnectionPoolDataSource(pcds);
319 tds.setMaxTotal(getMaxTotal());
320 tds.setDefaultMaxWait(getMaxWaitDuration());
321 tds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
322 tds.setDefaultAutoCommit(Boolean.TRUE);
323
324 ds = tds;
325 }
326
327
328 @Test
329 public void testChangePassword() throws Exception {
330 assertThrows(SQLException.class, () -> ds.getConnection("foo", "bay"));
331 final Connection con1 = ds.getConnection("foo", "bar");
332 final Connection con2 = ds.getConnection("foo", "bar");
333 final Connection con3 = ds.getConnection("foo", "bar");
334 con1.close();
335 con2.close();
336 TesterDriver.addUser("foo", "bay");
337 try (Connection con4 = ds.getConnection("foo", "bay")) {
338
339 assertEquals(0, ((SharedPoolDataSource) ds).getNumIdle(), "Should be no idle connections in the pool");
340 con4.close();
341
342 assertEquals(1, ((SharedPoolDataSource) ds).getNumIdle(), "Should be one idle connection in the pool");
343 assertThrows(SQLException.class, () -> ds.getConnection("foo", "bar"));
344 try (final Connection con5 = ds.getConnection("foo", "bay")) {
345 con3.close();
346 ds.getConnection("foo", "bay").close();
347 assertEquals(1, ((SharedPoolDataSource) ds).getNumIdle(), "Should be one idle connection in the pool");
348 }
349 } finally {
350 TesterDriver.addUser("foo", "bar");
351 }
352 }
353
354
355
356
357
358
359 @Test
360 public void testClosePool() throws Exception {
361 ((SharedPoolDataSource) ds).close();
362 @SuppressWarnings("resource")
363 final SharedPoolDataSource tds = new SharedPoolDataSource();
364
365 tds.close();
366 }
367
368 @Override
369 @Test
370 public void testClosing() throws Exception {
371 final Connection[] c = new Connection[getMaxTotal()];
372
373 for (int i = 0; i < c.length; i++) {
374 c[i] = ds.getConnection();
375 }
376
377
378 c[0].close();
379 assertTrue(c[0].isClosed());
380
381
382 c[0] = ds.getConnection();
383
384 for (final Connection element : c) {
385 element.close();
386 }
387 }
388
389 @Test
390 public void testClosingWithUserName() throws Exception {
391 final Connection[] c = new Connection[getMaxTotal()];
392
393 for (int i = 0; i < c.length; i++) {
394 c[i] = ds.getConnection("u1", "p1");
395 }
396
397
398 c[0].close();
399 assertTrue(c[0].isClosed());
400
401 c[0] = ds.getConnection("u1", "p1");
402
403 for (final Connection element : c) {
404 element.close();
405 }
406
407
408 for (int i = 0; i < c.length; i++) {
409 c[i] = ds.getConnection("u1", "p1");
410 }
411 for (final Connection element : c) {
412 element.close();
413 }
414 }
415
416 @Test
417 public void testDbcp369() {
418 final ArrayList<SharedPoolDataSource> dataSources = new ArrayList<>();
419 for (int j = 0; j < 10000; j++) {
420 dataSources.add(new SharedPoolDataSource());
421 }
422
423 final Thread t1 = new Thread(() -> {
424 for (final SharedPoolDataSource dataSource : dataSources) {
425 dataSource.setDataSourceName("a");
426 }
427 });
428
429 final Thread t2 = new Thread(() -> {
430 for (final SharedPoolDataSource dataSource : dataSources) {
431 try {
432 dataSource.close();
433 } catch (final Exception e) {
434
435 }
436 }
437 });
438
439 t1.start();
440 t2.start();
441
442 try {
443 t1.join();
444 t2.join();
445 } catch (final InterruptedException ie) {
446
447 }
448 }
449
450
451
452
453
454
455 @Test
456 public void testIncorrectPassword() throws SQLException {
457 ds.getConnection("u2", "p2").close();
458 try (Connection c = ds.getConnection("u1", "zlsafjk")){
459 fail("Able to retrieve connection with incorrect password");
460 } catch (final SQLException e1) {
461
462 }
463
464
465 ds.getConnection("u1", "p1").close();
466 try (Connection c = ds.getConnection("u1", "x")) {
467 fail("Able to retrieve connection with incorrect password");
468 } catch (final SQLException e) {
469 if (!e.getMessage().startsWith("Given password did not match")) {
470 throw e;
471 }
472
473 }
474
475
476 ds.getConnection("u1", "p1").close();
477
478
479 ds.getConnection("foo", "bar").close();
480 try (Connection c = ds.getConnection("u1", "ar")) {
481 fail("Should have caused an SQLException");
482 } catch (final SQLException expected) {
483 }
484 try (Connection c = ds.getConnection("u1", "baz")) {
485 fail("Should have generated SQLException");
486 } catch (final SQLException expected) {
487 }
488 }
489
490 @Override
491 @Test
492 public void testMaxTotal() throws Exception {
493 final Connection[] c = new Connection[getMaxTotal()];
494 for (int i=0; i<c.length; i++) {
495 c[i] = ds.getConnection();
496 assertNotNull(c[i]);
497 }
498
499 assertThrows(SQLException.class, ds::getConnection, "Allowed to open more than DefaultMaxTotal connections.");
500
501 for (final Connection element : c) {
502 element.close();
503 }
504 }
505
506 @Test
507 public void testMaxWaitMillis() throws Exception {
508 final int maxWaitMillis = 1000;
509 final int theadCount = 20;
510
511 ((SharedPoolDataSource) ds).setDefaultMaxWait(Duration.ofMillis(maxWaitMillis));
512
513 final Connection[] c = new Connection[getMaxTotal()];
514 for (int i = 0; i < c.length; i++) {
515 c[i] = ds.getConnection("foo", "bar");
516 assertNotNull(c[i]);
517 }
518
519 final long startMillis = System.currentTimeMillis();
520
521
522
523 final PoolTest[] pts = new PoolTest[theadCount];
524 final ThreadGroup threadGroup = new ThreadGroup("testMaxWaitMillis");
525
526
527 for (int i = 0; i < pts.length; i++) {
528 (pts[i] = new PoolTest(threadGroup, Duration.ofMillis(1), true)).start();
529 }
530
531
532 for (final PoolTest poolTest : pts) {
533 poolTest.getThread().join();
534 }
535
536 final long endMillis = System.currentTimeMillis();
537
538
539
540
541 assertTrue(endMillis - startMillis < 2 * maxWaitMillis);
542
543
544 for (final Connection element : c) {
545 element.close();
546 }
547 }
548
549 @Test
550 public void testMultipleThreads1() throws Exception {
551
552
553 final Duration defaultMaxWaitDuration = Duration.ofMillis(430);
554 ((SharedPoolDataSource) ds).setDefaultMaxWait(defaultMaxWaitDuration);
555 multipleThreads(Duration.ofMillis(1), false, false, defaultMaxWaitDuration);
556 }
557
558 @Test
559 public void testMultipleThreads2() throws Exception {
560 final Duration defaultMaxWaitDuration = Duration.ofMillis(500);
561 ((SharedPoolDataSource) ds).setDefaultMaxWait(defaultMaxWaitDuration);
562 multipleThreads(defaultMaxWaitDuration.multipliedBy(2), true, true, defaultMaxWaitDuration);
563 }
564
565 @Override
566 @Test
567 public void testOpening() throws Exception {
568 final Connection[] c = new Connection[getMaxTotal()];
569
570 for (int i = 0; i < c.length; i++) {
571 c[i] = ds.getConnection();
572 assertNotNull(c[i]);
573 for (int j = 0; j <= i; j++) {
574 assertFalse(c[j].isClosed());
575 }
576 }
577
578 for (final Connection element : c) {
579 element.close();
580 }
581 }
582
583
584
585
586 @Test
587 public void testPoolPrepareCall() throws SQLException {
588 pcds.setPoolPreparedStatements(true);
589 try (final Connection conn = ds.getConnection()) {
590 assertNotNull(conn);
591 try (final PreparedStatement stmt = conn.prepareCall("{call home()}")) {
592 assertNotNull(stmt);
593 try (final ResultSet rset = stmt.executeQuery()) {
594 assertNotNull(rset);
595 assertTrue(rset.next());
596 }
597 }
598 }
599 }
600
601 @Test
602 public void testPoolPreparedCalls() throws Exception {
603 doTestPoolCallableStatements(new CscbString());
604 doTestPoolCallableStatements(new CscbStringIntInt());
605 doTestPoolCallableStatements(new CscbStringIntIntInt());
606 }
607
608 @Test
609 public void testPoolPreparedStatements() throws Exception {
610 doTestPoolPreparedStatements(new PscbString());
611 doTestPoolPreparedStatements(new PscbStringIntInt());
612 doTestPoolPreparedStatements(new PscbStringInt());
613 doTestPoolPreparedStatements(new PscbStringIntArray());
614 doTestPoolPreparedStatements(new PscbStringStringArray());
615 doTestPoolPreparedStatements(new PscbStringIntIntInt());
616 }
617
618 @Test
619 public void testPoolPrepareStatement() throws SQLException {
620 pcds.setPoolPreparedStatements(true);
621
622 try (final Connection conn = ds.getConnection()) {
623 assertNotNull(conn);
624 try (final PreparedStatement stmt = conn.prepareStatement("select * from dual")) {
625 assertNotNull(stmt);
626 try (final ResultSet rset = stmt.executeQuery()) {
627 assertNotNull(rset);
628 assertTrue(rset.next());
629 }
630 }
631 }
632 }
633
634 @Override
635 @Test
636 public void testSimple() throws Exception {
637 try (final Connection conn = ds.getConnection()) {
638 assertNotNull(conn);
639 try (final PreparedStatement stmt = conn.prepareStatement("select * from dual")) {
640 assertNotNull(stmt);
641 try (final ResultSet rset = stmt.executeQuery()) {
642 assertNotNull(rset);
643 assertTrue(rset.next());
644 }
645 }
646 }
647 }
648
649 @Override
650 @Test
651 public void testSimple2() throws SQLException {
652 {
653 final Connection conn = ds.getConnection();
654 assertNotNull(conn);
655
656 try (PreparedStatement stmt = conn.prepareStatement("select * from dual")) {
657 assertNotNull(stmt);
658 try (ResultSet rset = stmt.executeQuery()) {
659 assertNotNull(rset);
660 assertTrue(rset.next());
661 }
662 }
663
664 try (PreparedStatement stmt = conn.prepareStatement("select * from dual")) {
665 assertNotNull(stmt);
666 try (ResultSet rset = stmt.executeQuery()) {
667 assertNotNull(rset);
668 assertTrue(rset.next());
669 }
670 }
671
672 conn.close();
673 assertThrows(SQLException.class, () -> conn.createStatement(), "Can't use closed connections");
674 }
675 try (Connection conn = ds.getConnection()) {
676 assertNotNull(conn);
677
678 try (PreparedStatement stmt = conn.prepareStatement("select * from dual")) {
679 assertNotNull(stmt);
680 try (ResultSet rset = stmt.executeQuery()) {
681 assertNotNull(rset);
682 assertTrue(rset.next());
683 }
684 }
685
686 try (PreparedStatement stmt = conn.prepareStatement("select * from dual")) {
687 assertNotNull(stmt);
688 try (ResultSet rset = stmt.executeQuery()) {
689 assertNotNull(rset);
690 assertTrue(rset.next());
691 }
692 }
693
694 }
695 }
696
697 @Test
698 public void testSimpleWithUsername() throws Exception {
699 try (final Connection conn = ds.getConnection("u1", "p1")) {
700 assertNotNull(conn);
701 try (final PreparedStatement stmt = conn.prepareStatement("select * from dual")) {
702 assertNotNull(stmt);
703 try (final ResultSet rset = stmt.executeQuery()) {
704 assertNotNull(rset);
705 assertTrue(rset.next());
706 }
707 }
708 }
709 }
710
711 @Test
712 public void testTransactionIsolationBehavior() throws Exception {
713 try (final Connection conn = getConnection()) {
714 assertNotNull(conn);
715 assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn.getTransactionIsolation());
716 conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
717 }
718
719 final Connection conn2 = getConnection();
720 assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn2.getTransactionIsolation());
721
722 final Connection conn3 = getConnection();
723 assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn3.getTransactionIsolation());
724 conn2.close();
725 conn3.close();
726 }
727 }