1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.pool2.impl;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
22 import static org.junit.jupiter.api.Assertions.assertNotEquals;
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.assertThrows;
26 import static org.junit.jupiter.api.Assertions.assertTrue;
27 import static org.junit.jupiter.api.Assertions.fail;
28
29 import java.io.Serializable;
30 import java.lang.management.ManagementFactory;
31 import java.lang.ref.WeakReference;
32 import java.nio.charset.UnsupportedCharsetException;
33 import java.time.Duration;
34 import java.time.Instant;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.HashSet;
38 import java.util.List;
39 import java.util.NoSuchElementException;
40 import java.util.Objects;
41 import java.util.Random;
42 import java.util.Set;
43 import java.util.Timer;
44 import java.util.TimerTask;
45 import java.util.concurrent.CountDownLatch;
46 import java.util.concurrent.ExecutorService;
47 import java.util.concurrent.Executors;
48 import java.util.concurrent.FutureTask;
49 import java.util.concurrent.Semaphore;
50 import java.util.concurrent.TimeUnit;
51 import java.util.concurrent.atomic.AtomicBoolean;
52 import java.util.concurrent.atomic.AtomicInteger;
53
54 import javax.management.MBeanServer;
55 import javax.management.ObjectName;
56
57 import org.apache.commons.lang3.ThreadUtils;
58 import org.apache.commons.lang3.function.Suppliers;
59 import org.apache.commons.lang3.time.DurationUtils;
60 import org.apache.commons.pool2.BasePooledObjectFactory;
61 import org.apache.commons.pool2.ObjectPool;
62 import org.apache.commons.pool2.PoolUtils;
63 import org.apache.commons.pool2.PooledObject;
64 import org.apache.commons.pool2.PooledObjectFactory;
65 import org.apache.commons.pool2.SwallowedExceptionListener;
66 import org.apache.commons.pool2.TestBaseObjectPool;
67 import org.apache.commons.pool2.VisitTracker;
68 import org.apache.commons.pool2.VisitTrackerFactory;
69 import org.apache.commons.pool2.Waiter;
70 import org.apache.commons.pool2.WaiterFactory;
71 import org.junit.jupiter.api.AfterEach;
72 import org.junit.jupiter.api.BeforeEach;
73 import org.junit.jupiter.api.Disabled;
74 import org.junit.jupiter.api.Test;
75 import org.junit.jupiter.api.Timeout;
76
77
78
79 class TestGenericObjectPool extends TestBaseObjectPool {
80 private final class ConcurrentBorrowAndEvictThread extends Thread {
81 private final boolean borrow;
82 String obj;
83
84 private ConcurrentBorrowAndEvictThread(final boolean borrow) {
85 this.borrow = borrow;
86 }
87
88 @Override
89 public void run() {
90 try {
91 if (borrow) {
92 obj = genericObjectPool.borrowObject();
93 } else {
94 genericObjectPool.evict();
95 }
96 } catch (final Exception e) {
97
98 }
99 }
100 }
101
102 private static final class CreateErrorFactory extends BasePooledObjectFactory<String> {
103 private final Semaphore semaphore = new Semaphore(0);
104
105 @Override
106 public String create() throws InterruptedException {
107 semaphore.acquire();
108 throw new UnknownError("wiggle");
109 }
110
111 public boolean hasQueuedThreads() {
112 return semaphore.hasQueuedThreads();
113 }
114
115 public void release() {
116 semaphore.release();
117 }
118
119 @Override
120 public PooledObject<String> wrap(final String obj) {
121 return new DefaultPooledObject<>(obj);
122 }
123 }
124
125 private static final class CreateFailFactory extends BasePooledObjectFactory<String> {
126 private final Semaphore semaphore = new Semaphore(0);
127
128 @Override
129 public String create() throws InterruptedException {
130 semaphore.acquire();
131 throw new UnsupportedCharsetException("wibble");
132 }
133
134 public boolean hasQueuedThreads() {
135 return semaphore.hasQueuedThreads();
136 }
137
138 public void release() {
139 semaphore.release();
140 }
141
142 @Override
143 public PooledObject<String> wrap(final String obj) {
144 return new DefaultPooledObject<>(obj);
145 }
146 }
147
148 private static final class DummyFactory extends BasePooledObjectFactory<Object> {
149 @Override
150 public Object create() {
151 return null;
152 }
153
154 @Override
155 public PooledObject<Object> wrap(final Object value) {
156 return new DefaultPooledObject<>(value);
157 }
158 }
159
160 private static final class EvictionThread<T> extends Thread {
161 private final GenericObjectPool<T> pool;
162
163 private EvictionThread(final GenericObjectPool<T> pool) {
164 this.pool = pool;
165 }
166
167 @Override
168 public void run() {
169 try {
170 pool.evict();
171 } catch (final Exception e) {
172
173 }
174 }
175 }
176
177
178
179
180
181 private static final class HashSetFactory extends BasePooledObjectFactory<HashSet<String>> {
182 @Override
183 public HashSet<String> create() {
184 return new HashSet<>();
185 }
186
187 @Override
188 public PooledObject<HashSet<String>> wrap(final HashSet<String> value) {
189 return new DefaultPooledObject<>(value);
190 }
191 }
192
193
194
195
196 private static class InvalidateThread implements Runnable {
197 private final String obj;
198 private final ObjectPool<String> pool;
199 private boolean done;
200
201 private InvalidateThread(final ObjectPool<String> pool, final String obj) {
202 this.obj = obj;
203 this.pool = pool;
204 }
205
206 private boolean complete() {
207 return done;
208 }
209
210 @Override
211 public void run() {
212 try {
213 pool.invalidateObject(obj);
214 } catch (final IllegalStateException ex) {
215
216 } catch (final Exception ex) {
217 fail("Unexpected exception " + ex.toString());
218 } finally {
219 done = true;
220 }
221 }
222 }
223
224 private static final class InvalidFactory extends BasePooledObjectFactory<Object> {
225 @Override
226 public Object create() {
227 return new Object();
228 }
229
230 @Override
231 public boolean validateObject(final PooledObject<Object> obj) {
232 Waiter.sleepQuietly(1000);
233 return false;
234 }
235
236 @Override
237 public PooledObject<Object> wrap(final Object value) {
238 return new DefaultPooledObject<>(value);
239 }
240 }
241
242 static class SimpleFactory implements PooledObjectFactory<String> {
243 int makeCounter;
244 int activationCounter;
245 int validateCounter;
246 int activeCount;
247 boolean evenValid = true;
248 boolean oddValid = true;
249 boolean exceptionOnPassivate;
250 boolean exceptionOnActivate;
251 boolean exceptionOnDestroy;
252 boolean exceptionOnValidate;
253 boolean enableValidation = true;
254 long destroyLatency;
255 long makeLatency;
256 long validateLatency;
257 int maxTotal = Integer.MAX_VALUE;
258
259 SimpleFactory() {
260 this(true);
261 }
262
263 SimpleFactory(final boolean valid) {
264 this(valid, valid);
265 }
266
267 SimpleFactory(final boolean evalid, final boolean ovalid) {
268 evenValid = evalid;
269 oddValid = ovalid;
270 }
271
272 @Override
273 public void activateObject(final PooledObject<String> obj) throws Exception {
274 final boolean hurl;
275 final boolean evenTest;
276 final boolean oddTest;
277 final int counter;
278 synchronized (this) {
279 hurl = exceptionOnActivate;
280 evenTest = evenValid;
281 oddTest = oddValid;
282 counter = activationCounter++;
283 }
284 if (hurl && !(counter % 2 == 0 ? evenTest : oddTest)) {
285 throw new Exception();
286 }
287 }
288
289 @Override
290 public void destroyObject(final PooledObject<String> obj) throws Exception {
291 final long waitLatency;
292 final boolean hurl;
293 synchronized (this) {
294 waitLatency = destroyLatency;
295 hurl = exceptionOnDestroy;
296 }
297 if (waitLatency > 0) {
298 doWait(waitLatency);
299 }
300 synchronized (this) {
301 activeCount--;
302 }
303 if (hurl) {
304 throw new Exception();
305 }
306 }
307
308 private void doWait(final long latency) {
309 Waiter.sleepQuietly(latency);
310 }
311
312 synchronized int getMakeCounter() {
313 return makeCounter;
314 }
315
316 synchronized boolean isThrowExceptionOnActivate() {
317 return exceptionOnActivate;
318 }
319
320 synchronized boolean isValidationEnabled() {
321 return enableValidation;
322 }
323
324 @Override
325 public PooledObject<String> makeObject() {
326 final long waitLatency;
327 synchronized (this) {
328 activeCount++;
329 if (activeCount > maxTotal) {
330 throw new IllegalStateException("Too many active instances: " + activeCount);
331 }
332 waitLatency = makeLatency;
333 }
334 if (waitLatency > 0) {
335 doWait(waitLatency);
336 }
337 final int counter;
338 synchronized (this) {
339 counter = makeCounter++;
340 }
341 return new DefaultPooledObject<>(String.valueOf(counter));
342 }
343
344 @Override
345 public void passivateObject(final PooledObject<String> obj) throws Exception {
346 final boolean hurl;
347 synchronized (this) {
348 hurl = exceptionOnPassivate;
349 }
350 if (hurl) {
351 throw new Exception();
352 }
353 }
354
355 synchronized void setDestroyLatency(final long destroyLatency) {
356 this.destroyLatency = destroyLatency;
357 }
358
359 synchronized void setEvenValid(final boolean valid) {
360 evenValid = valid;
361 }
362
363 synchronized void setMakeLatency(final long makeLatency) {
364 this.makeLatency = makeLatency;
365 }
366
367 synchronized void setMaxTotal(final int maxTotal) {
368 this.maxTotal = maxTotal;
369 }
370
371 synchronized void setOddValid(final boolean valid) {
372 oddValid = valid;
373 }
374
375 synchronized void setThrowExceptionOnActivate(final boolean b) {
376 exceptionOnActivate = b;
377 }
378
379 synchronized void setThrowExceptionOnDestroy(final boolean b) {
380 exceptionOnDestroy = b;
381 }
382
383 synchronized void setThrowExceptionOnPassivate(final boolean bool) {
384 exceptionOnPassivate = bool;
385 }
386
387 synchronized void setThrowExceptionOnValidate(final boolean bool) {
388 exceptionOnValidate = bool;
389 }
390
391 synchronized void setValid(final boolean valid) {
392 setEvenValid(valid);
393 setOddValid(valid);
394 }
395
396 synchronized void setValidateLatency(final long validateLatency) {
397 this.validateLatency = validateLatency;
398 }
399
400 synchronized void setValidationEnabled(final boolean b) {
401 enableValidation = b;
402 }
403
404 @Override
405 public boolean validateObject(final PooledObject<String> obj) {
406 final boolean validate;
407 final boolean throwException;
408 final boolean evenTest;
409 final boolean oddTest;
410 final long waitLatency;
411 final int counter;
412 synchronized (this) {
413 validate = enableValidation;
414 throwException = exceptionOnValidate;
415 evenTest = evenValid;
416 oddTest = oddValid;
417 counter = validateCounter++;
418 waitLatency = validateLatency;
419 }
420 if (waitLatency > 0) {
421 doWait(waitLatency);
422 }
423 if (throwException) {
424 throw new RuntimeException("validation failed");
425 }
426 if (validate) {
427 return counter % 2 == 0 ? evenTest : oddTest;
428 }
429 return true;
430 }
431 }
432
433
434
435
436
437
438 public static class TestEvictionPolicy<T> implements EvictionPolicy<T> {
439 private final AtomicInteger callCount = new AtomicInteger();
440
441 @Override
442 public boolean evict(final EvictionConfig config, final PooledObject<T> underTest, final int idleCount) {
443 return callCount.incrementAndGet() > 1500;
444 }
445 }
446
447 private static class TestThread<T> implements Runnable {
448
449 private final Random random;
450
451 private final ObjectPool<T> pool;
452
453 private final int iter;
454
455 private final int startDelay;
456
457 private final int holdTime;
458
459 private final boolean randomDelay;
460
461 private final Object expectedObject;
462 private volatile boolean complete;
463 private volatile boolean failed;
464 private volatile Throwable error;
465
466 private TestThread(final ObjectPool<T> pool) {
467 this(pool, 100, 50, true, null);
468 }
469
470 private TestThread(final ObjectPool<T> pool, final int iter) {
471 this(pool, iter, 50, true, null);
472 }
473
474 private TestThread(final ObjectPool<T> pool, final int iter, final int delay) {
475 this(pool, iter, delay, true, null);
476 }
477
478 private TestThread(final ObjectPool<T> pool, final int iter, final int delay, final boolean randomDelay) {
479 this(pool, iter, delay, randomDelay, null);
480 }
481
482 private TestThread(final ObjectPool<T> pool, final int iter, final int delay, final boolean randomDelay, final Object obj) {
483 this(pool, iter, delay, delay, randomDelay, obj);
484 }
485
486 private TestThread(final ObjectPool<T> pool, final int iter, final int startDelay, final int holdTime, final boolean randomDelay, final Object obj) {
487 this.pool = pool;
488 this.iter = iter;
489 this.startDelay = startDelay;
490 this.holdTime = holdTime;
491 this.randomDelay = randomDelay;
492 this.random = this.randomDelay ? new Random() : null;
493 this.expectedObject = obj;
494 }
495
496 private boolean complete() {
497 return complete;
498 }
499
500 private boolean failed() {
501 return failed;
502 }
503
504 @Override
505 public void run() {
506 for (int i = 0; i < iter; i++) {
507 final long actualStartDelay = randomDelay ? (long) random.nextInt(startDelay) : startDelay;
508 final long actualHoldTime = randomDelay ? (long) random.nextInt(holdTime) : holdTime;
509 Waiter.sleepQuietly(actualStartDelay);
510 T obj = null;
511 try {
512 obj = pool.borrowObject();
513 } catch (final Exception e) {
514 error = e;
515 failed = true;
516 complete = true;
517 break;
518 }
519 if (expectedObject != null && !expectedObject.equals(obj)) {
520 error = new Throwable("Expected: " + expectedObject + " found: " + obj);
521 failed = true;
522 complete = true;
523 break;
524 }
525 Waiter.sleepQuietly(actualHoldTime);
526 try {
527 pool.returnObject(obj);
528 } catch (final Exception e) {
529 error = e;
530 failed = true;
531 complete = true;
532 break;
533 }
534 }
535 complete = true;
536 }
537 }
538
539
540
541
542 private static class WaitingTestThread extends Thread {
543 private final GenericObjectPool<String> pool;
544 private final long pause;
545 private Throwable thrown;
546 private long preBorrowMillis;
547 private long postBorrowMillis;
548 private long postReturnMillis;
549 private long endedMillis;
550 private String objectId;
551
552 private WaitingTestThread(final GenericObjectPool<String> pool, final long pause) {
553 this.pool = pool;
554 this.pause = pause;
555 this.thrown = null;
556 }
557
558 @Override
559 public void run() {
560 try {
561 preBorrowMillis = System.currentTimeMillis();
562 final String obj = pool.borrowObject();
563 objectId = obj;
564 postBorrowMillis = System.currentTimeMillis();
565 Thread.sleep(pause);
566 pool.returnObject(obj);
567 postReturnMillis = System.currentTimeMillis();
568 } catch (final Throwable e) {
569 thrown = e;
570 } finally {
571 endedMillis = System.currentTimeMillis();
572 }
573 }
574 }
575
576
577
578
579 private static final boolean DISPLAY_THREAD_DETAILS = Boolean.getBoolean("TestGenericObjectPool.display.thread.details");
580 private GenericObjectPool<String> genericObjectPool;
581 private SimpleFactory simpleFactory;
582
583 @SuppressWarnings("deprecation")
584 private void assertConfiguration(final GenericObjectPoolConfig<?> expected, final GenericObjectPool<?> actual) {
585 assertEquals(Boolean.valueOf(expected.getTestOnCreate()), Boolean.valueOf(actual.getTestOnCreate()), "testOnCreate");
586 assertEquals(Boolean.valueOf(expected.getTestOnBorrow()), Boolean.valueOf(actual.getTestOnBorrow()), "testOnBorrow");
587 assertEquals(Boolean.valueOf(expected.getTestOnReturn()), Boolean.valueOf(actual.getTestOnReturn()), "testOnReturn");
588 assertEquals(Boolean.valueOf(expected.getTestWhileIdle()), Boolean.valueOf(actual.getTestWhileIdle()), "testWhileIdle");
589 assertEquals(Boolean.valueOf(expected.getBlockWhenExhausted()), Boolean.valueOf(actual.getBlockWhenExhausted()), "whenExhaustedAction");
590 assertEquals(expected.getMaxTotal(), actual.getMaxTotal(), "maxTotal");
591 assertEquals(expected.getMaxIdle(), actual.getMaxIdle(), "maxIdle");
592 assertEquals(expected.getMaxWaitMillis(), actual.getMaxWaitMillis(), "maxWaitDuration");
593 assertEquals(expected.getMaxWaitDuration(), actual.getMaxWaitDuration(), "maxWaitDuration");
594 assertEquals(expected.getMinEvictableIdleTimeMillis(), actual.getMinEvictableIdleTimeMillis(), "minEvictableIdleTimeMillis");
595 assertEquals(expected.getMinEvictableIdleTime(), actual.getMinEvictableIdleTime(), "minEvictableIdleTime");
596 assertEquals(expected.getMinEvictableIdleDuration(), actual.getMinEvictableIdleDuration(), "minEvictableIdleDuration");
597 assertEquals(expected.getNumTestsPerEvictionRun(), actual.getNumTestsPerEvictionRun(), "numTestsPerEvictionRun");
598 assertEquals(expected.getEvictorShutdownTimeoutDuration(), actual.getEvictorShutdownTimeoutDuration(), "evictorShutdownTimeoutDuration");
599 assertEquals(expected.getEvictorShutdownTimeoutMillis(), actual.getEvictorShutdownTimeoutMillis(), "evictorShutdownTimeoutMillis");
600 assertEquals(expected.getEvictorShutdownTimeout(), actual.getEvictorShutdownTimeout(), "evictorShutdownTimeout");
601 assertEquals(expected.getTimeBetweenEvictionRunsMillis(), actual.getTimeBetweenEvictionRunsMillis(), "timeBetweenEvictionRunsMillis");
602 assertEquals(expected.getDurationBetweenEvictionRuns(), actual.getTimeBetweenEvictionRuns(), "timeBetweenEvictionRuns");
603 assertEquals(expected.getTimeBetweenEvictionRuns(), actual.getTimeBetweenEvictionRuns(), "timeBetweenEvictionRuns");
604 }
605
606 private void checkEvict(final boolean lifo) throws Exception {
607
608 genericObjectPool.setSoftMinEvictableIdleDuration(Duration.ofMillis(10));
609 genericObjectPool.setSoftMinEvictableIdle(Duration.ofMillis(10));
610 genericObjectPool.setSoftMinEvictableIdleTime(Duration.ofMillis(10));
611 genericObjectPool.setMinIdle(2);
612 genericObjectPool.setTestWhileIdle(true);
613 genericObjectPool.setLifo(lifo);
614 genericObjectPool.addObjects(5);
615 genericObjectPool.evict();
616 simpleFactory.setEvenValid(false);
617 simpleFactory.setOddValid(false);
618 simpleFactory.setThrowExceptionOnActivate(true);
619 genericObjectPool.evict();
620 genericObjectPool.addObjects(5);
621 simpleFactory.setThrowExceptionOnActivate(false);
622 simpleFactory.setThrowExceptionOnPassivate(true);
623 genericObjectPool.evict();
624 simpleFactory.setThrowExceptionOnPassivate(false);
625 simpleFactory.setEvenValid(true);
626 simpleFactory.setOddValid(true);
627 Thread.sleep(125);
628 genericObjectPool.evict();
629 assertEquals(2, genericObjectPool.getNumIdle());
630 }
631
632 private void checkEvictionOrder(final boolean lifo) throws Exception {
633 checkEvictionOrderPart1(lifo);
634 tearDown();
635 setUp();
636 checkEvictionOrderPart2(lifo);
637 }
638
639 private void checkEvictionOrderPart1(final boolean lifo) throws Exception {
640 genericObjectPool.setNumTestsPerEvictionRun(2);
641 genericObjectPool.setMinEvictableIdleTime(Duration.ofMillis(100));
642 genericObjectPool.setLifo(lifo);
643 for (int i = 0; i < 5; i++) {
644 genericObjectPool.addObject();
645 Thread.sleep(100);
646 }
647
648 genericObjectPool.evict();
649 final Object obj = genericObjectPool.borrowObject();
650 assertNotEquals("0", obj, "oldest not evicted");
651 assertNotEquals("1", obj, "second oldest not evicted");
652
653 assertEquals(lifo ? "4" : "2", obj, "Wrong instance returned");
654 }
655
656 private void checkEvictionOrderPart2(final boolean lifo) throws Exception {
657
658 genericObjectPool.setNumTestsPerEvictionRun(2);
659 genericObjectPool.setMinEvictableIdleTime(Duration.ofMillis(100));
660 genericObjectPool.setLifo(lifo);
661 for (int i = 0; i < 5; i++) {
662 genericObjectPool.addObject();
663 Thread.sleep(100);
664 }
665 genericObjectPool.evict();
666 genericObjectPool.evict();
667 final Object obj = genericObjectPool.borrowObject();
668 assertEquals("4", obj, "Wrong instance remaining in pool");
669 }
670
671 private void checkEvictorVisiting(final boolean lifo) throws Exception {
672 VisitTracker<Object> obj;
673 VisitTrackerFactory<Object> trackerFactory = new VisitTrackerFactory<>();
674 try (GenericObjectPool<VisitTracker<Object>> trackerPool = new GenericObjectPool<>(trackerFactory)) {
675 trackerPool.setNumTestsPerEvictionRun(2);
676 trackerPool.setMinEvictableIdleTime(Duration.ofMillis(-1));
677 trackerPool.setTestWhileIdle(true);
678 trackerPool.setLifo(lifo);
679 trackerPool.setTestOnReturn(false);
680 trackerPool.setTestOnBorrow(false);
681 for (int i = 0; i < 8; i++) {
682 trackerPool.addObject();
683 }
684 trackerPool.evict();
685 obj = trackerPool.borrowObject();
686 trackerPool.returnObject(obj);
687 obj = trackerPool.borrowObject();
688 trackerPool.returnObject(obj);
689
690
691
692 trackerPool.evict();
693 for (int i = 0; i < 8; i++) {
694 final VisitTracker<Object> tracker = trackerPool.borrowObject();
695 if (tracker.getId() >= 4) {
696 assertEquals(0, tracker.getValidateCount(), "Unexpected instance visited " + tracker.getId());
697 } else {
698 assertEquals(1, tracker.getValidateCount(), "Instance " + tracker.getId() + " visited wrong number of times.");
699 }
700 }
701 }
702 trackerFactory = new VisitTrackerFactory<>();
703 try (GenericObjectPool<VisitTracker<Object>> trackerPool = new GenericObjectPool<>(trackerFactory)) {
704 trackerPool.setNumTestsPerEvictionRun(3);
705 trackerPool.setMinEvictableIdleTime(Duration.ofMillis(-1));
706 trackerPool.setTestWhileIdle(true);
707 trackerPool.setLifo(lifo);
708 trackerPool.setTestOnReturn(false);
709 trackerPool.setTestOnBorrow(false);
710 for (int i = 0; i < 8; i++) {
711 trackerPool.addObject();
712 }
713 trackerPool.evict();
714 trackerPool.evict();
715 obj = trackerPool.borrowObject();
716 trackerPool.returnObject(obj);
717 obj = trackerPool.borrowObject();
718 trackerPool.returnObject(obj);
719 obj = trackerPool.borrowObject();
720 trackerPool.returnObject(obj);
721
722
723
724
725 trackerPool.evict();
726
727 for (int i = 0; i < 8; i++) {
728 final VisitTracker<Object> tracker = trackerPool.borrowObject();
729 if (tracker.getId() != 0) {
730 assertEquals(1, tracker.getValidateCount(), "Instance " + tracker.getId() + " visited wrong number of times.");
731 } else {
732 assertEquals(2, tracker.getValidateCount(), "Instance " + tracker.getId() + " visited wrong number of times.");
733 }
734 }
735 }
736
737
738 final int[] smallPrimes = { 2, 3, 5, 7 };
739 final Random random = new Random();
740 random.setSeed(System.currentTimeMillis());
741 for (int i = 0; i < 4; i++) {
742 for (int j = 0; j < 5; j++) {
743 try (GenericObjectPool<VisitTracker<Object>> trackerPool = new GenericObjectPool<>(trackerFactory)) {
744 trackerPool.setNumTestsPerEvictionRun(smallPrimes[i]);
745 trackerPool.setMinEvictableIdleTime(Duration.ofMillis(-1));
746 trackerPool.setTestWhileIdle(true);
747 trackerPool.setLifo(lifo);
748 trackerPool.setTestOnReturn(false);
749 trackerPool.setTestOnBorrow(false);
750 trackerPool.setMaxIdle(-1);
751 final int instanceCount = 10 + random.nextInt(20);
752 trackerPool.setMaxTotal(instanceCount);
753 trackerPool.setMaxIdle(instanceCount);
754 for (int k = 0; k < instanceCount; k++) {
755 trackerPool.addObject();
756 }
757
758 final int runs = 10 + random.nextInt(50);
759 for (int k = 0; k < runs; k++) {
760 trackerPool.evict();
761 }
762
763 final int cycleCount = runs * trackerPool.getNumTestsPerEvictionRun() / instanceCount;
764
765
766 VisitTracker<Object> tracker = null;
767 int visitCount = 0;
768 for (int k = 0; k < instanceCount; k++) {
769 tracker = trackerPool.borrowObject();
770 assertTrue(trackerPool.getNumActive() <= trackerPool.getMaxTotal());
771 visitCount = tracker.getValidateCount();
772 assertTrue(visitCount >= cycleCount && visitCount <= cycleCount + 1);
773 }
774 }
775 }
776 }
777 }
778
779 private BasePooledObjectFactory<String> createDefaultPooledObjectFactory() {
780 return new BasePooledObjectFactory<String>() {
781 @Override
782 public String create() {
783
784 return null;
785 }
786
787 @Override
788 public PooledObject<String> wrap(final String obj) {
789
790 return new DefaultPooledObject<>(obj);
791 }
792 };
793 }
794
795 private BasePooledObjectFactory<String> createNullPooledObjectFactory() {
796 return new BasePooledObjectFactory<String>() {
797 @Override
798 public String create() {
799
800 return null;
801 }
802
803 @Override
804 public PooledObject<String> wrap(final String obj) {
805
806 return null;
807 }
808 };
809 }
810
811 private BasePooledObjectFactory<Object> createPooledObjectFactory() {
812 return new BasePooledObjectFactory<Object>() {
813 @Override
814 public Object create() {
815 return new Object();
816 }
817
818 @Override
819 public PooledObject<Object> wrap(final Object obj) {
820 return new DefaultPooledObject<>(obj);
821 }
822 };
823 }
824
825 private BasePooledObjectFactory<String> createSlowObjectFactory(final Duration sleepDuration) {
826 return new BasePooledObjectFactory<String>() {
827 @Override
828 public String create() throws InterruptedException {
829 ThreadUtils.sleep(sleepDuration);
830 return "created";
831 }
832
833 @Override
834 public PooledObject<String> wrap(final String obj) {
835
836 return new DefaultPooledObject<>(obj);
837 }
838 };
839 }
840
841 @Override
842 protected Object getNthObject(final int n) {
843 return String.valueOf(n);
844 }
845
846 @Override
847 protected boolean isFifo() {
848 return false;
849 }
850
851 @Override
852 protected boolean isLifo() {
853 return true;
854 }
855
856 @Override
857 protected ObjectPool<String> makeEmptyPool(final int minCap) {
858 final GenericObjectPool<String> mtPool = new GenericObjectPool<>(new SimpleFactory());
859 mtPool.setMaxTotal(minCap);
860 mtPool.setMaxIdle(minCap);
861 return mtPool;
862 }
863
864 @Override
865 protected <E extends Exception> ObjectPool<Object> makeEmptyPool(final PooledObjectFactory<Object> fac) {
866 return new GenericObjectPool<>(fac);
867 }
868
869
870
871
872 private <T> void runTestThreads(final int numThreads, final int iterations, final int delay, final GenericObjectPool<T> testPool) {
873 final TestThread<T>[] threads = new TestThread[numThreads];
874 for (int i = 0; i < numThreads; i++) {
875 threads[i] = new TestThread<>(testPool, iterations, delay);
876 final Thread t = new Thread(threads[i]);
877 t.start();
878 }
879 for (int i = 0; i < numThreads; i++) {
880 while (!threads[i].complete()) {
881 Waiter.sleepQuietly(500L);
882 }
883 if (threads[i].failed()) {
884 fail("Thread " + i + " failed: " + threads[i].error.toString());
885 }
886 }
887 }
888
889 @BeforeEach
890 public void setUp() {
891 simpleFactory = new SimpleFactory();
892 genericObjectPool = new GenericObjectPool<>(simpleFactory);
893 }
894
895 @AfterEach
896 public void tearDown() throws Exception {
897 final ObjectName jmxName = genericObjectPool.getJmxName();
898 final String poolName = Objects.toString(jmxName, null);
899 genericObjectPool.clear();
900 genericObjectPool.close();
901 genericObjectPool = null;
902 simpleFactory = null;
903 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
904 final Set<ObjectName> result = mbs.queryNames(new ObjectName("org.apache.commoms.pool2:type=GenericObjectPool,*"), null);
905
906 final int registeredPoolCount = result.size();
907 final StringBuilder msg = new StringBuilder("Current pool is: ");
908 msg.append(poolName);
909 msg.append(" Still open pools are: ");
910 for (final ObjectName name : result) {
911
912 msg.append(name.toString());
913 msg.append(" created via\n");
914 msg.append(mbs.getAttribute(name, "CreationStackTrace"));
915 msg.append('\n');
916 mbs.unregisterMBean(name);
917 }
918 assertEquals(0, registeredPoolCount, msg.toString());
919
920 Thread.yield();
921 if (EvictionTimer.getExecutor() != null) {
922 Thread.sleep(1000);
923 }
924 assertNull(EvictionTimer.getExecutor(), "EvictionTimer.getExecutor()");
925 }
926
927
928
929
930
931
932
933
934
935 @SuppressWarnings("deprecation")
936 @Test
937 void testAbandonedPool() throws Exception {
938 final GenericObjectPoolConfig<String> config = new GenericObjectPoolConfig<>();
939 config.setJmxEnabled(false);
940
941
942
943
944 GenericObjectPool<String> abandoned1 = new GenericObjectPool<>(simpleFactory, config);
945 abandoned1.setDurationBetweenEvictionRuns(Duration.ofMillis(100));
946 GenericObjectPool<String> abandoned2 = new GenericObjectPool<>(simpleFactory, config);
947 abandoned2.setDurationBetweenEvictionRuns(Duration.ofMillis(100));
948
949
950 final WeakReference<GenericObjectPool<String>> ref1 = new WeakReference<>(abandoned1);
951 abandoned1 = null;
952 while (ref1.get() != null) {
953 System.gc();
954 Thread.sleep(100);
955 }
956 final WeakReference<GenericObjectPool<String>> ref2 = new WeakReference<>(abandoned2);
957 abandoned2 = null;
958 while (ref2.get() != null) {
959 System.gc();
960 Thread.sleep(100);
961 }
962 }
963
964 @Test
965 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
966 void testAddObject() throws Exception {
967 assertEquals(0, genericObjectPool.getNumIdle(), "should be zero idle");
968 genericObjectPool.addObject();
969 assertEquals(1, genericObjectPool.getNumIdle(), "should be one idle");
970 assertEquals(0, genericObjectPool.getNumActive(), "should be zero active");
971 final String obj = genericObjectPool.borrowObject();
972 assertEquals(0, genericObjectPool.getNumIdle(), "should be zero idle");
973 assertEquals(1, genericObjectPool.getNumActive(), "should be one active");
974 genericObjectPool.returnObject(obj);
975 assertEquals(1, genericObjectPool.getNumIdle(), "should be one idle");
976 assertEquals(0, genericObjectPool.getNumActive(), "should be zero active");
977 }
978
979 @Test
980 void testAddObjectCanAddToMaxIdle() throws Exception {
981 genericObjectPool.setMaxTotal(5);
982 genericObjectPool.borrowObject();
983 genericObjectPool.borrowObject();
984 genericObjectPool.setMaxIdle(3);
985 for (int i = 0; i < 3; i++) {
986 genericObjectPool.addObject();
987 }
988 assertEquals(3, genericObjectPool.getNumIdle());
989 }
990
991 @Test
992 @Timeout(value = 400, unit = TimeUnit.MILLISECONDS)
993 void testAddObjectFastReturn() throws Exception {
994 final SimpleFactory simpleFactory = new SimpleFactory();
995 simpleFactory.makeLatency = 500;
996 try (GenericObjectPool<String> pool = new GenericObjectPool<>(simpleFactory)) {
997 pool.setMaxTotal(1);
998 pool.setBlockWhenExhausted(true);
999 pool.setMaxWait(Duration.ofMillis(1000));
1000
1001 final TestThread<String> thread = new TestThread<>(pool);
1002 final Thread t = new Thread(thread);
1003 t.start();
1004 Thread.sleep(50);
1005 pool.addObject();
1006 }
1007 }
1008
1009 @Test
1010 void testAddObjectRespectsMaxIdle() throws Exception {
1011 genericObjectPool.setMaxIdle(1);
1012 genericObjectPool.addObject();
1013 genericObjectPool.addObject();
1014 assertEquals(1, genericObjectPool.getNumIdle());
1015 }
1016
1017 @Test
1018 void testAddObjectRespectsMaxTotal() throws Exception {
1019 genericObjectPool.setMaxTotal(1);
1020 genericObjectPool.addObject();
1021 genericObjectPool.addObject();
1022 assertEquals(1, genericObjectPool.getNumIdle());
1023 }
1024
1025 @Test
1026 void testAppendStats() {
1027 assertFalse(genericObjectPool.getMessageStatistics());
1028 assertEquals("foo", genericObjectPool.appendStats("foo"));
1029 try (GenericObjectPool<?> pool = new GenericObjectPool<>(new SimpleFactory())) {
1030 pool.setMessagesStatistics(true);
1031 assertNotEquals("foo", pool.appendStats("foo"));
1032 pool.setMessagesStatistics(false);
1033 assertEquals("foo", pool.appendStats("foo"));
1034 }
1035 }
1036
1037
1038
1039
1040
1041 @SuppressWarnings({ "rawtypes", "unchecked" })
1042 @Test
1043 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1044 void testBorrowObjectFairness() throws Exception {
1045 final int numThreads = 40;
1046 final int maxTotal = 40;
1047 final GenericObjectPoolConfig config = new GenericObjectPoolConfig();
1048 config.setMaxTotal(maxTotal);
1049 config.setMaxIdle(maxTotal);
1050 config.setFairness(true);
1051 config.setLifo(false);
1052 genericObjectPool = new GenericObjectPool(simpleFactory, config);
1053
1054 final String[] objects = new String[maxTotal];
1055 for (int i = 0; i < maxTotal; i++) {
1056 objects[i] = genericObjectPool.borrowObject();
1057 }
1058
1059 final TestThread[] threads = new TestThread[numThreads];
1060 for (int i = 0; i < numThreads; i++) {
1061 threads[i] = new TestThread(genericObjectPool, 1, 0, 2000, false, String.valueOf(i % maxTotal));
1062 final Thread t = new Thread(threads[i]);
1063 t.start();
1064
1065 try {
1066 Thread.sleep(10);
1067 } catch (final InterruptedException e) {
1068 fail(e.toString());
1069 }
1070 }
1071
1072 for (int i = 0; i < maxTotal; i++) {
1073 genericObjectPool.returnObject(objects[i]);
1074 }
1075
1076 for (int i = 0; i < numThreads; i++) {
1077 while (!threads[i].complete()) {
1078 Waiter.sleepQuietly(500L);
1079 }
1080 if (threads[i].failed()) {
1081 fail("Thread " + i + " failed: " + threads[i].error.toString());
1082 }
1083 }
1084 }
1085
1086 @Test
1087 @Timeout(value = 1200, unit = TimeUnit.MILLISECONDS)
1088 void testBorrowObjectOverrideMaxWaitLarge() throws Exception {
1089 try (GenericObjectPool<String> pool = new GenericObjectPool<>(createSlowObjectFactory(Duration.ofSeconds(60)))) {
1090 pool.setMaxTotal(1);
1091 pool.setMaxWait(Duration.ofMillis(1_000));
1092 pool.setBlockWhenExhausted(false);
1093
1094 final WaitingTestThread thread1 = new WaitingTestThread(pool, 0);
1095 thread1.start();
1096
1097 Thread.sleep(100);
1098
1099 final Duration d = DurationUtils.of(() -> assertThrows(NoSuchElementException.class, () -> pool.borrowObject(Duration.ofMillis(1)),
1100 "borrowObject must fail quickly due to timeout parameter"));
1101 final long millis = d.toMillis();
1102 final long nanos = d.toNanos();
1103 assertTrue(nanos >= 0, () -> "borrowObject(Duration) argument not respected: " + nanos);
1104 assertTrue(millis >= 0, () -> "borrowObject(Duration) argument not respected: " + millis);
1105 assertTrue(millis < 50, () -> "borrowObject(Duration) argument not respected: " + millis);
1106 }
1107 }
1108
1109 @Test
1110 @Timeout(value = 1200, unit = TimeUnit.MILLISECONDS)
1111 void testBorrowObjectOverrideMaxWaitSmall() throws Exception {
1112 try (GenericObjectPool<String> pool = new GenericObjectPool<>(createSlowObjectFactory(Duration.ofSeconds(60)))) {
1113 pool.setMaxTotal(1);
1114 pool.setMaxWait(Duration.ofMillis(1));
1115 pool.setBlockWhenExhausted(false);
1116
1117 final WaitingTestThread thread1 = new WaitingTestThread(pool, 0);
1118 thread1.start();
1119
1120 Thread.sleep(100);
1121
1122 final Duration d = DurationUtils.of(() -> assertThrows(NoSuchElementException.class, () -> pool.borrowObject(Duration.ofMillis(500)),
1123 "borrowObject must fail slowly due to timeout parameter"));
1124 final long millis = d.toMillis();
1125 final long nanos = d.toNanos();
1126 assertTrue(nanos >= 0, () -> "borrowObject(Duration) argument not respected: " + nanos);
1127 assertTrue(millis >= 0, () -> "borrowObject(Duration) argument not respected: " + millis);
1128 assertTrue(millis < 600, () -> "borrowObject(Duration) argument not respected: " + millis);
1129 assertTrue(millis > 490, () -> "borrowObject(Duration) argument not respected: " + millis);
1130 }
1131 }
1132
1133 @Test
1134 void testBorrowTimings() throws Exception {
1135
1136 final String object = genericObjectPool.borrowObject();
1137 final PooledObject<String> po = genericObjectPool.getPooledObject(object);
1138
1139
1140
1141
1142 final Instant lastBorrowInstant1 = po.getLastBorrowInstant();
1143 final Instant lastReturnInstant1 = po.getLastReturnInstant();
1144 final Instant lastUsedInstant1 = po.getLastUsedInstant();
1145 assertTrue(po.getCreateInstant().compareTo(lastBorrowInstant1) <= 0);
1146 assertTrue(po.getCreateInstant().compareTo(lastReturnInstant1) <= 0);
1147 assertTrue(po.getCreateInstant().compareTo(lastUsedInstant1) <= 0);
1148
1149 assertTrue(po.getCreateTime() <= lastBorrowInstant1.toEpochMilli());
1150 assertTrue(po.getCreateTime() <= lastReturnInstant1.toEpochMilli());
1151 assertTrue(po.getCreateTime() <= lastUsedInstant1.toEpochMilli());
1152
1153
1154 Thread.sleep(200);
1155 assertFalse(po.getActiveDuration().isNegative());
1156 assertFalse(po.getActiveDuration().isZero());
1157
1158 assertTrue(Duration.ZERO.compareTo(Duration.ZERO.plusNanos(1)) <= 0);
1159 assertTrue(po.getActiveDuration().compareTo(po.getIdleDuration()) <= 0);
1160
1161 assertTrue(po.getActiveDuration().toMillis() <= po.getActiveTimeMillis());
1162 assertTrue(po.getActiveDuration().compareTo(po.getIdleDuration()) <= 0);
1163
1164
1165 assertTrue(po.getActiveDuration().compareTo(po.getIdleTime()) <= 0);
1166 assertTrue(po.getActiveDuration().toMillis() <= po.getIdleTimeMillis());
1167
1168 assertTrue(po.getCreateInstant().compareTo(po.getLastBorrowInstant()) <= 0);
1169 assertTrue(po.getCreateInstant().compareTo(po.getLastReturnInstant()) <= 0);
1170 assertTrue(po.getCreateInstant().compareTo(po.getLastUsedInstant()) <= 0);
1171 assertTrue(lastBorrowInstant1.compareTo(po.getLastBorrowInstant()) <= 0);
1172 assertTrue(lastReturnInstant1.compareTo(po.getLastReturnInstant()) <= 0);
1173 assertTrue(lastUsedInstant1.compareTo(po.getLastUsedInstant()) <= 0);
1174 genericObjectPool.returnObject(object);
1175 assertFalse(po.getActiveDuration().isNegative());
1176 assertFalse(po.getActiveDuration().isZero());
1177 assertTrue(po.getActiveDuration().toMillis() <= po.getActiveTimeMillis());
1178 assertTrue(po.getActiveDuration().compareTo(po.getActiveTime()) <= 0);
1179 assertTrue(lastBorrowInstant1.compareTo(po.getLastBorrowInstant()) <= 0);
1180 assertTrue(lastReturnInstant1.compareTo(po.getLastReturnInstant()) <= 0);
1181 assertTrue(lastUsedInstant1.compareTo(po.getLastUsedInstant()) <= 0);
1182 }
1183
1184
1185
1186
1187
1188
1189 @Test
1190 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1191 void testBrokenFactoryShouldNotBlockPool() throws Exception {
1192 final int maxTotal = 1;
1193 simpleFactory.setMaxTotal(maxTotal);
1194 genericObjectPool.setMaxTotal(maxTotal);
1195 genericObjectPool.setBlockWhenExhausted(true);
1196 genericObjectPool.setTestOnBorrow(true);
1197
1198
1199 String obj = null;
1200 Exception ex = null;
1201 simpleFactory.setValid(false);
1202 try {
1203 obj = genericObjectPool.borrowObject();
1204 } catch (final Exception e) {
1205 ex = e;
1206 }
1207
1208 assertNotNull(ex);
1209 assertInstanceOf(NoSuchElementException.class, ex);
1210 assertNull(obj);
1211
1212 simpleFactory.setValid(true);
1213
1214 obj = genericObjectPool.borrowObject();
1215 assertNotNull(obj);
1216 genericObjectPool.returnObject(obj);
1217 }
1218
1219
1220 @Test
1221 void testClientWaitStats() throws Exception {
1222 final SimpleFactory factory = new SimpleFactory();
1223
1224 factory.setMakeLatency(200);
1225 try (GenericObjectPool<String> pool = new GenericObjectPool<>(factory, new GenericObjectPoolConfig<>())) {
1226 final String s = pool.borrowObject();
1227
1228
1229 assertTrue(pool.getMaxBorrowWaitTimeMillis() >= 100);
1230 assertTrue(pool.getMeanBorrowWaitTimeMillis() >= 100);
1231 pool.returnObject(s);
1232 pool.borrowObject();
1233
1234 assertTrue(pool.getMaxBorrowWaitTimeMillis() > 100);
1235 assertTrue(pool.getMeanBorrowWaitTimeMillis() < 200);
1236 assertTrue(pool.getMeanBorrowWaitTimeMillis() > 20);
1237 }
1238 }
1239
1240 @Test
1241 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1242 void testCloseMultiplePools1() {
1243 try (GenericObjectPool<String> genericObjectPool2 = new GenericObjectPool<>(simpleFactory)) {
1244 genericObjectPool.setTimeBetweenEvictionRuns(TestConstants.ONE_MILLISECOND_DURATION);
1245 genericObjectPool2.setTimeBetweenEvictionRuns(TestConstants.ONE_MILLISECOND_DURATION);
1246 }
1247 genericObjectPool.close();
1248 }
1249
1250 @Test
1251 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1252 void testCloseMultiplePools2() throws Exception {
1253 try (GenericObjectPool<String> genericObjectPool2 = new GenericObjectPool<>(simpleFactory)) {
1254
1255 simpleFactory.setDestroyLatency(1000L);
1256
1257 genericObjectPool.setTimeBetweenEvictionRuns(TestConstants.ONE_MILLISECOND_DURATION);
1258 genericObjectPool2.setTimeBetweenEvictionRuns(TestConstants.ONE_MILLISECOND_DURATION);
1259 genericObjectPool.setMinEvictableIdleTime(TestConstants.ONE_MILLISECOND_DURATION);
1260 genericObjectPool2.setMinEvictableIdleTime(TestConstants.ONE_MILLISECOND_DURATION);
1261 genericObjectPool.addObject();
1262 genericObjectPool2.addObject();
1263
1264 }
1265 genericObjectPool.close();
1266 }
1267
1268 @Test
1269 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1270 void testConcurrentBorrowAndEvict() throws Exception {
1271 genericObjectPool.setMaxTotal(1);
1272 genericObjectPool.addObject();
1273 for (int i = 0; i < 5000; i++) {
1274 final ConcurrentBorrowAndEvictThread one = new ConcurrentBorrowAndEvictThread(true);
1275 final ConcurrentBorrowAndEvictThread two = new ConcurrentBorrowAndEvictThread(false);
1276 one.start();
1277 two.start();
1278 one.join();
1279 two.join();
1280 genericObjectPool.returnObject(one.obj);
1281
1282
1283
1284 }
1285 }
1286
1287
1288
1289
1290
1291
1292 @Test
1293 void testConcurrentInvalidate() throws Exception {
1294
1295 final int nObjects = 1000;
1296 genericObjectPool.setMaxTotal(nObjects);
1297 genericObjectPool.setMaxIdle(nObjects);
1298 final String[] obj = new String[nObjects];
1299 for (int i = 0; i < nObjects; i++) {
1300 obj[i] = genericObjectPool.borrowObject();
1301 }
1302 for (int i = 0; i < nObjects; i++) {
1303 if (i % 2 == 0) {
1304 genericObjectPool.returnObject(obj[i]);
1305 }
1306 }
1307 final int nThreads = 20;
1308 final int nIterations = 60;
1309 final InvalidateThread[] threads = new InvalidateThread[nThreads];
1310
1311 final ArrayList<Integer> targets = new ArrayList<>();
1312 final Random random = new Random();
1313 for (int j = 0; j < nIterations; j++) {
1314
1315 Integer targ = Integer.valueOf(random.nextInt(nObjects));
1316 while (targets.contains(targ)) {
1317 targ = Integer.valueOf(random.nextInt(nObjects));
1318 }
1319 targets.add(targ);
1320
1321 for (int i = 0; i < nThreads; i++) {
1322 threads[i] = new InvalidateThread(genericObjectPool, obj[targ.intValue()]);
1323 }
1324 for (int i = 0; i < nThreads; i++) {
1325 new Thread(threads[i]).start();
1326 }
1327 boolean done = false;
1328 while (!done) {
1329 done = true;
1330 for (int i = 0; i < nThreads; i++) {
1331 done = done && threads[i].complete();
1332 }
1333 Thread.sleep(100);
1334 }
1335 }
1336 assertEquals(nIterations, genericObjectPool.getDestroyedCount());
1337 }
1338
1339 @Test
1340 void testConstructorNullFactory() {
1341
1342 assertThrows(IllegalArgumentException.class, () -> new GenericObjectPool<>(null));
1343 }
1344
1345 @Test
1346 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1347 void testConstructors() {
1348
1349 final int minIdle = 2;
1350 final Duration maxWaitDuration = Duration.ofMillis(3);
1351 final long maxWaitMillis = maxWaitDuration.toMillis();
1352 final int maxIdle = 4;
1353 final int maxTotal = 5;
1354 final Duration minEvictableIdleDuration = Duration.ofMillis(6);
1355 final long minEvictableIdleMillis = minEvictableIdleDuration.toMillis();
1356 final int numTestsPerEvictionRun = 7;
1357 final boolean testOnBorrow = true;
1358 final boolean testOnReturn = true;
1359 final boolean testWhileIdle = true;
1360 final long timeBetweenEvictionRunsMillis = 8;
1361 final boolean blockWhenExhausted = false;
1362 final boolean lifo = false;
1363 final PooledObjectFactory<Object> dummyFactory = new DummyFactory();
1364 try (GenericObjectPool<Object> dummyPool = new GenericObjectPool<>(dummyFactory)) {
1365 assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_IDLE, dummyPool.getMaxIdle());
1366 assertEquals(BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS, dummyPool.getMaxWaitMillis());
1367 assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_IDLE, dummyPool.getMinIdle());
1368 assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL, dummyPool.getMaxTotal());
1369 assertEquals(BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, dummyPool.getMinEvictableIdleTimeMillis());
1370 assertEquals(BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME, dummyPool.getMinEvictableIdleTime());
1371 assertEquals(BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME, dummyPool.getMinEvictableIdleDuration());
1372 assertEquals(BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN, dummyPool.getNumTestsPerEvictionRun());
1373 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW), Boolean.valueOf(dummyPool.getTestOnBorrow()));
1374 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN), Boolean.valueOf(dummyPool.getTestOnReturn()));
1375 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE), Boolean.valueOf(dummyPool.getTestWhileIdle()));
1376 assertEquals(BaseObjectPoolConfig.DEFAULT_DURATION_BETWEEN_EVICTION_RUNS, dummyPool.getDurationBetweenEvictionRuns());
1377 assertEquals(BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, dummyPool.getTimeBetweenEvictionRunsMillis());
1378 assertEquals(BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS, dummyPool.getTimeBetweenEvictionRuns());
1379 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED), Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
1380 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_LIFO), Boolean.valueOf(dummyPool.getLifo()));
1381 }
1382 final GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>();
1383 config.setLifo(lifo);
1384 config.setMaxIdle(maxIdle);
1385 config.setMinIdle(minIdle);
1386 config.setMaxTotal(maxTotal);
1387 config.setMaxWait(maxWaitDuration);
1388 config.setMinEvictableIdleTimeMillis(minEvictableIdleMillis);
1389 assertEquals(minEvictableIdleMillis, config.getMinEvictableIdleTime().toMillis());
1390 config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
1391 config.setTestOnBorrow(testOnBorrow);
1392 config.setTestOnReturn(testOnReturn);
1393 config.setTestWhileIdle(testWhileIdle);
1394 config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
1395 assertEquals(timeBetweenEvictionRunsMillis, config.getTimeBetweenEvictionRuns().toMillis());
1396 config.setBlockWhenExhausted(blockWhenExhausted);
1397 try (GenericObjectPool<Object> dummyPool = new GenericObjectPool<>(dummyFactory, config)) {
1398 assertEquals(maxIdle, dummyPool.getMaxIdle());
1399 assertEquals(maxWaitDuration, dummyPool.getMaxWaitDuration());
1400 assertEquals(maxWaitMillis, dummyPool.getMaxWaitMillis());
1401 assertEquals(minIdle, dummyPool.getMinIdle());
1402 assertEquals(maxTotal, dummyPool.getMaxTotal());
1403 assertEquals(minEvictableIdleMillis, dummyPool.getMinEvictableIdleTimeMillis());
1404 assertEquals(numTestsPerEvictionRun, dummyPool.getNumTestsPerEvictionRun());
1405 assertEquals(Boolean.valueOf(testOnBorrow), Boolean.valueOf(dummyPool.getTestOnBorrow()));
1406 assertEquals(Boolean.valueOf(testOnReturn), Boolean.valueOf(dummyPool.getTestOnReturn()));
1407 assertEquals(Boolean.valueOf(testWhileIdle), Boolean.valueOf(dummyPool.getTestWhileIdle()));
1408 assertEquals(timeBetweenEvictionRunsMillis, dummyPool.getTimeBetweenEvictionRunsMillis());
1409 assertEquals(Boolean.valueOf(blockWhenExhausted), Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
1410 assertEquals(Boolean.valueOf(lifo), Boolean.valueOf(dummyPool.getLifo()));
1411 }
1412 }
1413
1414 @Test
1415 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1416 void testDefaultConfiguration() {
1417 assertConfiguration(new GenericObjectPoolConfig<>(), genericObjectPool);
1418 }
1419
1420
1421
1422
1423
1424
1425 @Test
1426 void testEqualsIndiscernible() throws Exception {
1427 final HashSetFactory factory = new HashSetFactory();
1428 try (GenericObjectPool<HashSet<String>> pool = new GenericObjectPool<>(factory, new GenericObjectPoolConfig<>())) {
1429 final HashSet<String> s1 = pool.borrowObject();
1430 final HashSet<String> s2 = pool.borrowObject();
1431 pool.returnObject(s1);
1432 pool.returnObject(s2);
1433 }
1434 }
1435
1436 @Test
1437 void testErrorFactoryDoesNotBlockThreads() throws Exception {
1438 final CreateErrorFactory factory = new CreateErrorFactory();
1439 try (GenericObjectPool<String> createFailFactoryPool = new GenericObjectPool<>(factory)) {
1440 createFailFactoryPool.setMaxTotal(1);
1441
1442 final WaitingTestThread thread1 = new WaitingTestThread(createFailFactoryPool, 0);
1443 thread1.start();
1444
1445 while (!factory.hasQueuedThreads()) {
1446 Thread.sleep(200);
1447 }
1448
1449 final WaitingTestThread thread2 = new WaitingTestThread(createFailFactoryPool, 0);
1450 thread2.start();
1451
1452
1453
1454
1455 Thread.sleep(1000);
1456
1457 factory.release();
1458
1459 factory.release();
1460
1461 boolean threadRunning = true;
1462 int count = 0;
1463 while (threadRunning && count < 15) {
1464 threadRunning = thread1.isAlive();
1465 threadRunning = thread2.isAlive();
1466 Thread.sleep(200);
1467 count++;
1468 }
1469 assertFalse(thread1.isAlive());
1470 assertFalse(thread2.isAlive());
1471 assertTrue(thread1.thrown instanceof UnknownError);
1472 assertTrue(thread2.thrown instanceof UnknownError);
1473 }
1474 }
1475
1476
1477
1478
1479
1480
1481 @Test
1482 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1483 void testEvictAddObjects() throws Exception {
1484 simpleFactory.setMakeLatency(300);
1485 simpleFactory.setMaxTotal(2);
1486 genericObjectPool.setMaxTotal(2);
1487 genericObjectPool.setMinIdle(1);
1488 genericObjectPool.borrowObject();
1489
1490
1491 final TestThread<String> borrower = new TestThread<>(genericObjectPool, 1, 150, false);
1492 final Thread borrowerThread = new Thread(borrower);
1493
1494 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(100));
1495 borrowerThread.start();
1496 borrowerThread.join();
1497 assertFalse(borrower.failed());
1498 }
1499
1500 @Test
1501 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1502 void testEvictFIFO() throws Exception {
1503 checkEvict(false);
1504 }
1505
1506 @Test
1507 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1508 void testEviction() throws Exception {
1509 genericObjectPool.setMaxIdle(500);
1510 genericObjectPool.setMaxTotal(500);
1511 genericObjectPool.setNumTestsPerEvictionRun(100);
1512 genericObjectPool.setMinEvictableIdleTime(Duration.ofMillis(250));
1513 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(500));
1514 genericObjectPool.setTestWhileIdle(true);
1515 final String[] active = new String[500];
1516 for (int i = 0; i < 500; i++) {
1517 active[i] = genericObjectPool.borrowObject();
1518 }
1519 for (int i = 0; i < 500; i++) {
1520 genericObjectPool.returnObject(active[i]);
1521 }
1522 Waiter.sleepQuietly(1000L);
1523 assertTrue(genericObjectPool.getNumIdle() < 500, "Should be less than 500 idle, found " + genericObjectPool.getNumIdle());
1524 Waiter.sleepQuietly(600L);
1525 assertTrue(genericObjectPool.getNumIdle() < 400, "Should be less than 400 idle, found " + genericObjectPool.getNumIdle());
1526 Waiter.sleepQuietly(600L);
1527 assertTrue(genericObjectPool.getNumIdle() < 300, "Should be less than 300 idle, found " + genericObjectPool.getNumIdle());
1528 Waiter.sleepQuietly(600L);
1529 assertTrue(genericObjectPool.getNumIdle() < 200, "Should be less than 200 idle, found " + genericObjectPool.getNumIdle());
1530 Waiter.sleepQuietly(600L);
1531 assertTrue(genericObjectPool.getNumIdle() < 100, "Should be less than 100 idle, found " + genericObjectPool.getNumIdle());
1532 Waiter.sleepQuietly(600L);
1533 assertEquals(0, genericObjectPool.getNumIdle(), "Should be zero idle, found " + genericObjectPool.getNumIdle());
1534 for (int i = 0; i < 500; i++) {
1535 active[i] = genericObjectPool.borrowObject();
1536 }
1537 for (int i = 0; i < 500; i++) {
1538 genericObjectPool.returnObject(active[i]);
1539 }
1540 Waiter.sleepQuietly(1000L);
1541 assertTrue(genericObjectPool.getNumIdle() < 500, "Should be less than 500 idle, found " + genericObjectPool.getNumIdle());
1542 Waiter.sleepQuietly(600L);
1543 assertTrue(genericObjectPool.getNumIdle() < 400, "Should be less than 400 idle, found " + genericObjectPool.getNumIdle());
1544 Waiter.sleepQuietly(600L);
1545 assertTrue(genericObjectPool.getNumIdle() < 300, "Should be less than 300 idle, found " + genericObjectPool.getNumIdle());
1546 Waiter.sleepQuietly(600L);
1547 assertTrue(genericObjectPool.getNumIdle() < 200, "Should be less than 200 idle, found " + genericObjectPool.getNumIdle());
1548 Waiter.sleepQuietly(600L);
1549 assertTrue(genericObjectPool.getNumIdle() < 100, "Should be less than 100 idle, found " + genericObjectPool.getNumIdle());
1550 Waiter.sleepQuietly(600L);
1551 assertEquals(0, genericObjectPool.getNumIdle(), "Should be zero idle, found " + genericObjectPool.getNumIdle());
1552 }
1553
1554 @Test
1555 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1556 void testEvictionInvalid() throws Exception {
1557 try (GenericObjectPool<Object> invalidFactoryPool = new GenericObjectPool<>(new InvalidFactory())) {
1558 invalidFactoryPool.setMaxIdle(1);
1559 invalidFactoryPool.setMaxTotal(1);
1560 invalidFactoryPool.setTestOnBorrow(false);
1561 invalidFactoryPool.setTestOnReturn(false);
1562 invalidFactoryPool.setTestWhileIdle(true);
1563 invalidFactoryPool.setMinEvictableIdleTime(Duration.ofSeconds(100));
1564 invalidFactoryPool.setNumTestsPerEvictionRun(1);
1565 final Object p = invalidFactoryPool.borrowObject();
1566 invalidFactoryPool.returnObject(p);
1567
1568 final Thread t = new EvictionThread<>(invalidFactoryPool);
1569 t.start();
1570
1571 Thread.sleep(300);
1572 try {
1573 invalidFactoryPool.borrowObject(1);
1574 } catch (final NoSuchElementException nsee) {
1575
1576 }
1577
1578 Thread.sleep(1000);
1579
1580 assertEquals(0, invalidFactoryPool.getNumIdle(), "Idle count different than expected.");
1581 assertEquals(0, invalidFactoryPool.getNumActive(), "Total count different than expected.");
1582 }
1583 }
1584
1585
1586
1587
1588
1589
1590
1591
1592 @Test
1593 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1594 void testEvictionOrder() throws Exception {
1595 checkEvictionOrder(false);
1596 tearDown();
1597 setUp();
1598 checkEvictionOrder(true);
1599 }
1600
1601 @Test
1602 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1603 void testEvictionPolicy() throws Exception {
1604 genericObjectPool.setMaxIdle(500);
1605 genericObjectPool.setMaxTotal(500);
1606 genericObjectPool.setNumTestsPerEvictionRun(500);
1607 genericObjectPool.setMinEvictableIdleTime(Duration.ofMillis(250));
1608 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(500));
1609 genericObjectPool.setTestWhileIdle(true);
1610
1611 assertThrows(IllegalArgumentException.class, () -> genericObjectPool.setEvictionPolicyClassName(Long.toString(System.currentTimeMillis())),
1612 "setEvictionPolicyClassName must throw an error if the class name is invalid.");
1613
1614 assertThrows(IllegalArgumentException.class, () -> genericObjectPool.setEvictionPolicyClassName(Serializable.class.getName()),
1615 "setEvictionPolicyClassName must throw an error if the class name is invalid.");
1616
1617 assertThrows(IllegalArgumentException.class, () -> genericObjectPool.setEvictionPolicyClassName(Collections.class.getName()),
1618 "setEvictionPolicyClassName must throw an error if the class name is invalid.");
1619 assertThrows(IllegalArgumentException.class, () -> genericObjectPool.setEvictionPolicyClassName(String.class.getName()),
1620 () -> "setEvictionPolicyClassName must throw an error if a class that does not implement EvictionPolicy is specified.");
1621 genericObjectPool.setEvictionPolicy(new TestEvictionPolicy<>());
1622 assertEquals(TestEvictionPolicy.class.getName(), genericObjectPool.getEvictionPolicyClassName());
1623 genericObjectPool.setEvictionPolicyClassName(TestEvictionPolicy.class.getName());
1624 assertEquals(TestEvictionPolicy.class.getName(), genericObjectPool.getEvictionPolicyClassName());
1625 final String[] active = new String[500];
1626 for (int i = 0; i < 500; i++) {
1627 active[i] = genericObjectPool.borrowObject();
1628 }
1629 for (int i = 0; i < 500; i++) {
1630 genericObjectPool.returnObject(active[i]);
1631 }
1632
1633
1634
1635 Waiter.sleepQuietly(1000L);
1636 assertEquals(500, genericObjectPool.getNumIdle(), "Should be 500 idle");
1637
1638
1639 Waiter.sleepQuietly(2000L);
1640 assertEquals(0, genericObjectPool.getNumIdle(), "Should be 0 idle");
1641 }
1642
1643 @Test
1644 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1645 void testEvictionSoftMinIdle() throws Exception {
1646 final class TimeTest extends BasePooledObjectFactory<TimeTest> {
1647 private final long createTimeMillis;
1648
1649 TimeTest() {
1650 createTimeMillis = System.currentTimeMillis();
1651 }
1652
1653 @Override
1654 public TimeTest create() {
1655 return new TimeTest();
1656 }
1657
1658 public long getCreateTimeMillis() {
1659 return createTimeMillis;
1660 }
1661
1662 @Override
1663 public PooledObject<TimeTest> wrap(final TimeTest value) {
1664 return new DefaultPooledObject<>(value);
1665 }
1666 }
1667 try (GenericObjectPool<TimeTest> timePool = new GenericObjectPool<>(new TimeTest())) {
1668 timePool.setMaxIdle(5);
1669 timePool.setMaxTotal(5);
1670 timePool.setNumTestsPerEvictionRun(5);
1671 timePool.setMinEvictableIdleDuration(Duration.ofSeconds(3));
1672 timePool.setMinEvictableIdle(Duration.ofSeconds(3));
1673 timePool.setMinEvictableIdleTime(Duration.ofSeconds(3));
1674 timePool.setSoftMinEvictableIdleTime(TestConstants.ONE_SECOND_DURATION);
1675 timePool.setMinIdle(2);
1676 final TimeTest[] active = new TimeTest[5];
1677 final Long[] creationTime = new Long[5];
1678 for (int i = 0; i < 5; i++) {
1679 active[i] = timePool.borrowObject();
1680 creationTime[i] = Long.valueOf(active[i].getCreateTimeMillis());
1681 }
1682 for (int i = 0; i < 5; i++) {
1683 timePool.returnObject(active[i]);
1684 }
1685
1686 Thread.sleep(1500L);
1687 timePool.evict();
1688 assertEquals(2, timePool.getNumIdle(), "Idle count different than expected.");
1689
1690 Thread.sleep(2000L);
1691 timePool.evict();
1692 assertEquals(0, timePool.getNumIdle(), "Idle count different than expected.");
1693 }
1694 }
1695
1696 @Test
1697 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1698 void testEvictionWithNegativeNumTests() throws Exception {
1699
1700 genericObjectPool.setMaxIdle(6);
1701 genericObjectPool.setMaxTotal(6);
1702 genericObjectPool.setNumTestsPerEvictionRun(-2);
1703 genericObjectPool.setMinEvictableIdleTime(Duration.ofMillis(50));
1704 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(100));
1705 final String[] active = new String[6];
1706 for (int i = 0; i < 6; i++) {
1707 active[i] = genericObjectPool.borrowObject();
1708 }
1709 for (int i = 0; i < 6; i++) {
1710 genericObjectPool.returnObject(active[i]);
1711 }
1712 Waiter.sleepQuietly(100L);
1713 assertTrue(genericObjectPool.getNumIdle() <= 6, "Should at most 6 idle, found " + genericObjectPool.getNumIdle());
1714 Waiter.sleepQuietly(100L);
1715 assertTrue(genericObjectPool.getNumIdle() <= 3, "Should at most 3 idle, found " + genericObjectPool.getNumIdle());
1716 Waiter.sleepQuietly(100L);
1717 assertTrue(genericObjectPool.getNumIdle() <= 2, "Should be at most 2 idle, found " + genericObjectPool.getNumIdle());
1718 Waiter.sleepQuietly(100L);
1719 assertEquals(0, genericObjectPool.getNumIdle(), "Should be zero idle, found " + genericObjectPool.getNumIdle());
1720 }
1721
1722 @Test
1723 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1724 void testEvictLIFO() throws Exception {
1725 checkEvict(true);
1726 }
1727
1728
1729
1730
1731
1732
1733 @Test
1734 void testEvictorVisiting() throws Exception {
1735 checkEvictorVisiting(true);
1736 checkEvictorVisiting(false);
1737 }
1738
1739 @Test
1740 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1741 void testEvictWhileEmpty() throws Exception {
1742 genericObjectPool.evict();
1743 genericObjectPool.evict();
1744 genericObjectPool.close();
1745 }
1746
1747 @Test
1748 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1749 void testExceptionInValidationDuringEviction() throws Exception {
1750 genericObjectPool.setMaxIdle(1);
1751 genericObjectPool.setMinEvictableIdleTime(Duration.ZERO);
1752 genericObjectPool.setTestWhileIdle(true);
1753 final String active = genericObjectPool.borrowObject();
1754 genericObjectPool.returnObject(active);
1755 simpleFactory.setThrowExceptionOnValidate(true);
1756 assertThrows(RuntimeException.class, () -> genericObjectPool.evict());
1757 assertEquals(0, genericObjectPool.getNumActive());
1758 assertEquals(0, genericObjectPool.getNumIdle());
1759 }
1760
1761 @Test
1762 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1763 void testExceptionOnActivateDuringBorrow() throws Exception {
1764 final String obj1 = genericObjectPool.borrowObject();
1765 final String obj2 = genericObjectPool.borrowObject();
1766 genericObjectPool.returnObject(obj1);
1767 genericObjectPool.returnObject(obj2);
1768 simpleFactory.setThrowExceptionOnActivate(true);
1769 simpleFactory.setEvenValid(false);
1770
1771
1772 final String obj = genericObjectPool.borrowObject();
1773 assertEquals(1, genericObjectPool.getNumActive());
1774 assertEquals(0, genericObjectPool.getNumIdle());
1775 genericObjectPool.returnObject(obj);
1776 simpleFactory.setValid(false);
1777
1778
1779 assertThrows(NoSuchElementException.class, () -> genericObjectPool.borrowObject());
1780 assertEquals(0, genericObjectPool.getNumActive());
1781 assertEquals(0, genericObjectPool.getNumIdle());
1782 }
1783
1784 @Test
1785 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1786 void testExceptionOnDestroyDuringBorrow() throws Exception {
1787 simpleFactory.setThrowExceptionOnDestroy(true);
1788 genericObjectPool.setTestOnBorrow(true);
1789 genericObjectPool.borrowObject();
1790 simpleFactory.setValid(false);
1791 assertThrows(NoSuchElementException.class, () -> genericObjectPool.borrowObject());
1792 assertEquals(1, genericObjectPool.getNumActive());
1793 assertEquals(0, genericObjectPool.getNumIdle());
1794 }
1795
1796 @Test
1797 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1798 void testExceptionOnDestroyDuringReturn() throws Exception {
1799 simpleFactory.setThrowExceptionOnDestroy(true);
1800 genericObjectPool.setTestOnReturn(true);
1801 final String obj1 = genericObjectPool.borrowObject();
1802 genericObjectPool.borrowObject();
1803 simpleFactory.setValid(false);
1804 genericObjectPool.returnObject(obj1);
1805 assertEquals(1, genericObjectPool.getNumActive());
1806 assertEquals(0, genericObjectPool.getNumIdle());
1807 }
1808
1809 @Test
1810 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1811 void testExceptionOnPassivateDuringReturn() throws Exception {
1812 final String obj = genericObjectPool.borrowObject();
1813 simpleFactory.setThrowExceptionOnPassivate(true);
1814 genericObjectPool.returnObject(obj);
1815 assertEquals(0, genericObjectPool.getNumIdle());
1816 }
1817
1818 @Test
1819 void testFailingFactoryDoesNotBlockThreads() throws Exception {
1820 final CreateFailFactory factory = new CreateFailFactory();
1821 try (GenericObjectPool<String> createFailFactoryPool = new GenericObjectPool<>(factory)) {
1822 createFailFactoryPool.setMaxTotal(1);
1823
1824 final WaitingTestThread thread1 = new WaitingTestThread(createFailFactoryPool, 0);
1825 thread1.start();
1826
1827 while (!factory.hasQueuedThreads()) {
1828 Thread.sleep(200);
1829 }
1830
1831 final WaitingTestThread thread2 = new WaitingTestThread(createFailFactoryPool, 0);
1832 thread2.start();
1833
1834
1835
1836
1837 Thread.sleep(1000);
1838
1839 factory.release();
1840
1841 factory.release();
1842
1843 boolean threadRunning = true;
1844 int count = 0;
1845 while (threadRunning && count < 15) {
1846 threadRunning = thread1.isAlive();
1847 threadRunning = thread2.isAlive();
1848 Thread.sleep(200);
1849 count++;
1850 }
1851 assertFalse(thread1.isAlive());
1852 assertFalse(thread2.isAlive());
1853 assertTrue(thread1.thrown instanceof UnsupportedCharsetException);
1854 assertTrue(thread2.thrown instanceof UnsupportedCharsetException);
1855 }
1856 }
1857
1858 @Test
1859 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1860 void testFIFO() throws Exception {
1861 genericObjectPool.setLifo(false);
1862 genericObjectPool.addObject();
1863 genericObjectPool.addObject();
1864 genericObjectPool.addObject();
1865 assertEquals("0", genericObjectPool.borrowObject(), "Oldest");
1866 assertEquals("1", genericObjectPool.borrowObject(), "Middle");
1867 assertEquals("2", genericObjectPool.borrowObject(), "Youngest");
1868 final String o = genericObjectPool.borrowObject();
1869 assertEquals("3", o, "new-3");
1870 genericObjectPool.returnObject(o);
1871 assertEquals(o, genericObjectPool.borrowObject(), "returned-3");
1872 assertEquals("4", genericObjectPool.borrowObject(), "new-4");
1873 }
1874
1875 @Test
1876 void testGetFactoryType_DefaultPooledObjectFactory() {
1877 try (GenericObjectPool<String> pool = new GenericObjectPool<>(createDefaultPooledObjectFactory())) {
1878 assertNotNull(pool.getFactoryType());
1879 }
1880 }
1881
1882 @Test
1883 void testGetFactoryType_NullPooledObjectFactory() {
1884 try (GenericObjectPool<String> pool = new GenericObjectPool<>(createNullPooledObjectFactory())) {
1885 assertNotNull(pool.getFactoryType());
1886 }
1887 }
1888
1889 @Test
1890 void testGetFactoryType_PoolUtilsSynchronizedDefaultPooledFactory() {
1891 try (GenericObjectPool<String> pool = new GenericObjectPool<>(PoolUtils.synchronizedPooledFactory(createDefaultPooledObjectFactory()))) {
1892 assertNotNull(pool.getFactoryType());
1893 }
1894 }
1895
1896 @Test
1897 void testGetFactoryType_PoolUtilsSynchronizedNullPooledFactory() {
1898 try (GenericObjectPool<String> pool = new GenericObjectPool<>(PoolUtils.synchronizedPooledFactory(createNullPooledObjectFactory()))) {
1899 assertNotNull(pool.getFactoryType());
1900 }
1901 }
1902
1903 @Test
1904 void testGetFactoryType_SynchronizedDefaultPooledObjectFactory() {
1905 try (GenericObjectPool<String> pool = new GenericObjectPool<>(new TestSynchronizedPooledObjectFactory<>(createDefaultPooledObjectFactory()))) {
1906 assertNotNull(pool.getFactoryType());
1907 }
1908 }
1909
1910 @Test
1911 void testGetFactoryType_SynchronizedNullPooledObjectFactory() {
1912 try (GenericObjectPool<String> pool = new GenericObjectPool<>(new TestSynchronizedPooledObjectFactory<>(createNullPooledObjectFactory()))) {
1913 assertNotNull(pool.getFactoryType());
1914 }
1915 }
1916
1917 @Test
1918 void testGetStatsString() {
1919 try (GenericObjectPool<String> pool = new GenericObjectPool<>(new TestSynchronizedPooledObjectFactory<>(createNullPooledObjectFactory()))) {
1920 assertNotNull(pool.getStatsString());
1921 }
1922 }
1923
1924
1925
1926
1927
1928
1929
1930
1931 @Test
1932 void testInvalidateFreesCapacity() throws Exception {
1933 final SimpleFactory factory = new SimpleFactory();
1934 try (GenericObjectPool<String> pool = new GenericObjectPool<>(factory)) {
1935 pool.setMaxTotal(2);
1936 pool.setMaxWaitMillis(500);
1937
1938 final WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
1939 thread1.start();
1940
1941 final String obj = pool.borrowObject();
1942
1943 final WaitingTestThread thread2 = new WaitingTestThread(pool, 100);
1944 thread2.start();
1945
1946 Thread.sleep(20);
1947 pool.invalidateObject(obj);
1948 Thread.sleep(600);
1949 if (thread2.thrown != null) {
1950 fail(thread2.thrown.toString());
1951 }
1952 }
1953 }
1954
1955
1956
1957
1958 @Test
1959 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1960 void testJmxRegistration() {
1961 final ObjectName oname = genericObjectPool.getJmxName();
1962 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
1963 final Set<ObjectName> result = mbs.queryNames(oname, null);
1964 assertEquals(1, result.size());
1965 genericObjectPool.jmxUnregister();
1966 final GenericObjectPoolConfig<String> config = new GenericObjectPoolConfig<>();
1967 config.setJmxEnabled(false);
1968 try (GenericObjectPool<String> poolWithoutJmx = new GenericObjectPool<>(simpleFactory, config)) {
1969 assertNull(poolWithoutJmx.getJmxName());
1970 config.setJmxEnabled(true);
1971 poolWithoutJmx.jmxUnregister();
1972 }
1973 config.setJmxNameBase(null);
1974 try (GenericObjectPool<String> poolWithDefaultJmxNameBase = new GenericObjectPool<>(simpleFactory, config)) {
1975 assertNotNull(poolWithDefaultJmxNameBase.getJmxName());
1976 }
1977 }
1978
1979 @Test
1980 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1981 void testLIFO() throws Exception {
1982 final String o;
1983 genericObjectPool.setLifo(true);
1984 genericObjectPool.addObject();
1985 genericObjectPool.addObject();
1986 genericObjectPool.addObject();
1987 assertEquals("2", genericObjectPool.borrowObject(), "Youngest");
1988 assertEquals("1", genericObjectPool.borrowObject(), "Middle");
1989 assertEquals("0", genericObjectPool.borrowObject(), "Oldest");
1990 o = genericObjectPool.borrowObject();
1991 assertEquals("3", o, "new-3");
1992 genericObjectPool.returnObject(o);
1993 assertEquals(o, genericObjectPool.borrowObject(), "returned-3");
1994 assertEquals("4", genericObjectPool.borrowObject(), "new-4");
1995 }
1996
1997
1998
1999
2000
2001 @Test
2002 @Disabled
2003 @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS)
2004 void testLivenessOnTransientFactoryFailure() throws Exception {
2005 final DisconnectingWaiterFactory<String> factory = new DisconnectingWaiterFactory<>(DisconnectingWaiterFactory.DEFAULT_DISCONNECTED_CREATE_ACTION,
2006 DisconnectingWaiterFactory.DEFAULT_DISCONNECTED_LIFECYCLE_ACTION, obj -> false
2007 );
2008 final AtomicBoolean failed = new AtomicBoolean();
2009 try (GenericObjectPool<Waiter> pool = new GenericObjectPool<>(factory)) {
2010 pool.setMaxWait(Duration.ofMillis(100));
2011 pool.setTestOnReturn(true);
2012 pool.setMaxTotal(1);
2013 final Waiter w = pool.borrowObject();
2014 final Thread t = new Thread(() -> {
2015 try {
2016 pool.borrowObject();
2017 } catch (final Exception e) {
2018 failed.set(true);
2019 }
2020 });
2021 Thread.sleep(10);
2022 t.start();
2023
2024 Thread.sleep(10);
2025 factory.disconnect();
2026 pool.returnObject(w);
2027 Thread.sleep(10);
2028 factory.connect();
2029
2030 t.join();
2031 }
2032 if (failed.get()) {
2033 fail("Borrower timed out waiting for an instance");
2034 }
2035 }
2036
2037
2038
2039
2040
2041
2042
2043 @Test
2044 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2045 void testMakeConcurrentWithReturn() throws Exception {
2046 genericObjectPool.setTestOnBorrow(true);
2047 simpleFactory.setValid(true);
2048
2049 final WaitingTestThread thread1 = new WaitingTestThread(genericObjectPool, 200);
2050 thread1.start();
2051 Thread.sleep(50);
2052
2053 simpleFactory.setValidateLatency(400);
2054 final String instance = genericObjectPool.borrowObject();
2055
2056 assertEquals(simpleFactory.getMakeCounter(), genericObjectPool.getNumIdle() + 1);
2057 genericObjectPool.returnObject(instance);
2058 assertEquals(simpleFactory.getMakeCounter(), genericObjectPool.getNumIdle());
2059 }
2060
2061 @Test
2062 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2063 void testMaxIdle() throws Exception {
2064 genericObjectPool.setMaxTotal(100);
2065 genericObjectPool.setMaxIdle(8);
2066 final String[] active = new String[100];
2067 for (int i = 0; i < 100; i++) {
2068 active[i] = genericObjectPool.borrowObject();
2069 }
2070 assertEquals(100, genericObjectPool.getNumActive());
2071 assertEquals(0, genericObjectPool.getNumIdle());
2072 for (int i = 0; i < 100; i++) {
2073 genericObjectPool.returnObject(active[i]);
2074 assertEquals(99 - i, genericObjectPool.getNumActive());
2075 assertEquals(i < 8 ? i + 1 : 8, genericObjectPool.getNumIdle());
2076 }
2077 }
2078
2079 @Test
2080 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2081 void testMaxIdleZero() throws Exception {
2082 genericObjectPool.setMaxTotal(100);
2083 genericObjectPool.setMaxIdle(0);
2084 final String[] active = new String[100];
2085 for (int i = 0; i < 100; i++) {
2086 active[i] = genericObjectPool.borrowObject();
2087 }
2088 assertEquals(100, genericObjectPool.getNumActive());
2089 assertEquals(0, genericObjectPool.getNumIdle());
2090 for (int i = 0; i < 100; i++) {
2091 genericObjectPool.returnObject(active[i]);
2092 assertEquals(99 - i, genericObjectPool.getNumActive());
2093 assertEquals(0, genericObjectPool.getNumIdle());
2094 }
2095 }
2096
2097
2098
2099
2100 @Test
2101 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2102 @SuppressWarnings("rawtypes")
2103 void testMaxIdleZeroUnderLoad() {
2104
2105 final int numThreads = 199;
2106 final int numIter = 20;
2107 final int delay = 25;
2108 final int maxTotal = 10;
2109 simpleFactory.setMaxTotal(maxTotal);
2110 genericObjectPool.setMaxTotal(maxTotal);
2111 genericObjectPool.setBlockWhenExhausted(true);
2112 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(-1));
2113
2114 genericObjectPool.setMaxIdle(0);
2115
2116 final TestThread[] threads = new TestThread[numThreads];
2117 for (int i = 0; i < numThreads; i++) {
2118
2119
2120
2121 threads[i] = new TestThread<>(genericObjectPool, numIter * 2, delay * 2);
2122 final Thread t = new Thread(threads[i]);
2123 t.start();
2124 }
2125
2126 Waiter.sleepQuietly(100L);
2127 for (int i = 0; i < numIter; i++) {
2128 String obj = null;
2129 try {
2130 Waiter.sleepQuietly(delay);
2131 obj = genericObjectPool.borrowObject();
2132
2133 if (genericObjectPool.getNumActive() > genericObjectPool.getMaxTotal()) {
2134 throw new IllegalStateException("Too many active objects");
2135 }
2136 Waiter.sleepQuietly(delay);
2137 } catch (final Exception e) {
2138
2139 e.printStackTrace();
2140 fail("Exception on borrow");
2141 } finally {
2142 if (obj != null) {
2143 try {
2144 genericObjectPool.returnObject(obj);
2145 } catch (final Exception e) {
2146
2147 }
2148 }
2149 }
2150 }
2151 for (int i = 0; i < numThreads; i++) {
2152 while (!threads[i].complete()) {
2153 Waiter.sleepQuietly(500L);
2154 }
2155 if (threads[i].failed()) {
2156 threads[i].error.printStackTrace();
2157 fail("Thread " + i + " failed: " + threads[i].error.toString());
2158 }
2159 }
2160 }
2161
2162 @Test
2163 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2164 void testMaxTotal() throws Exception {
2165 genericObjectPool.setMaxTotal(3);
2166 genericObjectPool.setBlockWhenExhausted(false);
2167 genericObjectPool.borrowObject();
2168 genericObjectPool.borrowObject();
2169 genericObjectPool.borrowObject();
2170 assertThrows(NoSuchElementException.class, () -> genericObjectPool.borrowObject());
2171 }
2172
2173
2174
2175
2176
2177 @Test
2178 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2179 void testMaxTotalInvariant() {
2180 final int maxTotal = 15;
2181 simpleFactory.setEvenValid(false);
2182 simpleFactory.setDestroyLatency(100);
2183 simpleFactory.setMaxTotal(maxTotal);
2184 simpleFactory.setValidationEnabled(true);
2185 genericObjectPool.setMaxTotal(maxTotal);
2186 genericObjectPool.setMaxIdle(-1);
2187 genericObjectPool.setTestOnReturn(true);
2188 genericObjectPool.setMaxWaitMillis(1000L);
2189 runTestThreads(5, 10, 50, genericObjectPool);
2190 }
2191
2192 @Test
2193 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2194 @SuppressWarnings("rawtypes")
2195 void testMaxTotalUnderLoad() {
2196
2197 final int numThreads = 199;
2198 final int numIter = 20;
2199 final int delay = 25;
2200 final int maxTotal = 10;
2201 simpleFactory.setMaxTotal(maxTotal);
2202 genericObjectPool.setMaxTotal(maxTotal);
2203 genericObjectPool.setBlockWhenExhausted(true);
2204 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(-1));
2205
2206 final TestThread[] threads = new TestThread[numThreads];
2207 for (int i = 0; i < numThreads; i++) {
2208
2209
2210
2211 threads[i] = new TestThread<>(genericObjectPool, numIter * 2, delay * 2);
2212 final Thread t = new Thread(threads[i]);
2213 t.start();
2214 }
2215
2216 Waiter.sleepQuietly(5000);
2217 for (int i = 0; i < numIter; i++) {
2218 String obj = null;
2219 try {
2220 Waiter.sleepQuietly(delay);
2221 obj = genericObjectPool.borrowObject();
2222
2223 if (genericObjectPool.getNumActive() > genericObjectPool.getMaxTotal()) {
2224 throw new IllegalStateException("Too many active objects");
2225 }
2226 Waiter.sleepQuietly(delay);
2227 } catch (final Exception e) {
2228
2229 e.printStackTrace();
2230 fail("Exception on borrow");
2231 } finally {
2232 if (obj != null) {
2233 try {
2234 genericObjectPool.returnObject(obj);
2235 } catch (final Exception e) {
2236
2237 }
2238 }
2239 }
2240 }
2241 for (int i = 0; i < numThreads; i++) {
2242 while (!threads[i].complete()) {
2243 Waiter.sleepQuietly(500L);
2244 }
2245 if (threads[i].failed()) {
2246 fail("Thread " + i + " failed: " + threads[i].error.toString());
2247 }
2248 }
2249 }
2250
2251 @Test
2252 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2253 void testMaxTotalZero() throws Exception {
2254 genericObjectPool.setMaxTotal(0);
2255 genericObjectPool.setBlockWhenExhausted(false);
2256 assertThrows(NoSuchElementException.class, () -> genericObjectPool.borrowObject());
2257 }
2258
2259
2260
2261
2262
2263
2264
2265 @Test
2266 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2267 void testMaxWaitMultiThreaded() throws Exception {
2268 final long maxWait = 500;
2269 final long holdTime = 2 * maxWait;
2270 final int threads = 10;
2271 genericObjectPool.setBlockWhenExhausted(true);
2272 genericObjectPool.setMaxWaitMillis(maxWait);
2273 genericObjectPool.setMaxTotal(threads);
2274
2275 final WaitingTestThread[] wtt = new WaitingTestThread[threads * 2];
2276 for (int i = 0; i < wtt.length; i++) {
2277 wtt[i] = new WaitingTestThread(genericObjectPool, holdTime);
2278 }
2279 final long originMillis = System.currentTimeMillis() - 1000;
2280 for (final WaitingTestThread element : wtt) {
2281 element.start();
2282 }
2283 int failed = 0;
2284 for (final WaitingTestThread element : wtt) {
2285 element.join();
2286 if (element.thrown != null) {
2287 failed++;
2288 }
2289 }
2290 if (DISPLAY_THREAD_DETAILS || wtt.length / 2 != failed) {
2291 System.out.println("MaxWait: " + maxWait + " HoldTime: " + holdTime + " MaxTotal: " + threads + " Threads: " + wtt.length + " Failed: " + failed);
2292 for (final WaitingTestThread wt : wtt) {
2293 System.out.println("PreBorrow: " + (wt.preBorrowMillis - originMillis) + " PostBorrow: "
2294 + (wt.postBorrowMillis != 0 ? wt.postBorrowMillis - originMillis : -1) + " BorrowTime: "
2295 + (wt.postBorrowMillis != 0 ? wt.postBorrowMillis - wt.preBorrowMillis : -1) + " PostReturn: "
2296 + (wt.postReturnMillis != 0 ? wt.postReturnMillis - originMillis : -1) + " Ended: " + (wt.endedMillis - originMillis) + " ObjId: "
2297 + wt.objectId);
2298 }
2299 }
2300 assertEquals(wtt.length / 2, failed, "Expected half the threads to fail");
2301 }
2302
2303 @Test
2304 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2305 void testMinIdle() throws Exception {
2306 genericObjectPool.setMaxIdle(500);
2307 genericObjectPool.setMinIdle(5);
2308 genericObjectPool.setMaxTotal(10);
2309 genericObjectPool.setNumTestsPerEvictionRun(0);
2310 genericObjectPool.setMinEvictableIdleTime(Duration.ofMillis(50));
2311 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(100));
2312 genericObjectPool.setTestWhileIdle(true);
2313 Waiter.sleepQuietly(150L);
2314 assertEquals(5, genericObjectPool.getNumIdle(), "Should be 5 idle, found " + genericObjectPool.getNumIdle());
2315 final String[] active = new String[5];
2316 active[0] = genericObjectPool.borrowObject();
2317 Waiter.sleepQuietly(150L);
2318 assertEquals(5, genericObjectPool.getNumIdle(), "Should be 5 idle, found " + genericObjectPool.getNumIdle());
2319 for (int i = 1; i < 5; i++) {
2320 active[i] = genericObjectPool.borrowObject();
2321 }
2322 Waiter.sleepQuietly(150L);
2323 assertEquals(5, genericObjectPool.getNumIdle(), "Should be 5 idle, found " + genericObjectPool.getNumIdle());
2324 for (int i = 0; i < 5; i++) {
2325 genericObjectPool.returnObject(active[i]);
2326 }
2327 Waiter.sleepQuietly(150L);
2328 assertEquals(10, genericObjectPool.getNumIdle(), "Should be 10 idle, found " + genericObjectPool.getNumIdle());
2329 }
2330
2331 @Test
2332 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2333 void testMinIdleMaxTotal() throws Exception {
2334 genericObjectPool.setMaxIdle(500);
2335 genericObjectPool.setMinIdle(5);
2336 genericObjectPool.setMaxTotal(10);
2337 genericObjectPool.setNumTestsPerEvictionRun(0);
2338 genericObjectPool.setMinEvictableIdleTime(Duration.ofMillis(50));
2339 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(100));
2340 genericObjectPool.setTestWhileIdle(true);
2341 Waiter.sleepQuietly(150L);
2342 assertEquals(5, genericObjectPool.getNumIdle(), "Should be 5 idle, found " + genericObjectPool.getNumIdle());
2343 final String[] active = new String[10];
2344 Waiter.sleepQuietly(150L);
2345 assertEquals(5, genericObjectPool.getNumIdle(), "Should be 5 idle, found " + genericObjectPool.getNumIdle());
2346 for (int i = 0; i < 5; i++) {
2347 active[i] = genericObjectPool.borrowObject();
2348 }
2349 Waiter.sleepQuietly(150L);
2350 assertEquals(5, genericObjectPool.getNumIdle(), "Should be 5 idle, found " + genericObjectPool.getNumIdle());
2351 for (int i = 0; i < 5; i++) {
2352 genericObjectPool.returnObject(active[i]);
2353 }
2354 Waiter.sleepQuietly(150L);
2355 assertEquals(10, genericObjectPool.getNumIdle(), "Should be 10 idle, found " + genericObjectPool.getNumIdle());
2356 for (int i = 0; i < 10; i++) {
2357 active[i] = genericObjectPool.borrowObject();
2358 }
2359 Waiter.sleepQuietly(150L);
2360 assertEquals(0, genericObjectPool.getNumIdle(), "Should be 0 idle, found " + genericObjectPool.getNumIdle());
2361 for (int i = 0; i < 10; i++) {
2362 genericObjectPool.returnObject(active[i]);
2363 }
2364 Waiter.sleepQuietly(150L);
2365 assertEquals(10, genericObjectPool.getNumIdle(), "Should be 10 idle, found " + genericObjectPool.getNumIdle());
2366 }
2367
2368
2369
2370
2371
2372
2373 @Test
2374 void testMultipleReturn() throws Exception {
2375 final WaiterFactory<String> factory = new WaiterFactory<>(0, 0, 0, 0, 0, 0);
2376 try (GenericObjectPool<Waiter> pool = new GenericObjectPool<>(factory)) {
2377 pool.setTestOnReturn(true);
2378 final Waiter waiter = pool.borrowObject();
2379 pool.returnObject(waiter);
2380 assertEquals(1, waiter.getValidationCount());
2381 assertEquals(1, waiter.getPassivationCount());
2382 try {
2383 pool.returnObject(waiter);
2384 fail("Expecting IllegalStateException from multiple return");
2385 } catch (final IllegalStateException ex) {
2386
2387 assertEquals(1, waiter.getValidationCount());
2388 assertEquals(1, waiter.getPassivationCount());
2389 }
2390 }
2391 }
2392
2393
2394 @Test
2395 void testMultipleReturnOfSameObject() throws Exception {
2396 try (GenericObjectPool<String> pool = new GenericObjectPool<>(simpleFactory, new GenericObjectPoolConfig<>())) {
2397 assertEquals(0, pool.getNumActive());
2398 assertEquals(0, pool.getNumIdle());
2399 final String obj = pool.borrowObject();
2400 assertEquals(1, pool.getNumActive());
2401 assertEquals(0, pool.getNumIdle());
2402 pool.returnObject(obj);
2403 assertEquals(0, pool.getNumActive());
2404 assertEquals(1, pool.getNumIdle());
2405 assertThrows(IllegalStateException.class, () -> pool.returnObject(obj));
2406 assertEquals(0, pool.getNumActive());
2407 assertEquals(1, pool.getNumIdle());
2408 }
2409 }
2410
2411
2412
2413
2414
2415
2416 @Test
2417 void testMutable() throws Exception {
2418 final HashSetFactory factory = new HashSetFactory();
2419 try (GenericObjectPool<HashSet<String>> pool = new GenericObjectPool<>(factory, new GenericObjectPoolConfig<>())) {
2420 final HashSet<String> s1 = pool.borrowObject();
2421 final HashSet<String> s2 = pool.borrowObject();
2422 s1.add("One");
2423 s2.add("One");
2424 pool.returnObject(s1);
2425 pool.returnObject(s2);
2426 }
2427 }
2428
2429 @Test
2430 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2431 void testNegativeMaxTotal() throws Exception {
2432 genericObjectPool.setMaxTotal(-1);
2433 genericObjectPool.setBlockWhenExhausted(false);
2434 final String obj = genericObjectPool.borrowObject();
2435 assertEquals(getNthObject(0), obj);
2436 genericObjectPool.returnObject(obj);
2437 }
2438
2439
2440
2441
2442 @Test
2443 void testNoInstanceOverlap() {
2444 final int maxTotal = 5;
2445 final int numThreads = 100;
2446 final int delay = 1;
2447 final int iterations = 1000;
2448 final AtomicIntegerFactory factory = new AtomicIntegerFactory();
2449 try (GenericObjectPool<AtomicInteger> pool = new GenericObjectPool<>(factory)) {
2450 pool.setMaxTotal(maxTotal);
2451 pool.setMaxIdle(maxTotal);
2452 pool.setTestOnBorrow(true);
2453 pool.setBlockWhenExhausted(true);
2454 pool.setMaxWaitMillis(-1);
2455 runTestThreads(numThreads, iterations, delay, pool);
2456 assertEquals(0, pool.getDestroyedByBorrowValidationCount());
2457 }
2458 }
2459
2460
2461
2462
2463 @Test
2464 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2465 void testNoInvalidateNPE() throws Exception {
2466 genericObjectPool.setMaxTotal(1);
2467 genericObjectPool.setTestOnCreate(true);
2468 genericObjectPool.setMaxWaitMillis(-1);
2469 final String obj = genericObjectPool.borrowObject();
2470
2471 simpleFactory.setValid(false);
2472
2473 final WaitingTestThread wtt = new WaitingTestThread(genericObjectPool, 200);
2474 wtt.start();
2475
2476 Thread.sleep(200);
2477 genericObjectPool.invalidateObject(obj);
2478
2479 simpleFactory.setValid(true);
2480 }
2481
2482
2483
2484
2485
2486
2487 @Test
2488 @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS)
2489 void testNPEOnFactoryNull() throws Exception {
2490
2491 final DisconnectingWaiterFactory<String> factory = new DisconnectingWaiterFactory<>(Suppliers.nul(),
2492 DisconnectingWaiterFactory.DEFAULT_DISCONNECTED_LIFECYCLE_ACTION, DisconnectingWaiterFactory.DEFAULT_DISCONNECTED_VALIDATION_ACTION);
2493 try (GenericObjectPool<Waiter> pool = new GenericObjectPool<>(factory)) {
2494 pool.setTestOnBorrow(true);
2495 pool.setMaxTotal(-1);
2496 pool.setMinIdle(1);
2497
2498 factory.disconnect();
2499 assertThrows(NullPointerException.class, pool::borrowObject);
2500 assertThrows(NullPointerException.class, pool::addObject);
2501 assertThrows(NullPointerException.class, pool::ensureMinIdle);
2502 }
2503 }
2504
2505
2506
2507
2508
2509 @Test
2510 void testPool419() throws Exception {
2511
2512 final ExecutorService executor = Executors.newFixedThreadPool(100);
2513
2514 final GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>();
2515
2516 final int maxConnections = 10000;
2517
2518 config.setMaxTotal(maxConnections);
2519 config.setMaxIdle(maxConnections);
2520 config.setMinIdle(1);
2521
2522 final BasePooledObjectFactory<Object> pof = createPooledObjectFactory();
2523
2524 try (ObjectPool<Object> connectionPool = new GenericObjectPool<>(pof, config)) {
2525 assertNotNull(connectionPool);
2526
2527 final CountDownLatch startLatch = new CountDownLatch(1);
2528
2529 final List<Object> poolObjects = new ArrayList<>();
2530
2531 final List<FutureTask<Boolean>> tasks = new ArrayList<>();
2532
2533 for (int i = 0; i < maxConnections; i++) {
2534 poolObjects.add(connectionPool.borrowObject());
2535 }
2536
2537 for (final Object poolObject : poolObjects) {
2538
2539 tasks.add(new FutureTask<>(() -> {
2540 startLatch.await();
2541 connectionPool.invalidateObject(poolObject);
2542 return true;
2543 }));
2544
2545 tasks.add(new FutureTask<>(() -> {
2546 startLatch.await();
2547 connectionPool.returnObject(poolObject);
2548 return true;
2549 }));
2550 }
2551
2552 tasks.forEach(executor::submit);
2553
2554 startLatch.countDown();
2555
2556 executor.shutdown();
2557 assertTrue(executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS));
2558
2559 assertEquals(0, connectionPool.getNumActive(), "getNumActive() must not return a negative value");
2560
2561 }
2562 }
2563
2564 @Test
2565 void testPreparePool() throws Exception {
2566 genericObjectPool.setMinIdle(1);
2567 genericObjectPool.setMaxTotal(1);
2568 genericObjectPool.preparePool();
2569 assertEquals(1, genericObjectPool.getNumIdle());
2570 final String obj = genericObjectPool.borrowObject();
2571 genericObjectPool.preparePool();
2572 assertEquals(0, genericObjectPool.getNumIdle());
2573 genericObjectPool.setMinIdle(0);
2574 genericObjectPool.returnObject(obj);
2575 genericObjectPool.preparePool();
2576 assertEquals(1, genericObjectPool.getNumIdle());
2577 }
2578
2579
2580
2581
2582
2583
2584 @Test
2585 @Timeout(value = 10_000, unit = TimeUnit.MILLISECONDS)
2586 void testReturnAndInvalidateServesWaiters() throws Exception {
2587 genericObjectPool.setMaxTotal(2);
2588 genericObjectPool.setBlockWhenExhausted(true);
2589 genericObjectPool.setMaxWait(Duration.ofMillis(100));
2590
2591
2592 final String obj1 = genericObjectPool.borrowObject();
2593 final String obj2 = genericObjectPool.borrowObject();
2594
2595
2596 final AtomicInteger successfulBorrows = new AtomicInteger(0);
2597
2598
2599 final Thread borrower1 = new Thread(() -> {
2600 try {
2601 genericObjectPool.borrowObject();
2602 successfulBorrows.incrementAndGet();
2603 } catch (final Exception e) {
2604
2605 }
2606 });
2607
2608 final Thread borrower2 = new Thread(() -> {
2609 try {
2610 genericObjectPool.borrowObject();
2611 successfulBorrows.incrementAndGet();
2612 } catch (final Exception e) {
2613
2614 }
2615 });
2616
2617
2618 borrower1.start();
2619 borrower2.start();
2620 Thread.sleep(50);
2621
2622
2623 genericObjectPool.invalidateObject(obj1);
2624 genericObjectPool.invalidateObject(obj2);
2625
2626
2627 borrower1.join();
2628 borrower2.join();
2629
2630
2631 assertEquals(2, successfulBorrows.get(),
2632 "Both waiting threads should have been served, but only " + successfulBorrows.get() + " were served");
2633 }
2634
2635 @Test
2636 @Timeout(value = 1200, unit = TimeUnit.MILLISECONDS)
2637 void testReturnBorrowObjectWithingMaxWaitDuration() throws Exception {
2638 final Duration maxWaitDuration = Duration.ofMillis(500);
2639 try (GenericObjectPool<String> createSlowObjectFactoryPool = new GenericObjectPool<>(createSlowObjectFactory(Duration.ofSeconds(60)))) {
2640 createSlowObjectFactoryPool.setMaxTotal(1);
2641 createSlowObjectFactoryPool.setMaxWait(maxWaitDuration);
2642
2643 final WaitingTestThread thread1 = new WaitingTestThread(createSlowObjectFactoryPool, 0);
2644 thread1.start();
2645
2646 Thread.sleep(100);
2647
2648 assertThrows(NoSuchElementException.class, () -> createSlowObjectFactoryPool.borrowObject(maxWaitDuration),
2649 "borrowObject must fail due to timeout by maxWait");
2650 assertTrue(thread1.isAlive());
2651 }
2652 }
2653
2654 @Test
2655 @Timeout(value = 1200, unit = TimeUnit.MILLISECONDS)
2656 void testReturnBorrowObjectWithingMaxWaitMillis() throws Exception {
2657 final long maxWaitMillis = 500;
2658 try (GenericObjectPool<String> createSlowObjectFactoryPool = new GenericObjectPool<>(createSlowObjectFactory(Duration.ofSeconds(60)))) {
2659 createSlowObjectFactoryPool.setMaxTotal(1);
2660 createSlowObjectFactoryPool.setMaxWaitMillis(maxWaitMillis);
2661
2662 final WaitingTestThread thread1 = new WaitingTestThread(createSlowObjectFactoryPool, 0);
2663 thread1.start();
2664
2665 Thread.sleep(100);
2666
2667 assertThrows(NoSuchElementException.class, () -> createSlowObjectFactoryPool.borrowObject(maxWaitMillis),
2668 "borrowObject must fail due to timeout by maxWait");
2669 assertTrue(thread1.isAlive());
2670 }
2671 }
2672
2673
2674
2675
2676
2677
2678
2679 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2680 void testReturnObject() throws Exception {
2681 genericObjectPool.setMaxTotal(1);
2682 genericObjectPool.setMaxIdle(-1);
2683 final String active = genericObjectPool.borrowObject();
2684 assertEquals(1, genericObjectPool.getNumActive());
2685 assertEquals(0, genericObjectPool.getNumIdle());
2686 final Thread t = new Thread(() -> genericObjectPool.close());
2687 t.start();
2688 genericObjectPool.returnObject(active);
2689
2690 while (t.isAlive()) {
2691 Thread.sleep(50);
2692 }
2693 assertEquals(0, genericObjectPool.getNumIdle());
2694 }
2695
2696 @Test
2697 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2698 void testSetConfig() throws Exception {
2699 final GenericObjectPoolConfig<String> expected = new GenericObjectPoolConfig<>();
2700 assertConfiguration(expected, genericObjectPool);
2701 expected.setMaxTotal(2);
2702 expected.setMaxIdle(3);
2703 expected.setMaxWait(Duration.ofMillis(5));
2704 expected.setMinEvictableIdleDuration(Duration.ofMillis(7L));
2705 expected.setNumTestsPerEvictionRun(9);
2706 expected.setTestOnCreate(true);
2707 expected.setTestOnBorrow(true);
2708 expected.setTestOnReturn(true);
2709 expected.setTestWhileIdle(true);
2710 expected.setTimeBetweenEvictionRuns(Duration.ofMillis(11L));
2711 expected.setBlockWhenExhausted(false);
2712 genericObjectPool.setConfig(expected);
2713 assertConfiguration(expected, genericObjectPool);
2714 }
2715
2716 @Test
2717 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2718 void testSettersAndGetters() throws Exception {
2719 {
2720
2721
2722 assertNotEquals("", genericObjectPool.getCreationStackTrace());
2723 }
2724 {
2725 assertEquals(0, genericObjectPool.getBorrowedCount());
2726 }
2727 {
2728 assertEquals(0, genericObjectPool.getReturnedCount());
2729 }
2730 {
2731 assertEquals(0, genericObjectPool.getCreatedCount());
2732 }
2733 {
2734 assertEquals(0, genericObjectPool.getDestroyedCount());
2735 }
2736 {
2737 assertEquals(0, genericObjectPool.getDestroyedByEvictorCount());
2738 }
2739 {
2740 assertEquals(0, genericObjectPool.getDestroyedByBorrowValidationCount());
2741 }
2742 {
2743 assertEquals(0, genericObjectPool.getMeanActiveTimeMillis());
2744 }
2745 {
2746 assertEquals(0, genericObjectPool.getMeanIdleTimeMillis());
2747 }
2748 {
2749 assertEquals(0, genericObjectPool.getMeanBorrowWaitTimeMillis());
2750 }
2751 {
2752 assertEquals(0, genericObjectPool.getMaxBorrowWaitTimeMillis());
2753 }
2754 {
2755 assertEquals(0, genericObjectPool.getNumIdle());
2756 }
2757 {
2758 genericObjectPool.setMaxTotal(123);
2759 assertEquals(123, genericObjectPool.getMaxTotal());
2760 }
2761 {
2762 genericObjectPool.setMaxIdle(12);
2763 assertEquals(12, genericObjectPool.getMaxIdle());
2764 }
2765 {
2766 genericObjectPool.setMaxWaitMillis(1234L);
2767 assertEquals(1234L, genericObjectPool.getMaxWaitMillis());
2768 }
2769 {
2770 genericObjectPool.setMinEvictableIdleTimeMillis(12345L);
2771 assertEquals(12345L, genericObjectPool.getMinEvictableIdleDuration().toMillis());
2772 assertEquals(12345L, genericObjectPool.getMinEvictableIdleTimeMillis());
2773 assertEquals(12345L, genericObjectPool.getMinEvictableIdleTime().toMillis());
2774 }
2775 {
2776 genericObjectPool.setNumTestsPerEvictionRun(11);
2777 assertEquals(11, genericObjectPool.getNumTestsPerEvictionRun());
2778 }
2779 {
2780 genericObjectPool.setTestOnBorrow(true);
2781 assertTrue(genericObjectPool.getTestOnBorrow());
2782 genericObjectPool.setTestOnBorrow(false);
2783 assertFalse(genericObjectPool.getTestOnBorrow());
2784 }
2785 {
2786 genericObjectPool.setTestOnReturn(true);
2787 assertTrue(genericObjectPool.getTestOnReturn());
2788 genericObjectPool.setTestOnReturn(false);
2789 assertFalse(genericObjectPool.getTestOnReturn());
2790 }
2791 {
2792 genericObjectPool.setTestWhileIdle(true);
2793 assertTrue(genericObjectPool.getTestWhileIdle());
2794 genericObjectPool.setTestWhileIdle(false);
2795 assertFalse(genericObjectPool.getTestWhileIdle());
2796 }
2797 {
2798 genericObjectPool.setTimeBetweenEvictionRunsMillis(11235L);
2799 assertEquals(11235L, genericObjectPool.getDurationBetweenEvictionRuns().toMillis());
2800 assertEquals(11235L, genericObjectPool.getTimeBetweenEvictionRunsMillis());
2801 assertEquals(11235L, genericObjectPool.getTimeBetweenEvictionRuns().toMillis());
2802 }
2803 {
2804 genericObjectPool.setSoftMinEvictableIdleTimeMillis(12135L);
2805 assertEquals(12135L, genericObjectPool.getSoftMinEvictableIdleDuration().toMillis());
2806 assertEquals(12135L, genericObjectPool.getSoftMinEvictableIdleTimeMillis());
2807 assertEquals(12135L, genericObjectPool.getSoftMinEvictableIdleTime().toMillis());
2808 }
2809 {
2810 genericObjectPool.setBlockWhenExhausted(true);
2811 assertTrue(genericObjectPool.getBlockWhenExhausted());
2812 genericObjectPool.setBlockWhenExhausted(false);
2813 assertFalse(genericObjectPool.getBlockWhenExhausted());
2814 }
2815 }
2816
2817 @Test
2818 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2819 void testStartAndStopEvictor() throws Exception {
2820
2821 genericObjectPool.setMaxIdle(6);
2822 genericObjectPool.setMaxTotal(6);
2823 genericObjectPool.setNumTestsPerEvictionRun(6);
2824 genericObjectPool.setMinEvictableIdleTime(Duration.ofMillis(100));
2825 for (int j = 0; j < 2; j++) {
2826
2827 {
2828 final String[] active = new String[6];
2829 for (int i = 0; i < 6; i++) {
2830 active[i] = genericObjectPool.borrowObject();
2831 }
2832 for (int i = 0; i < 6; i++) {
2833 genericObjectPool.returnObject(active[i]);
2834 }
2835 }
2836
2837 assertEquals(6, genericObjectPool.getNumIdle(), "Should have 6 idle");
2838
2839 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(50));
2840
2841 Waiter.sleepQuietly(200L);
2842
2843 assertEquals(0, genericObjectPool.getNumIdle(), "Should have 0 idle");
2844
2845 genericObjectPool.startEvictor(Duration.ZERO);
2846 }
2847 }
2848
2849 @Test
2850 void testSwallowedExceptionListener() {
2851 genericObjectPool.setSwallowedExceptionListener(null);
2852 final List<Exception> swallowedExceptions = new ArrayList<>();
2853
2854
2855
2856 final SwallowedExceptionListener listener = e -> {
2857 if (swallowedExceptions.size() == 2) {
2858 throw new OutOfMemoryError();
2859 }
2860 swallowedExceptions.add(e);
2861 };
2862 genericObjectPool.setSwallowedExceptionListener(listener);
2863 final Exception e1 = new Exception();
2864 final Exception e2 = new ArrayIndexOutOfBoundsException();
2865 genericObjectPool.swallowException(e1);
2866 genericObjectPool.swallowException(e2);
2867 assertThrows(OutOfMemoryError.class, () -> genericObjectPool.swallowException(e1));
2868 assertEquals(2, swallowedExceptions.size());
2869 }
2870
2871 @Test
2872 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2873 void testThreaded1() throws Exception {
2874 genericObjectPool.setMaxTotal(15);
2875 genericObjectPool.setMaxIdle(15);
2876 genericObjectPool.setMaxWaitMillis(1000L);
2877 runTestThreads(20, 100, 50, genericObjectPool);
2878 }
2879
2880 @Test
2881 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2882 void testTimeoutNoLeak() throws Exception {
2883 genericObjectPool.setMaxTotal(2);
2884 genericObjectPool.setMaxWaitMillis(10);
2885 genericObjectPool.setBlockWhenExhausted(true);
2886 final String obj = genericObjectPool.borrowObject();
2887 final String obj2 = genericObjectPool.borrowObject();
2888 assertThrows(NoSuchElementException.class, () -> genericObjectPool.borrowObject());
2889 genericObjectPool.returnObject(obj2);
2890 genericObjectPool.returnObject(obj);
2891 genericObjectPool.borrowObject();
2892 genericObjectPool.borrowObject();
2893 }
2894
2895
2896
2897
2898 @Test
2899 void testValidateOnCreate() throws Exception {
2900 genericObjectPool.setTestOnCreate(true);
2901 genericObjectPool.addObject();
2902 assertEquals(1, simpleFactory.validateCounter);
2903 }
2904
2905
2906
2907
2908 @Test
2909 void testValidateOnCreateFailure() throws Exception {
2910 genericObjectPool.setTestOnCreate(true);
2911 genericObjectPool.setTestOnBorrow(false);
2912 genericObjectPool.setMaxTotal(2);
2913 simpleFactory.setValid(false);
2914
2915 genericObjectPool.addObject();
2916 genericObjectPool.addObject();
2917 assertEquals(0, genericObjectPool.getNumIdle());
2918 assertEquals(0, genericObjectPool.getNumActive());
2919 simpleFactory.setValid(true);
2920 final String obj = genericObjectPool.borrowObject();
2921 assertNotNull(obj);
2922 genericObjectPool.addObject();
2923
2924 assertEquals(1, genericObjectPool.getNumIdle());
2925 assertEquals(1, genericObjectPool.getNumActive());
2926 }
2927
2928
2929
2930
2931
2932
2933
2934
2935 @Test
2936 void testValidationFailureOnReturnFreesCapacity() throws Exception {
2937 final SimpleFactory factory = new SimpleFactory();
2938 factory.setValid(false);
2939 factory.setValidationEnabled(true);
2940 try (GenericObjectPool<String> pool = new GenericObjectPool<>(factory)) {
2941 pool.setMaxTotal(2);
2942 pool.setMaxWaitMillis(1500);
2943 pool.setTestOnReturn(true);
2944 pool.setTestOnBorrow(false);
2945
2946 final WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
2947 thread1.start();
2948
2949 final WaitingTestThread thread2 = new WaitingTestThread(pool, 500);
2950 thread2.start();
2951 Thread.sleep(50);
2952
2953 final String obj = pool.borrowObject();
2954 pool.returnObject(obj);
2955 }
2956 }
2957
2958
2959
2960 @Test
2961 void testValidationOnCreateOnly() throws Exception {
2962 genericObjectPool.setMaxTotal(1);
2963 genericObjectPool.setTestOnCreate(true);
2964 genericObjectPool.setTestOnBorrow(false);
2965 genericObjectPool.setTestOnReturn(false);
2966 genericObjectPool.setTestWhileIdle(false);
2967 final String o1 = genericObjectPool.borrowObject();
2968 assertEquals("0", o1);
2969 final Timer t = new Timer();
2970 t.schedule(new TimerTask() {
2971 @Override
2972 public void run() {
2973 genericObjectPool.returnObject(o1);
2974 }
2975 }, 3000);
2976 final String o2 = genericObjectPool.borrowObject();
2977 assertEquals("0", o2);
2978 assertEquals(1, simpleFactory.validateCounter);
2979 }
2980
2981 @Test
2982 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2983 void testWhenExhaustedBlock() throws Exception {
2984 genericObjectPool.setMaxTotal(1);
2985 genericObjectPool.setBlockWhenExhausted(true);
2986 genericObjectPool.setMaxWaitMillis(10L);
2987 final String obj1 = genericObjectPool.borrowObject();
2988 assertNotNull(obj1);
2989 assertThrows(NoSuchElementException.class, () -> genericObjectPool.borrowObject());
2990 genericObjectPool.returnObject(obj1);
2991 genericObjectPool.close();
2992 }
2993
2994
2995
2996
2997
2998
2999 @Test
3000 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
3001 void testWhenExhaustedBlockClosePool() throws Exception {
3002 genericObjectPool.setMaxTotal(1);
3003 genericObjectPool.setBlockWhenExhausted(true);
3004 genericObjectPool.setMaxWaitMillis(-1);
3005 final Object obj1 = genericObjectPool.borrowObject();
3006
3007 assertNotNull(obj1);
3008
3009 final WaitingTestThread wtt = new WaitingTestThread(genericObjectPool, 200);
3010 wtt.start();
3011
3012 Thread.sleep(200);
3013
3014 genericObjectPool.close();
3015
3016 Thread.sleep(200);
3017
3018 assertTrue(wtt.thrown instanceof InterruptedException);
3019 }
3020
3021 @Test
3022 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
3023 void testWhenExhaustedBlockInterrupt() throws Exception {
3024 genericObjectPool.setMaxTotal(1);
3025 genericObjectPool.setBlockWhenExhausted(true);
3026 genericObjectPool.setMaxWaitMillis(-1);
3027 final String obj1 = genericObjectPool.borrowObject();
3028
3029 assertNotNull(obj1);
3030
3031 final WaitingTestThread wtt = new WaitingTestThread(genericObjectPool, 200000);
3032 wtt.start();
3033
3034 Thread.sleep(200);
3035 wtt.interrupt();
3036
3037 Thread.sleep(200);
3038
3039 assertTrue(wtt.thrown instanceof InterruptedException);
3040
3041 genericObjectPool.returnObject(obj1);
3042
3043 genericObjectPool.setMaxWaitMillis(10L);
3044 String obj2 = null;
3045 try {
3046 obj2 = genericObjectPool.borrowObject();
3047 assertNotNull(obj2);
3048 } catch (final NoSuchElementException e) {
3049
3050 fail("NoSuchElementException not expected");
3051 }
3052 genericObjectPool.returnObject(obj2);
3053 genericObjectPool.close();
3054 }
3055
3056 @Test
3057 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
3058 void testWhenExhaustedFail() throws Exception {
3059 genericObjectPool.setMaxTotal(1);
3060 genericObjectPool.setBlockWhenExhausted(false);
3061 final String obj1 = genericObjectPool.borrowObject();
3062 assertNotNull(obj1);
3063 assertThrows(NoSuchElementException.class, () -> genericObjectPool.borrowObject());
3064 genericObjectPool.returnObject(obj1);
3065 assertEquals(1, genericObjectPool.getNumIdle());
3066 genericObjectPool.close();
3067 }
3068 }