1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.dbcp2;
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.assertInstanceOf;
23 import static org.junit.jupiter.api.Assertions.assertNotNull;
24 import static org.junit.jupiter.api.Assertions.assertNull;
25 import static org.junit.jupiter.api.Assertions.assertSame;
26 import static org.junit.jupiter.api.Assertions.assertThrows;
27 import static org.junit.jupiter.api.Assertions.assertTrue;
28 import static org.junit.jupiter.api.Assertions.fail;
29
30 import java.io.IOException;
31 import java.lang.management.ManagementFactory;
32 import java.lang.management.ThreadMXBean;
33 import java.sql.Connection;
34 import java.sql.SQLException;
35 import java.time.Duration;
36 import java.util.ArrayList;
37 import java.util.Arrays;
38 import java.util.Collection;
39 import java.util.HashSet;
40 import java.util.Properties;
41 import java.util.Set;
42 import java.util.concurrent.atomic.AtomicInteger;
43 import java.util.stream.Stream;
44
45 import javax.management.AttributeNotFoundException;
46 import javax.management.MBeanAttributeInfo;
47 import javax.management.MBeanServer;
48 import javax.management.ObjectName;
49 import javax.sql.DataSource;
50
51 import org.junit.jupiter.api.AfterEach;
52 import org.junit.jupiter.api.Assertions;
53 import org.junit.jupiter.api.BeforeEach;
54 import org.junit.jupiter.api.Disabled;
55 import org.junit.jupiter.api.Test;
56
57
58
59
60 public class TestBasicDataSource extends TestConnectionPool {
61
62 private static final String CATALOG = "test catalog";
63
64 protected BasicDataSource ds;
65
66 protected BasicDataSource createDataSource() throws Exception {
67 return new BasicDataSource();
68 }
69
70 @Override
71 protected Connection getConnection() throws Exception {
72 return ds.getConnection();
73 }
74
75 @BeforeEach
76 public void setUp() throws Exception {
77 ds = createDataSource();
78 ds.setDriverClassName("org.apache.commons.dbcp2.TesterDriver");
79 ds.setUrl("jdbc:apache:commons:testdriver");
80 ds.setMaxTotal(getMaxTotal());
81 ds.setMaxWait(getMaxWaitDuration());
82 ds.setDefaultAutoCommit(Boolean.TRUE);
83 ds.setDefaultReadOnly(Boolean.FALSE);
84 ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
85 ds.setDefaultCatalog(CATALOG);
86 ds.setUsername("userName");
87 ds.setPassword("password");
88 ds.setValidationQuery("SELECT DUMMY FROM DUAL");
89 ds.setConnectionInitSqls(Arrays.asList("SELECT 1", "SELECT 2"));
90 ds.setDriverClassLoader(new TesterClassLoader());
91 ds.setJmxName("org.apache.commons.dbcp2:name=test");
92 }
93
94 @Override
95 @AfterEach
96 public void tearDown() throws Exception {
97 super.tearDown();
98 ds.close();
99 ds = null;
100 }
101
102 @Test
103 public void testAccessToUnderlyingConnectionAllowed() throws Exception {
104 ds.setAccessToUnderlyingConnectionAllowed(true);
105 assertTrue(ds.isAccessToUnderlyingConnectionAllowed());
106
107 try (final Connection conn = getConnection()) {
108 Connection dconn = ((DelegatingConnection<?>) conn).getDelegate();
109 assertNotNull(dconn);
110
111 dconn = ((DelegatingConnection<?>) conn).getInnermostDelegate();
112 assertNotNull(dconn);
113
114 assertInstanceOf(TesterConnection.class, dconn);
115 }
116 }
117
118 @Test
119 public void testClose() throws Exception {
120 ds.setAccessToUnderlyingConnectionAllowed(true);
121
122
123 final Connection activeConnection = getConnection();
124 final Connection rawActiveConnection = ((DelegatingConnection<?>) activeConnection).getInnermostDelegate();
125 assertFalse(activeConnection.isClosed());
126 assertFalse(rawActiveConnection.isClosed());
127
128
129 final Connection idleConnection = getConnection();
130 final Connection rawIdleConnection = ((DelegatingConnection<?>) idleConnection).getInnermostDelegate();
131 assertFalse(idleConnection.isClosed());
132 assertFalse(rawIdleConnection.isClosed());
133
134
135 idleConnection.close();
136 assertTrue(idleConnection.isClosed());
137 assertFalse(rawIdleConnection.isClosed());
138
139 ds.close();
140
141
142 assertTrue(rawIdleConnection.isClosed());
143
144
145 assertFalse(activeConnection.isClosed());
146 assertFalse(rawActiveConnection.isClosed());
147
148
149 activeConnection.close();
150
151
152 assertTrue(activeConnection.isClosed());
153 assertTrue(rawActiveConnection.isClosed());
154
155
156 assertThrows(SQLException.class, this::getConnection);
157
158
159 ds.close();
160
161 }
162
163 @Test
164 public void testConcurrentInitBorrow() throws Exception {
165 ds.setDriverClassName("org.apache.commons.dbcp2.TesterConnectionDelayDriver");
166 ds.setUrl("jdbc:apache:commons:testerConnectionDelayDriver:50");
167 ds.setInitialSize(8);
168
169
170 final TestThread testThread = new TestThread(1, 0);
171 final Thread t = new Thread(testThread);
172 t.start();
173
174
175 Thread.sleep(100);
176 try (Connection conn = ds.getConnection()) {
177
178
179
180 assertTrue(ds.getConnectionPool().getNumIdle() > 5);
181
182
183 t.join();
184 assertFalse(testThread.failed());
185 }
186 ds.close();
187 }
188
189
190
191
192
193 @Test
194 public void testConcurrentInvalidateBorrow() throws Exception {
195 ds.setDriverClassName("org.apache.commons.dbcp2.TesterConnRequestCountDriver");
196 ds.setUrl("jdbc:apache:commons:testerConnRequestCountDriver");
197 ds.setTestOnBorrow(true);
198 ds.setValidationQuery("SELECT DUMMY FROM DUAL");
199 ds.setMaxTotal(8);
200 ds.setLifo(true);
201 ds.setMaxWait(Duration.ofMillis(-1));
202
203
204 final TestThread testThread1 = new TestThread(1000,0);
205 final Thread t1 = new Thread(testThread1);
206 t1.start();
207 final TestThread testThread2 = new TestThread(1000,0);
208 final Thread t2 = new Thread(testThread1);
209 t2.start();
210
211
212 for (int i = 0; i < 1000; i++) {
213 final Connection conn = ds.getConnection();
214 ds.invalidateConnection(conn);
215 }
216
217
218 t1.join();
219 t2.join();
220 assertFalse(testThread1.failed());
221 assertFalse(testThread2.failed());
222
223 ds.close();
224 }
225
226
227
228
229
230 @Test
231 public void testConnectionMBeansDisabled() throws Exception {
232 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
233
234 final ObjectName commons = new ObjectName("org.apache.commons.*:*");
235 final Set<ObjectName> results = mbs.queryNames(commons, null);
236 for (final ObjectName result : results) {
237 mbs.unregisterMBean(result);
238 }
239 ds.setRegisterConnectionMBean(false);
240 try (Connection conn = ds.getConnection()) {
241
242 final ObjectName connections = new ObjectName("org.apache.commons.*:connection=*,*");
243 assertEquals(0, mbs.queryNames(connections, null).size());
244 }
245 }
246
247
248
249
250
251 @Test
252 public void testCreateConnectionFactoryWithConnectionFactoryClassName() throws Exception {
253 Properties properties = new Properties();
254
255 properties = new Properties();
256 properties.put("initialSize", "1");
257 properties.put("driverClassName", "org.apache.commons.dbcp2.TesterDriver");
258 properties.put("url", "jdbc:apache:commons:testdriver");
259 properties.put("username", "foo");
260 properties.put("password", "bar");
261 properties.put("connectionFactoryClassName", "org.apache.commons.dbcp2.TesterConnectionFactory");
262 try (BasicDataSource ds = BasicDataSourceFactory.createDataSource(properties)) {
263 try (Connection conn = ds.getConnection()) {
264 assertNotNull(conn);
265 }
266 }
267 }
268
269
270
271
272
273 @Test
274 public void testCreateConnectionFactoryWithoutConnectionFactoryClassName() throws Exception {
275
276 final Properties properties = new Properties();
277 properties.put("initialSize", "1");
278 properties.put("driverClassName", "org.apache.commons.dbcp2.TesterDriver");
279 properties.put("url", "jdbc:apache:commons:testdriver");
280 properties.put("username", "foo");
281 properties.put("password", "bar");
282 try (BasicDataSource ds = BasicDataSourceFactory.createDataSource(properties)) {
283 try (Connection conn = ds.getConnection()) {
284 assertNotNull(conn);
285 }
286 }
287 }
288
289
290
291
292
293
294 @Test
295 public void testCreateDataSourceCleanupEvictor() throws Exception {
296 ds.close();
297 ds = null;
298 ds = createDataSource();
299 ds.setDriverClassName("org.apache.commons.dbcp2.TesterConnRequestCountDriver");
300 ds.setUrl("jdbc:apache:commons:testerConnRequestCountDriver");
301 ds.setValidationQuery("SELECT DUMMY FROM DUAL");
302 ds.setUsername("userName");
303
304
305 ds.setPassword("wrong");
306
307 ds.setDurationBetweenEvictionRuns(Duration.ofMillis(100));
308
309 ds.setMinIdle(2);
310
311
312 synchronized (TesterConnRequestCountDriver.class) {
313 TesterConnRequestCountDriver.initConnRequestCount();
314
315
316 for (int i = 0; i < 10; i++) {
317 try {
318 @SuppressWarnings("unused")
319 final DataSource ds2 = ds.createDataSource();
320 } catch (final SQLException e) {
321
322 }
323 }
324
325
326 Thread.sleep(1000);
327
328
329 assertEquals(10, TesterConnRequestCountDriver.getConnectionRequestCount());
330 }
331
332
333 assertNull(ds.getConnectionPool());
334 }
335
336
337
338
339
340 @Test
341 public void testCreateDataSourceCleanupThreads() throws Exception {
342 ds.close();
343 ds = null;
344 ds = createDataSource();
345 ds.setDriverClassName("org.apache.commons.dbcp2.TesterDriver");
346 ds.setUrl("jdbc:apache:commons:testdriver");
347 ds.setMaxTotal(getMaxTotal());
348 ds.setMaxWait(getMaxWaitDuration());
349 ds.setDefaultAutoCommit(Boolean.TRUE);
350 ds.setDefaultReadOnly(Boolean.FALSE);
351 ds.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
352 ds.setDefaultCatalog(CATALOG);
353 ds.setUsername("userName");
354
355 ds.setDurationBetweenEvictionRuns(Duration.ofMillis(100));
356
357 ds.setPassword("wrong");
358 ds.setValidationQuery("SELECT DUMMY FROM DUAL");
359 final int threadCount = Thread.activeCount();
360 for (int i = 0; i < 10; i++) {
361 try (Connection c = ds.getConnection()){
362 } catch (final SQLException ex) {
363
364 }
365 }
366
367 assertTrue(Thread.activeCount() <= threadCount + 1);
368 }
369
370 @Test
371 public void testDefaultCatalog() throws Exception {
372 final Connection[] c = new Connection[getMaxTotal()];
373 for (int i = 0; i < c.length; i++) {
374 c[i] = getConnection();
375 assertNotNull(c[i]);
376 assertEquals(CATALOG, c[i].getCatalog());
377 }
378
379 for (final Connection element : c) {
380 element.setCatalog("error");
381 element.close();
382 }
383
384 for (int i = 0; i < c.length; i++) {
385 c[i] = getConnection();
386 assertNotNull(c[i]);
387 assertEquals(CATALOG, c[i].getCatalog());
388 }
389
390 for (final Connection element : c) {
391 element.close();
392 }
393 }
394
395 @Test
396 public void testDeprecatedAccessors() throws SQLException {
397 try (BasicDataSource bds = new BasicDataSource()) {
398 int i = 0;
399
400 i++;
401 bds.setDefaultQueryTimeout(i);
402 assertEquals(i, bds.getDefaultQueryTimeout());
403 assertEquals(Duration.ofSeconds(i), bds.getDefaultQueryTimeoutDuration());
404
405 i++;
406 bds.setMaxConnLifetimeMillis(i);
407 assertEquals(i, bds.getMaxConnLifetimeMillis());
408 assertEquals(Duration.ofMillis(i), bds.getMaxConnDuration());
409
410 i++;
411 bds.setMaxWaitMillis(i);
412 assertEquals(i, bds.getMaxWaitMillis());
413 assertEquals(Duration.ofMillis(i), bds.getMaxWaitDuration());
414
415 i++;
416 bds.setMinEvictableIdleTimeMillis(i);
417 assertEquals(i, bds.getMinEvictableIdleTimeMillis());
418 assertEquals(Duration.ofMillis(i), bds.getMinEvictableIdleDuration());
419
420 i++;
421 bds.setRemoveAbandonedTimeout(i);
422 assertEquals(i, bds.getRemoveAbandonedTimeout());
423 assertEquals(Duration.ofSeconds(i), bds.getRemoveAbandonedTimeoutDuration());
424
425 i++;
426 bds.setSoftMinEvictableIdleTimeMillis(i);
427 assertEquals(i, bds.getSoftMinEvictableIdleTimeMillis());
428 assertEquals(Duration.ofMillis(i), bds.getSoftMinEvictableIdleDuration());
429
430 i++;
431 bds.setTimeBetweenEvictionRunsMillis(i);
432 assertEquals(i, bds.getTimeBetweenEvictionRunsMillis());
433 assertEquals(Duration.ofMillis(i), bds.getDurationBetweenEvictionRuns());
434
435 i++;
436 bds.setValidationQueryTimeout(1);
437 assertEquals(1, bds.getValidationQueryTimeout());
438 assertEquals(Duration.ofSeconds(1), bds.getValidationQueryTimeoutDuration());
439 }
440 }
441
442 @Test
443 public void testDisconnectionIgnoreSqlCodes() throws Exception {
444 final ArrayList<String> disconnectionIgnoreSqlCodes = new ArrayList<>();
445 disconnectionIgnoreSqlCodes.add("XXXX");
446 ds.setDisconnectionIgnoreSqlCodes(disconnectionIgnoreSqlCodes);
447 ds.setFastFailValidation(true);
448 try (Connection conn = ds.getConnection()) {
449
450 final PoolableConnectionFactory pcf = (PoolableConnectionFactory) ds.getConnectionPool().getFactory();
451 assertTrue(pcf.isFastFailValidation());
452 assertTrue(pcf.getDisconnectionIgnoreSqlCodes().contains("XXXX"));
453 assertEquals(1, pcf.getDisconnectionIgnoreSqlCodes().size());
454 }
455 }
456
457
458
459
460
461
462 @Test
463 public void testDisconnectSqlCodes() throws Exception {
464 final ArrayList<String> disconnectionSqlCodes = new ArrayList<>();
465 disconnectionSqlCodes.add("XXX");
466 ds.setDisconnectionSqlCodes(disconnectionSqlCodes);
467 ds.setFastFailValidation(true);
468 try (Connection conn = ds.getConnection()) {
469
470 final PoolableConnectionFactory pcf = (PoolableConnectionFactory) ds.getConnectionPool().getFactory();
471 assertTrue(pcf.isFastFailValidation());
472 assertTrue(pcf.getDisconnectionSqlCodes().contains("XXX"));
473 assertEquals(1, pcf.getDisconnectionSqlCodes().size());
474 }
475 }
476
477
478
479
480
481 @Test
482 public void testDriverClassLoader() throws Exception {
483 try (Connection conn = getConnection()) {
484 final ClassLoader cl = ds.getDriverClassLoader();
485 assertNotNull(cl);
486 assertInstanceOf(TesterClassLoader.class, cl);
487 assertTrue(((TesterClassLoader) cl).didLoad(ds.getDriverClassName()));
488 }
489 }
490
491 @Test
492 public void testEmptyInitConnectionSql() throws Exception {
493
494 ds.setConnectionInitSqls(Arrays.asList("", " "));
495 assertNotNull(ds.getConnectionInitSqls());
496 assertEquals(0, ds.getConnectionInitSqls().size());
497
498 ds.setConnectionInitSqls(null);
499 assertNotNull(ds.getConnectionInitSqls());
500 assertEquals(0, ds.getConnectionInitSqls().size());
501
502 ds.setConnectionInitSqls((Collection<String>) Arrays.asList("", " "));
503 assertNotNull(ds.getConnectionInitSqls());
504 assertEquals(0, ds.getConnectionInitSqls().size());
505 }
506
507 @Test
508 public void testEmptyValidationQuery() throws Exception {
509 assertNotNull(ds.getValidationQuery());
510
511 ds.setValidationQuery("");
512 assertNull(ds.getValidationQuery());
513
514 ds.setValidationQuery(" ");
515 assertNull(ds.getValidationQuery());
516 }
517
518 @Test
519 @Disabled
520 public void testEvict() throws Exception {
521 final long delay = 1000;
522
523 ds.setInitialSize(10);
524 ds.setMaxIdle(10);
525 ds.setMaxTotal(10);
526 ds.setMinIdle(5);
527 ds.setNumTestsPerEvictionRun(3);
528 ds.setMinEvictableIdle(Duration.ofMillis(100));
529 ds.setDurationBetweenEvictionRuns(Duration.ofMillis(delay));
530 ds.setPoolPreparedStatements(true);
531
532 try (Connection conn = ds.getConnection()) {
533
534 }
535
536 final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
537 while (Stream.of(threadBean.getThreadInfo(threadBean.getAllThreadIds())).anyMatch(t -> t.getThreadName().equals("commons-pool-evictor-thread"))) {
538 if (ds.getNumIdle() <= ds.getMinIdle()) {
539 break;
540 }
541 Thread.sleep(delay);
542 }
543 if (ds.getNumIdle() > ds.getMinIdle()) {
544 fail("EvictionTimer thread was destroyed with numIdle=" + ds.getNumIdle() + "(expected: less or equal than " + ds.getMinIdle() + ")");
545 }
546 }
547
548 @Test
549 public void testInitialSize() throws Exception {
550 ds.setMaxTotal(20);
551 ds.setMaxIdle(20);
552 ds.setInitialSize(10);
553
554 try (Connection conn = getConnection()) {
555 assertNotNull(conn);
556 }
557
558 assertEquals(0, ds.getNumActive());
559 assertEquals(10, ds.getNumIdle());
560 }
561
562
563
564
565
566 @Test
567 public void testInstanceNotFoundExceptionLogSuppressed() throws Exception {
568 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
569 try (Connection c = ds.getConnection()) {
570
571 }
572 final ObjectName objectName = new ObjectName(ds.getJmxName());
573 if (mbs.isRegistered(objectName)) {
574 mbs.unregisterMBean(objectName);
575 }
576 StackMessageLog.clear();
577 ds.close();
578 assertNull(StackMessageLog.popMessage());
579 assertNull(ds.getRegisteredJmxName());
580 }
581
582 @Test
583 public void testInvalidateConnection() throws Exception {
584 ds.setMaxTotal(2);
585 try (final Connection conn1 = ds.getConnection()) {
586 try (final Connection conn2 = ds.getConnection()) {
587 ds.invalidateConnection(conn1);
588 assertTrue(conn1.isClosed());
589 assertEquals(1, ds.getNumActive());
590 assertEquals(0, ds.getNumIdle());
591 try (final Connection conn3 = ds.getConnection()) {
592 conn2.close();
593 }
594 }
595 }
596 }
597
598 @Test
599 public void testInvalidConnectionInitSqlCollection() {
600 ds.setConnectionInitSqls((Collection<String>) Arrays.asList("SELECT 1", "invalid"));
601 final SQLException e = assertThrows(SQLException.class, ds::getConnection);
602 assertTrue(e.toString().contains("invalid"));
603 }
604
605 @Test
606 public void testInvalidConnectionInitSqlList() {
607 ds.setConnectionInitSqls(Arrays.asList("SELECT 1", "invalid"));
608 final SQLException e = assertThrows(SQLException.class, ds::getConnection);
609 assertTrue(e.toString().contains("invalid"));
610 }
611
612 @Test
613 public void testInvalidValidationQuery() {
614 ds.setValidationQuery("invalid");
615 final SQLException e = assertThrows(SQLException.class, ds::getConnection);
616 assertTrue(e.toString().contains("invalid"));
617 }
618
619
620
621 @Test
622 public void testIsClosedFailure() throws SQLException {
623 ds.setAccessToUnderlyingConnectionAllowed(true);
624 final Connection conn = ds.getConnection();
625 assertNotNull(conn);
626 assertEquals(1, ds.getNumActive());
627
628
629 final TesterConnection tconn = (TesterConnection) ((DelegatingConnection<?>) conn).getInnermostDelegate();
630 tconn.setFailure(new IOException("network error"));
631
632 assertThrows(SQLException.class, () -> conn.close());
633
634 assertEquals(0, ds.getNumActive());
635 }
636
637 @Test
638 public void testIsWrapperFor() throws Exception {
639 assertTrue(ds.isWrapperFor(BasicDataSource.class));
640 assertTrue(ds.isWrapperFor(AutoCloseable.class));
641 assertFalse(ds.isWrapperFor(String.class));
642 assertFalse(ds.isWrapperFor(null));
643 }
644
645
646
647
648
649 @Test
650 public void testJmxDisabled() throws Exception {
651 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
652
653 final ObjectName commons = new ObjectName("org.apache.commons.*:*");
654 final Set<ObjectName> results = mbs.queryNames(commons, null);
655 for (final ObjectName result : results) {
656 mbs.unregisterMBean(result);
657 }
658 ds.setJmxName(null);
659 ds.setPoolPreparedStatements(true);
660 try (Connection conn = ds.getConnection()) {
661
662 assertEquals(0, mbs.queryNames(commons, null).size());
663 }
664 }
665
666
667
668
669
670
671
672 @Test
673 public void testJmxDoesNotExposePassword() throws Exception {
674 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
675 try (Connection c = ds.getConnection()) {
676
677 }
678 final ObjectName objectName = new ObjectName(ds.getJmxName());
679 final MBeanAttributeInfo[] attributes = mbs.getMBeanInfo(objectName).getAttributes();
680 assertTrue(attributes != null && attributes.length > 0);
681 Arrays.asList(attributes).forEach(attrInfo -> assertFalse("password".equalsIgnoreCase(attrInfo.getName())));
682 assertThrows(AttributeNotFoundException.class, () -> mbs.getAttribute(objectName, "Password"));
683 }
684
685 @Test
686 public void testManualConnectionEvict() throws Exception {
687 ds.setMinIdle(0);
688 ds.setMaxIdle(4);
689 ds.setMinEvictableIdle(Duration.ofMillis(10));
690 ds.setNumTestsPerEvictionRun(2);
691
692 try (Connection ds2 = ds.createDataSource().getConnection(); Connection ds3 = ds.createDataSource().getConnection()) {
693 assertEquals(0, ds.getNumIdle());
694 }
695
696
697 Thread.sleep(100);
698
699
700 assertEquals(2, ds.getNumIdle());
701
702
703 ds.evict();
704
705
706 assertEquals(0, ds.getNumIdle());
707 }
708
709 @Test
710 public void testMaxConnLifetimeExceeded() throws Exception {
711 try {
712 StackMessageLog.lock();
713 ds.setMaxConn(Duration.ofMillis(100));
714 try (Connection conn = ds.getConnection()) {
715 assertEquals(1, ds.getNumActive());
716 Thread.sleep(500);
717 }
718 assertEquals(0, ds.getNumIdle());
719 final String message = StackMessageLog.popMessage();
720 Assertions.assertNotNull(message);
721 assertTrue(message.indexOf("exceeds the maximum permitted value") > 0);
722 } finally {
723 StackMessageLog.clear();
724 StackMessageLog.unLock();
725 }
726 }
727
728 @Test
729 public void testMaxConnLifetimeExceededMutedLog() throws Exception {
730 try {
731 StackMessageLog.lock();
732 StackMessageLog.clear();
733 ds.setMaxConn(Duration.ofMillis(100));
734 ds.setLogExpiredConnections(false);
735 try (final Connection conn = ds.getConnection()) {
736 assertEquals(1, ds.getNumActive());
737 Thread.sleep(500);
738 }
739 assertEquals(0, ds.getNumIdle());
740 assertTrue(StackMessageLog.isEmpty(), StackMessageLog.getAll().toString());
741 } finally {
742 StackMessageLog.clear();
743 StackMessageLog.unLock();
744 }
745 }
746
747
748
749
750
751
752 @Test
753 public void testMaxTotalZero() throws Exception {
754 ds.setMaxTotal(0);
755 assertThrows(SQLException.class, ds::getConnection);
756 }
757
758
759
760
761
762
763 @Test
764 public void testMutateAbandonedConfig() throws Exception {
765 final Properties properties = new Properties();
766 properties.put("initialSize", "1");
767 properties.put("driverClassName", "org.apache.commons.dbcp2.TesterDriver");
768 properties.put("url", "jdbc:apache:commons:testdriver");
769 properties.put("username", "foo");
770 properties.put("password", "bar");
771 try (BasicDataSource ds = BasicDataSourceFactory.createDataSource(properties)) {
772 final boolean original = ds.getConnectionPool().getLogAbandoned();
773 ds.setLogAbandoned(!original);
774 Assertions.assertNotEquals(original, ds.getConnectionPool().getLogAbandoned());
775 }
776 }
777
778 @Test
779 public void testNoAccessToUnderlyingConnectionAllowed() throws Exception {
780
781 assertFalse(ds.isAccessToUnderlyingConnectionAllowed());
782
783 try (Connection conn = getConnection()) {
784 Connection dconn = ((DelegatingConnection<?>) conn).getDelegate();
785 assertNull(dconn);
786
787 dconn = ((DelegatingConnection<?>) conn).getInnermostDelegate();
788 assertNull(dconn);
789 }
790 }
791
792 @Test
793 public void testNoOverlapBetweenDisconnectionAndIgnoreSqlCodes() {
794
795 final HashSet<String> disconnectionSqlCodes = new HashSet<>(Arrays.asList("XXX", "ZZZ"));
796 ds.setDisconnectionSqlCodes(disconnectionSqlCodes);
797
798
799 final HashSet<String> disconnectionIgnoreSqlCodes = new HashSet<>(Arrays.asList("YYY", "AAA"));
800 ds.setDisconnectionIgnoreSqlCodes(disconnectionIgnoreSqlCodes);
801
802 assertEquals(disconnectionSqlCodes, ds.getDisconnectionSqlCodes(), "Disconnection SQL codes should match the set values.");
803 assertEquals(disconnectionIgnoreSqlCodes, ds.getDisconnectionIgnoreSqlCodes(), "Disconnection Ignore SQL codes should match the set values.");
804 }
805
806 @Test
807 public void testOverlapBetweenDisconnectionAndIgnoreSqlCodes() {
808
809 final HashSet<String> disconnectionSqlCodes = new HashSet<>(Arrays.asList("XXX", "ZZZ"));
810 ds.setDisconnectionSqlCodes(disconnectionSqlCodes);
811
812 final HashSet<String> disconnectionIgnoreSqlCodes = new HashSet<>(Arrays.asList("YYY", "XXX"));
813
814 final IllegalArgumentException exception = assertThrows(IllegalArgumentException.class,
815 () -> ds.setDisconnectionIgnoreSqlCodes(disconnectionIgnoreSqlCodes));
816 assertEquals("[XXX] cannot be in both disconnectionSqlCodes and disconnectionIgnoreSqlCodes.", exception.getMessage());
817 }
818
819
820
821
822
823
824 @Test
825 public void testPoolCloseCheckedException() throws Exception {
826 ds.setAccessToUnderlyingConnectionAllowed(true);
827
828 final TesterConnection tc;
829
830 try (Connection conn = ds.getConnection()) {
831 tc = (TesterConnection) ((DelegatingConnection<?>) conn).getInnermostDelegate();
832 }
833
834
835
836 tc.setFailure(new SQLException("bang"));
837
838
839
840
841 try {
842 StackMessageLog.lock();
843 StackMessageLog.clear();
844 ds.close();
845
846 final String message = StackMessageLog.popMessage();
847 Assertions.assertNotNull(message);
848 assertTrue(message.indexOf("bang") > 0);
849 } catch (final SQLException ex) {
850 assertTrue(ex.getMessage().indexOf("Cannot close") > 0);
851 assertTrue(ex.getCause().getMessage().indexOf("bang") > 0);
852 } finally {
853 StackMessageLog.unLock();
854 }
855 }
856
857 @Test
858 public void testPoolCloseRTE() throws Exception {
859
860 ds.setAccessToUnderlyingConnectionAllowed(true);
861 final TesterConnection tc;
862 try (Connection conn = ds.getConnection()) {
863 tc = (TesterConnection) ((DelegatingConnection<?>) conn).getInnermostDelegate();
864 }
865 tc.setFailure(new IllegalStateException("boom"));
866 try {
867 StackMessageLog.lock();
868 StackMessageLog.clear();
869 ds.close();
870 final String message = StackMessageLog.popMessage();
871 Assertions.assertNotNull(message);
872 assertTrue(message.indexOf("boom") > 0);
873 } catch (final IllegalStateException ex) {
874 assertTrue(ex.getMessage().indexOf("boom") > 0);
875 } finally {
876 StackMessageLog.unLock();
877 }
878 }
879
880 @Override
881 @Test
882 public void testPooling() throws Exception {
883
884 ds.setAccessToUnderlyingConnectionAllowed(true);
885 super.testPooling();
886 }
887
888
889
890
891
892
893 @Test
894 public void testPropertyTestOnReturn() throws Exception {
895 ds.setValidationQuery("select 1 from dual");
896 ds.setTestOnBorrow(false);
897 ds.setTestWhileIdle(false);
898 ds.setTestOnReturn(true);
899
900 try (Connection conn = ds.getConnection()) {
901 assertNotNull(conn);
902
903 assertFalse(ds.getConnectionPool().getTestOnBorrow());
904 assertFalse(ds.getConnectionPool().getTestWhileIdle());
905 assertTrue(ds.getConnectionPool().getTestOnReturn());
906 }
907 }
908
909 @Test
910 public void testRestart() throws Exception {
911 ds.setMaxTotal(2);
912 ds.setDurationBetweenEvictionRuns(Duration.ofMillis(100));
913 ds.setNumTestsPerEvictionRun(2);
914 ds.setMinEvictableIdle(Duration.ofMinutes(1));
915 ds.setInitialSize(2);
916 ds.setDefaultCatalog("foo");
917 try (Connection conn1 = ds.getConnection()) {
918 Thread.sleep(200);
919
920 ds.setDefaultCatalog("bar");
921 ds.setInitialSize(1);
922
923 ds.restart();
924 assertEquals("bar", ds.getDefaultCatalog());
925 assertEquals(1, ds.getInitialSize());
926 ds.getLogWriter();
927 assertEquals(0, ds.getNumActive());
928 assertEquals(1, ds.getNumIdle());
929 }
930
931 assertEquals(1, ds.getNumIdle());
932 ds.close();
933 }
934
935
936
937
938
939
940 @Test
941 public void testRollbackReadOnly() throws Exception {
942 ds.setDefaultReadOnly(Boolean.TRUE);
943 ds.setDefaultAutoCommit(Boolean.FALSE);
944
945 try (Connection conn = ds.getConnection()) {
946 assertNotNull(conn);
947 }
948 }
949
950 @Test
951 public void testSetAutoCommitTrueOnClose() throws Exception {
952 ds.setAccessToUnderlyingConnectionAllowed(true);
953 ds.setDefaultAutoCommit(Boolean.FALSE);
954 final Connection dconn;
955 try (Connection conn = getConnection()) {
956 assertNotNull(conn);
957 assertFalse(conn.getAutoCommit());
958
959 dconn = ((DelegatingConnection<?>) conn).getInnermostDelegate();
960 assertNotNull(dconn);
961 assertFalse(dconn.getAutoCommit());
962
963 }
964
965 assertTrue(dconn.getAutoCommit());
966 }
967
968 @Test
969 public void testSetProperties() throws Exception {
970
971 ds.setConnectionProperties("name1=value1;name2=value2;name3=value3");
972 assertEquals(3, ds.getConnectionProperties().size());
973 assertEquals("value1", ds.getConnectionProperties().getProperty("name1"));
974 assertEquals("value2", ds.getConnectionProperties().getProperty("name2"));
975 assertEquals("value3", ds.getConnectionProperties().getProperty("name3"));
976
977
978 ds.setConnectionProperties("name1=value1;name2=value2");
979 assertEquals(2, ds.getConnectionProperties().size());
980 assertEquals("value1", ds.getConnectionProperties().getProperty("name1"));
981 assertEquals("value2", ds.getConnectionProperties().getProperty("name2"));
982 assertFalse(ds.getConnectionProperties().containsKey("name3"));
983
984
985 ds.setConnectionProperties("name1=value1;name2");
986 assertEquals(2, ds.getConnectionProperties().size());
987 assertEquals("value1", ds.getConnectionProperties().getProperty("name1"));
988 assertEquals("", ds.getConnectionProperties().getProperty("name2"));
989
990
991 ds.setConnectionProperties("name1=value1;name2=");
992 assertEquals(2, ds.getConnectionProperties().size());
993 assertEquals("value1", ds.getConnectionProperties().getProperty("name1"));
994 assertEquals("", ds.getConnectionProperties().getProperty("name2"));
995
996
997 ds.setConnectionProperties("name1=value1");
998 assertEquals(1, ds.getConnectionProperties().size());
999 assertEquals("value1", ds.getConnectionProperties().getProperty("name1"));
1000
1001
1002 ds.setConnectionProperties("name1=value1;");
1003 assertEquals(1, ds.getConnectionProperties().size());
1004 assertEquals("value1", ds.getConnectionProperties().getProperty("name1"));
1005
1006
1007 ds.setConnectionProperties("name1");
1008 assertEquals(1, ds.getConnectionProperties().size());
1009 assertEquals("", ds.getConnectionProperties().getProperty("name1"));
1010
1011
1012 assertThrows(NullPointerException.class, () -> ds.setConnectionProperties(null));
1013 }
1014
1015 @Test
1016 public void testSetValidationTestProperties() {
1017
1018 assertTrue(ds.getTestOnBorrow());
1019 assertFalse(ds.getTestOnReturn());
1020 assertFalse(ds.getTestWhileIdle());
1021
1022 ds.setTestOnBorrow(true);
1023 ds.setTestOnReturn(true);
1024 ds.setTestWhileIdle(true);
1025 assertTrue(ds.getTestOnBorrow());
1026 assertTrue(ds.getTestOnReturn());
1027 assertTrue(ds.getTestWhileIdle());
1028
1029 ds.setTestOnBorrow(false);
1030 ds.setTestOnReturn(false);
1031 ds.setTestWhileIdle(false);
1032 assertFalse(ds.getTestOnBorrow());
1033 assertFalse(ds.getTestOnReturn());
1034 assertFalse(ds.getTestWhileIdle());
1035 }
1036
1037 @Test
1038 public void testStart() throws Exception {
1039 ds.setAccessToUnderlyingConnectionAllowed(true);
1040 ds.setMaxTotal(2);
1041 final DelegatingConnection<?> conn1 = (DelegatingConnection<?>) ds.getConnection();
1042 final DelegatingConnection<?> conn2 = (DelegatingConnection<?>) ds.getConnection();
1043 final Connection inner1 = conn1.getInnermostDelegate();
1044 final Connection inner2 = conn2.getInnermostDelegate();
1045 assertFalse(inner2.isClosed());
1046 conn2.close();
1047 assertFalse(inner2.isClosed());
1048
1049 ds.close();
1050
1051 assertFalse(conn1.isClosed());
1052 assertTrue(inner2.isClosed());
1053 assertEquals(0, ds.getNumIdle());
1054
1055
1056 ds.start();
1057 final Connection conn3 = ds.getConnection();
1058 final Connection conn4 = ds.getConnection();
1059 conn3.close();
1060 conn4.close();
1061
1062
1063 conn1.close();
1064 assertTrue(inner1.isClosed());
1065 }
1066
1067 @Test
1068 public void testStartInitializes() throws Exception {
1069 ds.setInitialSize(2);
1070
1071 assertEquals(0, ds.getNumIdle());
1072 assertNull(ds.getRegisteredJmxName());
1073
1074
1075 ds.start();
1076 assertEquals(2, ds.getNumIdle());
1077 assertNotNull(ds.getRegisteredJmxName());
1078 }
1079
1080 @Test
1081 public void testTransactionIsolationBehavior() throws Exception {
1082 try (final Connection conn = getConnection()) {
1083 assertNotNull(conn);
1084 assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn.getTransactionIsolation());
1085 conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
1086 }
1087
1088 final Connection conn2 = getConnection();
1089 assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn2.getTransactionIsolation());
1090
1091 final Connection conn3 = getConnection();
1092 assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn3.getTransactionIsolation());
1093
1094 conn2.close();
1095
1096 conn3.close();
1097 }
1098
1099 @Test
1100 public void testUnwrap() throws Exception {
1101 assertSame(ds.unwrap(BasicDataSource.class), ds);
1102 assertSame(ds.unwrap(AutoCloseable.class), ds);
1103 assertThrows(SQLException.class, () -> ds.unwrap(String.class));
1104 assertThrows(SQLException.class, () -> ds.unwrap(null));
1105 }
1106
1107 @Test
1108 public void testValidationQueryTimeoutNegative() throws Exception {
1109 ds.setTestOnBorrow(true);
1110 ds.setTestOnReturn(true);
1111 ds.setValidationQueryTimeout(Duration.ofSeconds(-1));
1112 try (final Connection con = ds.getConnection()) {
1113
1114 }
1115 }
1116
1117 @Test
1118 public void testValidationQueryTimeoutSucceed() throws Exception {
1119 ds.setTestOnBorrow(true);
1120 ds.setTestOnReturn(true);
1121 ds.setValidationQueryTimeout(Duration.ofMillis(100));
1122 try (final Connection con = ds.getConnection()) {
1123
1124 }
1125 }
1126
1127 @Test
1128 public void testValidationQueryTimeoutZero() throws Exception {
1129 ds.setTestOnBorrow(true);
1130 ds.setTestOnReturn(true);
1131 ds.setValidationQueryTimeout(Duration.ZERO);
1132 try (final Connection con = ds.getConnection()) {
1133
1134 }
1135 }
1136
1137 @Test
1138 public void testValidationQueryTimoutFail() {
1139 ds.setTestOnBorrow(true);
1140 ds.setValidationQueryTimeout(Duration.ofSeconds(3));
1141 final SQLException e = assertThrows(SQLException.class, ds::getConnection);
1142 assertTrue(e.toString().contains("timeout"));
1143 }
1144 }
1145
1146
1147
1148
1149
1150 final class TesterConnectionDelayDriver extends TesterDriver {
1151 private static final String CONNECT_STRING = "jdbc:apache:commons:testerConnectionDelayDriver";
1152
1153 public TesterConnectionDelayDriver() {
1154
1155 }
1156
1157 @Override
1158 public boolean acceptsURL(final String url) throws SQLException {
1159 return url.startsWith(CONNECT_STRING);
1160 }
1161
1162 @Override
1163 public Connection connect(final String url, final Properties info) throws SQLException {
1164 final String[] parsedUrl = url.split(":");
1165 final int delay = Integer.parseInt(parsedUrl[parsedUrl.length - 1]);
1166 try {
1167 Thread.sleep(delay);
1168 } catch (final InterruptedException ex) {
1169 Thread.currentThread().interrupt();
1170 }
1171 return super.connect(url, info);
1172 }
1173
1174 }
1175
1176
1177
1178
1179 final class TesterConnRequestCountDriver extends TesterDriver {
1180 private static final String CONNECT_STRING = "jdbc:apache:commons:testerConnRequestCountDriver";
1181 private static final AtomicInteger connectionRequestCount = new AtomicInteger();
1182
1183 public static int getConnectionRequestCount() {
1184 return connectionRequestCount.get();
1185 }
1186
1187 public static void initConnRequestCount() {
1188 connectionRequestCount.set(0);
1189 }
1190
1191 public TesterConnRequestCountDriver() {
1192
1193 }
1194
1195 @Override
1196 public boolean acceptsURL(final String url) throws SQLException {
1197 return CONNECT_STRING.startsWith(url);
1198 }
1199
1200 @Override
1201 public Connection connect(final String url, final Properties info) throws SQLException {
1202 connectionRequestCount.incrementAndGet();
1203 return super.connect(url, info);
1204 }
1205 }