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 private List<Runnable> getRunnables(final int numThreads,
847 final CountDownLatch startLatch,
848 final CountDownLatch doneLatch) {
849 final List<Runnable> tasks = new ArrayList<>();
850
851 for (int i = 0; i < numThreads; i++) {
852 tasks.add(() -> {
853 try {
854 startLatch.await();
855 genericObjectPool.addObject();
856 } catch (final Exception e) {
857 Thread.currentThread().interrupt();
858 } finally {
859 doneLatch.countDown();
860 }
861 });
862 }
863 return tasks;
864 }
865
866 @Override
867 protected boolean isFifo() {
868 return false;
869 }
870
871 @Override
872 protected boolean isLifo() {
873 return true;
874 }
875
876 @Override
877 protected ObjectPool<String> makeEmptyPool(final int minCap) {
878 final GenericObjectPool<String> mtPool = new GenericObjectPool<>(new SimpleFactory());
879 mtPool.setMaxTotal(minCap);
880 mtPool.setMaxIdle(minCap);
881 return mtPool;
882 }
883
884 @Override
885 protected <E extends Exception> ObjectPool<Object> makeEmptyPool(final PooledObjectFactory<Object> fac) {
886 return new GenericObjectPool<>(fac);
887 }
888
889
890
891
892 private <T> void runTestThreads(final int numThreads, final int iterations, final int delay, final GenericObjectPool<T> testPool) {
893 final TestThread<T>[] threads = new TestThread[numThreads];
894 for (int i = 0; i < numThreads; i++) {
895 threads[i] = new TestThread<>(testPool, iterations, delay);
896 final Thread t = new Thread(threads[i]);
897 t.start();
898 }
899 for (int i = 0; i < numThreads; i++) {
900 while (!threads[i].complete()) {
901 Waiter.sleepQuietly(500L);
902 }
903 if (threads[i].failed()) {
904 fail("Thread " + i + " failed: " + threads[i].error.toString());
905 }
906 }
907 }
908
909 @BeforeEach
910 public void setUp() {
911 simpleFactory = new SimpleFactory();
912 genericObjectPool = new GenericObjectPool<>(simpleFactory);
913 }
914
915 @AfterEach
916 public void tearDown() throws Exception {
917 final ObjectName jmxName = genericObjectPool.getJmxName();
918 final String poolName = Objects.toString(jmxName, null);
919 genericObjectPool.clear();
920 genericObjectPool.close();
921 genericObjectPool = null;
922 simpleFactory = null;
923 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
924 final Set<ObjectName> result = mbs.queryNames(new ObjectName("org.apache.commoms.pool2:type=GenericObjectPool,*"), null);
925
926 final int registeredPoolCount = result.size();
927 final StringBuilder msg = new StringBuilder("Current pool is: ");
928 msg.append(poolName);
929 msg.append(" Still open pools are: ");
930 for (final ObjectName name : result) {
931
932 msg.append(name.toString());
933 msg.append(" created via\n");
934 msg.append(mbs.getAttribute(name, "CreationStackTrace"));
935 msg.append('\n');
936 mbs.unregisterMBean(name);
937 }
938 assertEquals(0, registeredPoolCount, msg.toString());
939
940 Thread.yield();
941 if (EvictionTimer.getExecutor() != null) {
942 Thread.sleep(1000);
943 }
944 assertNull(EvictionTimer.getExecutor(), "EvictionTimer.getExecutor()");
945 }
946
947
948
949
950
951
952
953
954
955 @SuppressWarnings("deprecation")
956 @Test
957 void testAbandonedPool() throws Exception {
958 final GenericObjectPoolConfig<String> config = new GenericObjectPoolConfig<>();
959 config.setJmxEnabled(false);
960
961
962
963
964 GenericObjectPool<String> abandoned1 = new GenericObjectPool<>(simpleFactory, config);
965 abandoned1.setDurationBetweenEvictionRuns(Duration.ofMillis(100));
966 GenericObjectPool<String> abandoned2 = new GenericObjectPool<>(simpleFactory, config);
967 abandoned2.setDurationBetweenEvictionRuns(Duration.ofMillis(100));
968
969
970 final WeakReference<GenericObjectPool<String>> ref1 = new WeakReference<>(abandoned1);
971 abandoned1 = null;
972 while (ref1.get() != null) {
973 System.gc();
974 Thread.sleep(100);
975 }
976 final WeakReference<GenericObjectPool<String>> ref2 = new WeakReference<>(abandoned2);
977 abandoned2 = null;
978 while (ref2.get() != null) {
979 System.gc();
980 Thread.sleep(100);
981 }
982 }
983
984 @Test
985 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
986 void testAddObject() throws Exception {
987 assertEquals(0, genericObjectPool.getNumIdle(), "should be zero idle");
988 genericObjectPool.addObject();
989 assertEquals(1, genericObjectPool.getNumIdle(), "should be one idle");
990 assertEquals(0, genericObjectPool.getNumActive(), "should be zero active");
991 final String obj = genericObjectPool.borrowObject();
992 assertEquals(0, genericObjectPool.getNumIdle(), "should be zero idle");
993 assertEquals(1, genericObjectPool.getNumActive(), "should be one active");
994 genericObjectPool.returnObject(obj);
995 assertEquals(1, genericObjectPool.getNumIdle(), "should be one idle");
996 assertEquals(0, genericObjectPool.getNumActive(), "should be zero active");
997 }
998
999 @Test
1000 void testAddObjectCanAddToMaxIdle() throws Exception {
1001 genericObjectPool.setMaxTotal(5);
1002 genericObjectPool.borrowObject();
1003 genericObjectPool.borrowObject();
1004 genericObjectPool.setMaxIdle(3);
1005 for (int i = 0; i < 3; i++) {
1006 genericObjectPool.addObject();
1007 }
1008 assertEquals(3, genericObjectPool.getNumIdle());
1009 }
1010
1011 @Disabled("WIP for https://issues.apache.org/jira/browse/POOL-413")
1012 @Test
1013 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1014 void testAddObjectConcurrentCallsRespectsMaxIdle() throws Exception {
1015 final int maxIdleLimit = 5;
1016 final int numThreads = 10;
1017 genericObjectPool.setMaxIdle(maxIdleLimit);
1018
1019 final CountDownLatch startLatch = new CountDownLatch(1);
1020 final CountDownLatch doneLatch = new CountDownLatch(numThreads);
1021
1022 final List<Runnable> tasks = getRunnables(numThreads, startLatch, doneLatch);
1023
1024 final ExecutorService executorService = Executors.newFixedThreadPool(numThreads);
1025 tasks.forEach(executorService::submit);
1026 try {
1027 startLatch.countDown();
1028 doneLatch.await();
1029 } finally {
1030 executorService.shutdown();
1031 assertTrue(executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS));
1032 }
1033
1034 assertTrue(genericObjectPool.getNumIdle() <= maxIdleLimit,
1035 "Concurrent addObject() calls should not exceed maxIdle limit of " + maxIdleLimit +
1036 ", but found " + genericObjectPool.getNumIdle() + " idle objects");
1037 }
1038
1039 @Test
1040 @Timeout(value = 400, unit = TimeUnit.MILLISECONDS)
1041 void testAddObjectFastReturn() throws Exception {
1042 final SimpleFactory simpleFactory = new SimpleFactory();
1043 simpleFactory.makeLatency = 500;
1044 try (GenericObjectPool<String> pool = new GenericObjectPool<>(simpleFactory)) {
1045 pool.setMaxTotal(1);
1046 pool.setBlockWhenExhausted(true);
1047 pool.setMaxWait(Duration.ofMillis(1000));
1048
1049 final TestThread<String> thread = new TestThread<>(pool);
1050 final Thread t = new Thread(thread);
1051 t.start();
1052 Thread.sleep(50);
1053 pool.addObject();
1054 }
1055 }
1056
1057 @Test
1058 void testAddObjectNegativeMaxIdle() throws Exception {
1059 genericObjectPool.setMaxIdle(-1);
1060 genericObjectPool.addObject();
1061 assertEquals(1, genericObjectPool.getNumIdle());
1062 }
1063
1064 @Test
1065 void testAddObjectNegativeMaxTotal() throws Exception {
1066 genericObjectPool.setMaxTotal(-1);
1067 genericObjectPool.addObject();
1068 assertEquals(1, genericObjectPool.getNumIdle());
1069 }
1070
1071 @Test
1072 void testAddObjectRespectsMaxIdle() throws Exception {
1073 genericObjectPool.setMaxIdle(1);
1074 genericObjectPool.addObject();
1075 genericObjectPool.addObject();
1076 assertEquals(1, genericObjectPool.getNumIdle());
1077 }
1078
1079 @Test
1080 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1081 void testAddObjectRespectsMaxIdleLimit() throws Exception {
1082 genericObjectPool.setMaxIdle(1);
1083 genericObjectPool.addObject();
1084 genericObjectPool.addObject();
1085 assertEquals(1, genericObjectPool.getNumIdle(), "should be one idle");
1086
1087 genericObjectPool.setMaxIdle(-1);
1088 genericObjectPool.addObject();
1089 genericObjectPool.addObject();
1090 genericObjectPool.addObject();
1091 assertEquals(4, genericObjectPool.getNumIdle(), "should be four idle");
1092 }
1093
1094 @Test
1095 void testAddObjectRespectsMaxTotal() throws Exception {
1096 genericObjectPool.setMaxTotal(1);
1097 genericObjectPool.addObject();
1098 genericObjectPool.addObject();
1099 assertEquals(1, genericObjectPool.getNumIdle());
1100 }
1101
1102 @Test
1103 void testAddObjectZeroMaxIdle() throws Exception {
1104 genericObjectPool.setMaxIdle(0);
1105 genericObjectPool.addObject();
1106 assertEquals(0, genericObjectPool.getNumIdle());
1107 }
1108
1109 @Test
1110 void testAppendStats() {
1111 assertFalse(genericObjectPool.getMessageStatistics());
1112 assertEquals("foo", genericObjectPool.appendStats("foo"));
1113 try (GenericObjectPool<?> pool = new GenericObjectPool<>(new SimpleFactory())) {
1114 pool.setMessagesStatistics(true);
1115 assertNotEquals("foo", pool.appendStats("foo"));
1116 pool.setMessagesStatistics(false);
1117 assertEquals("foo", pool.appendStats("foo"));
1118 }
1119 }
1120
1121
1122
1123
1124
1125 @SuppressWarnings({ "rawtypes", "unchecked" })
1126 @Test
1127 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1128 void testBorrowObjectFairness() throws Exception {
1129 final int numThreads = 40;
1130 final int maxTotal = 40;
1131 final GenericObjectPoolConfig config = new GenericObjectPoolConfig();
1132 config.setMaxTotal(maxTotal);
1133 config.setMaxIdle(maxTotal);
1134 config.setFairness(true);
1135 config.setLifo(false);
1136 genericObjectPool = new GenericObjectPool(simpleFactory, config);
1137
1138 final String[] objects = new String[maxTotal];
1139 for (int i = 0; i < maxTotal; i++) {
1140 objects[i] = genericObjectPool.borrowObject();
1141 }
1142
1143 final TestThread[] threads = new TestThread[numThreads];
1144 for (int i = 0; i < numThreads; i++) {
1145 threads[i] = new TestThread(genericObjectPool, 1, 0, 2000, false, String.valueOf(i % maxTotal));
1146 final Thread t = new Thread(threads[i]);
1147 t.start();
1148
1149 try {
1150 Thread.sleep(10);
1151 } catch (final InterruptedException e) {
1152 fail(e.toString());
1153 }
1154 }
1155
1156 for (int i = 0; i < maxTotal; i++) {
1157 genericObjectPool.returnObject(objects[i]);
1158 }
1159
1160 for (int i = 0; i < numThreads; i++) {
1161 while (!threads[i].complete()) {
1162 Waiter.sleepQuietly(500L);
1163 }
1164 if (threads[i].failed()) {
1165 fail("Thread " + i + " failed: " + threads[i].error.toString());
1166 }
1167 }
1168 }
1169
1170 @Test
1171 @Timeout(value = 1200, unit = TimeUnit.MILLISECONDS)
1172 void testBorrowObjectOverrideMaxWaitLarge() throws Exception {
1173 try (GenericObjectPool<String> pool = new GenericObjectPool<>(createSlowObjectFactory(Duration.ofSeconds(60)))) {
1174 pool.setMaxTotal(1);
1175 pool.setMaxWait(Duration.ofMillis(1_000));
1176 pool.setBlockWhenExhausted(false);
1177
1178 final WaitingTestThread thread1 = new WaitingTestThread(pool, 0);
1179 thread1.start();
1180
1181 Thread.sleep(100);
1182
1183 final Duration d = DurationUtils.of(() -> assertThrows(NoSuchElementException.class, () -> pool.borrowObject(Duration.ofMillis(1)),
1184 "borrowObject must fail quickly due to timeout parameter"));
1185 final long millis = d.toMillis();
1186 final long nanos = d.toNanos();
1187 assertTrue(nanos >= 0, () -> "borrowObject(Duration) argument not respected: " + nanos);
1188 assertTrue(millis >= 0, () -> "borrowObject(Duration) argument not respected: " + millis);
1189 assertTrue(millis < 50, () -> "borrowObject(Duration) argument not respected: " + millis);
1190 }
1191 }
1192
1193 @Test
1194 @Timeout(value = 1200, unit = TimeUnit.MILLISECONDS)
1195 void testBorrowObjectOverrideMaxWaitSmall() throws Exception {
1196 try (GenericObjectPool<String> pool = new GenericObjectPool<>(createSlowObjectFactory(Duration.ofSeconds(60)))) {
1197 pool.setMaxTotal(1);
1198 pool.setMaxWait(Duration.ofMillis(1));
1199 pool.setBlockWhenExhausted(false);
1200
1201 final WaitingTestThread thread1 = new WaitingTestThread(pool, 0);
1202 thread1.start();
1203
1204 Thread.sleep(100);
1205
1206 final Duration d = DurationUtils.of(() -> assertThrows(NoSuchElementException.class, () -> pool.borrowObject(Duration.ofMillis(500)),
1207 "borrowObject must fail slowly due to timeout parameter"));
1208 final long millis = d.toMillis();
1209 final long nanos = d.toNanos();
1210 assertTrue(nanos >= 0, () -> "borrowObject(Duration) argument not respected: " + nanos);
1211 assertTrue(millis >= 0, () -> "borrowObject(Duration) argument not respected: " + millis);
1212 assertTrue(millis < 600, () -> "borrowObject(Duration) argument not respected: " + millis);
1213 assertTrue(millis > 490, () -> "borrowObject(Duration) argument not respected: " + millis);
1214 }
1215 }
1216
1217 @Test
1218 void testBorrowTimings() throws Exception {
1219
1220 final String object = genericObjectPool.borrowObject();
1221 final PooledObject<String> po = genericObjectPool.getPooledObject(object);
1222
1223
1224
1225
1226 final Instant lastBorrowInstant1 = po.getLastBorrowInstant();
1227 final Instant lastReturnInstant1 = po.getLastReturnInstant();
1228 final Instant lastUsedInstant1 = po.getLastUsedInstant();
1229 assertTrue(po.getCreateInstant().compareTo(lastBorrowInstant1) <= 0);
1230 assertTrue(po.getCreateInstant().compareTo(lastReturnInstant1) <= 0);
1231 assertTrue(po.getCreateInstant().compareTo(lastUsedInstant1) <= 0);
1232
1233 assertTrue(po.getCreateTime() <= lastBorrowInstant1.toEpochMilli());
1234 assertTrue(po.getCreateTime() <= lastReturnInstant1.toEpochMilli());
1235 assertTrue(po.getCreateTime() <= lastUsedInstant1.toEpochMilli());
1236
1237
1238 Thread.sleep(200);
1239 assertFalse(po.getActiveDuration().isNegative());
1240 assertFalse(po.getActiveDuration().isZero());
1241
1242 assertTrue(Duration.ZERO.compareTo(Duration.ZERO.plusNanos(1)) <= 0);
1243 assertTrue(po.getActiveDuration().compareTo(po.getIdleDuration()) <= 0);
1244
1245 assertTrue(po.getActiveDuration().toMillis() <= po.getActiveTimeMillis());
1246 assertTrue(po.getActiveDuration().compareTo(po.getIdleDuration()) <= 0);
1247
1248
1249 assertTrue(po.getActiveDuration().compareTo(po.getIdleTime()) <= 0);
1250 assertTrue(po.getActiveDuration().toMillis() <= po.getIdleTimeMillis());
1251
1252 assertTrue(po.getCreateInstant().compareTo(po.getLastBorrowInstant()) <= 0);
1253 assertTrue(po.getCreateInstant().compareTo(po.getLastReturnInstant()) <= 0);
1254 assertTrue(po.getCreateInstant().compareTo(po.getLastUsedInstant()) <= 0);
1255 assertTrue(lastBorrowInstant1.compareTo(po.getLastBorrowInstant()) <= 0);
1256 assertTrue(lastReturnInstant1.compareTo(po.getLastReturnInstant()) <= 0);
1257 assertTrue(lastUsedInstant1.compareTo(po.getLastUsedInstant()) <= 0);
1258 genericObjectPool.returnObject(object);
1259 assertFalse(po.getActiveDuration().isNegative());
1260 assertFalse(po.getActiveDuration().isZero());
1261 assertTrue(po.getActiveDuration().toMillis() <= po.getActiveTimeMillis());
1262 assertTrue(po.getActiveDuration().compareTo(po.getActiveTime()) <= 0);
1263 assertTrue(lastBorrowInstant1.compareTo(po.getLastBorrowInstant()) <= 0);
1264 assertTrue(lastReturnInstant1.compareTo(po.getLastReturnInstant()) <= 0);
1265 assertTrue(lastUsedInstant1.compareTo(po.getLastUsedInstant()) <= 0);
1266 }
1267
1268
1269
1270
1271
1272
1273 @Test
1274 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1275 void testBrokenFactoryShouldNotBlockPool() throws Exception {
1276 final int maxTotal = 1;
1277 simpleFactory.setMaxTotal(maxTotal);
1278 genericObjectPool.setMaxTotal(maxTotal);
1279 genericObjectPool.setBlockWhenExhausted(true);
1280 genericObjectPool.setTestOnBorrow(true);
1281
1282
1283 String obj = null;
1284 Exception ex = null;
1285 simpleFactory.setValid(false);
1286 try {
1287 obj = genericObjectPool.borrowObject();
1288 } catch (final Exception e) {
1289 ex = e;
1290 }
1291
1292 assertNotNull(ex);
1293 assertInstanceOf(NoSuchElementException.class, ex);
1294 assertNull(obj);
1295
1296 simpleFactory.setValid(true);
1297
1298 obj = genericObjectPool.borrowObject();
1299 assertNotNull(obj);
1300 genericObjectPool.returnObject(obj);
1301 }
1302
1303
1304 @Test
1305 void testClientWaitStats() throws Exception {
1306 final SimpleFactory factory = new SimpleFactory();
1307
1308 factory.setMakeLatency(200);
1309 try (GenericObjectPool<String> pool = new GenericObjectPool<>(factory, new GenericObjectPoolConfig<>())) {
1310 final String s = pool.borrowObject();
1311
1312
1313 assertTrue(pool.getMaxBorrowWaitTimeMillis() >= 100);
1314 assertTrue(pool.getMeanBorrowWaitTimeMillis() >= 100);
1315 pool.returnObject(s);
1316 pool.borrowObject();
1317
1318 assertTrue(pool.getMaxBorrowWaitTimeMillis() > 100);
1319 assertTrue(pool.getMeanBorrowWaitTimeMillis() < 200);
1320 assertTrue(pool.getMeanBorrowWaitTimeMillis() > 20);
1321 }
1322 }
1323
1324 @Test
1325 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1326 void testCloseMultiplePools1() {
1327 try (GenericObjectPool<String> genericObjectPool2 = new GenericObjectPool<>(simpleFactory)) {
1328 genericObjectPool.setTimeBetweenEvictionRuns(TestConstants.ONE_MILLISECOND_DURATION);
1329 genericObjectPool2.setTimeBetweenEvictionRuns(TestConstants.ONE_MILLISECOND_DURATION);
1330 }
1331 genericObjectPool.close();
1332 }
1333
1334 @Test
1335 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1336 void testCloseMultiplePools2() throws Exception {
1337 try (GenericObjectPool<String> genericObjectPool2 = new GenericObjectPool<>(simpleFactory)) {
1338
1339 simpleFactory.setDestroyLatency(1000L);
1340
1341 genericObjectPool.setTimeBetweenEvictionRuns(TestConstants.ONE_MILLISECOND_DURATION);
1342 genericObjectPool2.setTimeBetweenEvictionRuns(TestConstants.ONE_MILLISECOND_DURATION);
1343 genericObjectPool.setMinEvictableIdleTime(TestConstants.ONE_MILLISECOND_DURATION);
1344 genericObjectPool2.setMinEvictableIdleTime(TestConstants.ONE_MILLISECOND_DURATION);
1345 genericObjectPool.addObject();
1346 genericObjectPool2.addObject();
1347
1348 }
1349 genericObjectPool.close();
1350 }
1351
1352 @Test
1353 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1354 void testConcurrentBorrowAndEvict() throws Exception {
1355 genericObjectPool.setMaxTotal(1);
1356 genericObjectPool.addObject();
1357 for (int i = 0; i < 5000; i++) {
1358 final ConcurrentBorrowAndEvictThread one = new ConcurrentBorrowAndEvictThread(true);
1359 final ConcurrentBorrowAndEvictThread two = new ConcurrentBorrowAndEvictThread(false);
1360 one.start();
1361 two.start();
1362 one.join();
1363 two.join();
1364 genericObjectPool.returnObject(one.obj);
1365
1366
1367
1368 }
1369 }
1370
1371
1372
1373
1374
1375
1376 @Test
1377 void testConcurrentInvalidate() throws Exception {
1378
1379 final int nObjects = 1000;
1380 genericObjectPool.setMaxTotal(nObjects);
1381 genericObjectPool.setMaxIdle(nObjects);
1382 final String[] obj = new String[nObjects];
1383 for (int i = 0; i < nObjects; i++) {
1384 obj[i] = genericObjectPool.borrowObject();
1385 }
1386 for (int i = 0; i < nObjects; i++) {
1387 if (i % 2 == 0) {
1388 genericObjectPool.returnObject(obj[i]);
1389 }
1390 }
1391 final int nThreads = 20;
1392 final int nIterations = 60;
1393 final InvalidateThread[] threads = new InvalidateThread[nThreads];
1394
1395 final ArrayList<Integer> targets = new ArrayList<>();
1396 final Random random = new Random();
1397 for (int j = 0; j < nIterations; j++) {
1398
1399 Integer targ = Integer.valueOf(random.nextInt(nObjects));
1400 while (targets.contains(targ)) {
1401 targ = Integer.valueOf(random.nextInt(nObjects));
1402 }
1403 targets.add(targ);
1404
1405 for (int i = 0; i < nThreads; i++) {
1406 threads[i] = new InvalidateThread(genericObjectPool, obj[targ.intValue()]);
1407 }
1408 for (int i = 0; i < nThreads; i++) {
1409 new Thread(threads[i]).start();
1410 }
1411 boolean done = false;
1412 while (!done) {
1413 done = true;
1414 for (int i = 0; i < nThreads; i++) {
1415 done = done && threads[i].complete();
1416 }
1417 Thread.sleep(100);
1418 }
1419 }
1420 assertEquals(nIterations, genericObjectPool.getDestroyedCount());
1421 }
1422
1423 @Test
1424 void testConstructorNullFactory() {
1425
1426 assertThrows(IllegalArgumentException.class, () -> new GenericObjectPool<>(null));
1427 }
1428
1429 @Test
1430 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1431 void testConstructors() {
1432
1433 final int minIdle = 2;
1434 final Duration maxWaitDuration = Duration.ofMillis(3);
1435 final long maxWaitMillis = maxWaitDuration.toMillis();
1436 final int maxIdle = 4;
1437 final int maxTotal = 5;
1438 final Duration minEvictableIdleDuration = Duration.ofMillis(6);
1439 final long minEvictableIdleMillis = minEvictableIdleDuration.toMillis();
1440 final int numTestsPerEvictionRun = 7;
1441 final boolean testOnBorrow = true;
1442 final boolean testOnReturn = true;
1443 final boolean testWhileIdle = true;
1444 final long timeBetweenEvictionRunsMillis = 8;
1445 final boolean blockWhenExhausted = false;
1446 final boolean lifo = false;
1447 final PooledObjectFactory<Object> dummyFactory = new DummyFactory();
1448 try (GenericObjectPool<Object> dummyPool = new GenericObjectPool<>(dummyFactory)) {
1449 assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_IDLE, dummyPool.getMaxIdle());
1450 assertEquals(BaseObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS, dummyPool.getMaxWaitMillis());
1451 assertEquals(GenericObjectPoolConfig.DEFAULT_MIN_IDLE, dummyPool.getMinIdle());
1452 assertEquals(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL, dummyPool.getMaxTotal());
1453 assertEquals(BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS, dummyPool.getMinEvictableIdleTimeMillis());
1454 assertEquals(BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME, dummyPool.getMinEvictableIdleTime());
1455 assertEquals(BaseObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME, dummyPool.getMinEvictableIdleDuration());
1456 assertEquals(BaseObjectPoolConfig.DEFAULT_NUM_TESTS_PER_EVICTION_RUN, dummyPool.getNumTestsPerEvictionRun());
1457 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_TEST_ON_BORROW), Boolean.valueOf(dummyPool.getTestOnBorrow()));
1458 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_TEST_ON_RETURN), Boolean.valueOf(dummyPool.getTestOnReturn()));
1459 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_TEST_WHILE_IDLE), Boolean.valueOf(dummyPool.getTestWhileIdle()));
1460 assertEquals(BaseObjectPoolConfig.DEFAULT_DURATION_BETWEEN_EVICTION_RUNS, dummyPool.getDurationBetweenEvictionRuns());
1461 assertEquals(BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS, dummyPool.getTimeBetweenEvictionRunsMillis());
1462 assertEquals(BaseObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS, dummyPool.getTimeBetweenEvictionRuns());
1463 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED), Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
1464 assertEquals(Boolean.valueOf(BaseObjectPoolConfig.DEFAULT_LIFO), Boolean.valueOf(dummyPool.getLifo()));
1465 }
1466 final GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>();
1467 config.setLifo(lifo);
1468 config.setMaxIdle(maxIdle);
1469 config.setMinIdle(minIdle);
1470 config.setMaxTotal(maxTotal);
1471 config.setMaxWait(maxWaitDuration);
1472 config.setMinEvictableIdleTimeMillis(minEvictableIdleMillis);
1473 assertEquals(minEvictableIdleMillis, config.getMinEvictableIdleTime().toMillis());
1474 config.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
1475 config.setTestOnBorrow(testOnBorrow);
1476 config.setTestOnReturn(testOnReturn);
1477 config.setTestWhileIdle(testWhileIdle);
1478 config.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
1479 assertEquals(timeBetweenEvictionRunsMillis, config.getTimeBetweenEvictionRuns().toMillis());
1480 config.setBlockWhenExhausted(blockWhenExhausted);
1481 try (GenericObjectPool<Object> dummyPool = new GenericObjectPool<>(dummyFactory, config)) {
1482 assertEquals(maxIdle, dummyPool.getMaxIdle());
1483 assertEquals(maxWaitDuration, dummyPool.getMaxWaitDuration());
1484 assertEquals(maxWaitMillis, dummyPool.getMaxWaitMillis());
1485 assertEquals(minIdle, dummyPool.getMinIdle());
1486 assertEquals(maxTotal, dummyPool.getMaxTotal());
1487 assertEquals(minEvictableIdleMillis, dummyPool.getMinEvictableIdleTimeMillis());
1488 assertEquals(numTestsPerEvictionRun, dummyPool.getNumTestsPerEvictionRun());
1489 assertEquals(Boolean.valueOf(testOnBorrow), Boolean.valueOf(dummyPool.getTestOnBorrow()));
1490 assertEquals(Boolean.valueOf(testOnReturn), Boolean.valueOf(dummyPool.getTestOnReturn()));
1491 assertEquals(Boolean.valueOf(testWhileIdle), Boolean.valueOf(dummyPool.getTestWhileIdle()));
1492 assertEquals(timeBetweenEvictionRunsMillis, dummyPool.getTimeBetweenEvictionRunsMillis());
1493 assertEquals(Boolean.valueOf(blockWhenExhausted), Boolean.valueOf(dummyPool.getBlockWhenExhausted()));
1494 assertEquals(Boolean.valueOf(lifo), Boolean.valueOf(dummyPool.getLifo()));
1495 }
1496 }
1497
1498 @Test
1499 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1500 void testDefaultConfiguration() {
1501 assertConfiguration(new GenericObjectPoolConfig<>(), genericObjectPool);
1502 }
1503
1504
1505
1506
1507
1508
1509 @Test
1510 void testEqualsIndiscernible() throws Exception {
1511 final HashSetFactory factory = new HashSetFactory();
1512 try (GenericObjectPool<HashSet<String>> pool = new GenericObjectPool<>(factory, new GenericObjectPoolConfig<>())) {
1513 final HashSet<String> s1 = pool.borrowObject();
1514 final HashSet<String> s2 = pool.borrowObject();
1515 pool.returnObject(s1);
1516 pool.returnObject(s2);
1517 }
1518 }
1519
1520 @Test
1521 void testErrorFactoryDoesNotBlockThreads() throws Exception {
1522 final CreateErrorFactory factory = new CreateErrorFactory();
1523 try (GenericObjectPool<String> createFailFactoryPool = new GenericObjectPool<>(factory)) {
1524 createFailFactoryPool.setMaxTotal(1);
1525
1526 final WaitingTestThread thread1 = new WaitingTestThread(createFailFactoryPool, 0);
1527 thread1.start();
1528
1529 while (!factory.hasQueuedThreads()) {
1530 Thread.sleep(200);
1531 }
1532
1533 final WaitingTestThread thread2 = new WaitingTestThread(createFailFactoryPool, 0);
1534 thread2.start();
1535
1536
1537
1538
1539 Thread.sleep(1000);
1540
1541 factory.release();
1542
1543 factory.release();
1544
1545 boolean threadRunning = true;
1546 int count = 0;
1547 while (threadRunning && count < 15) {
1548 threadRunning = thread1.isAlive();
1549 threadRunning = thread2.isAlive();
1550 Thread.sleep(200);
1551 count++;
1552 }
1553 assertFalse(thread1.isAlive());
1554 assertFalse(thread2.isAlive());
1555 assertTrue(thread1.thrown instanceof UnknownError);
1556 assertTrue(thread2.thrown instanceof UnknownError);
1557 }
1558 }
1559
1560
1561
1562
1563
1564
1565 @Test
1566 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1567 void testEvictAddObjects() throws Exception {
1568 simpleFactory.setMakeLatency(300);
1569 simpleFactory.setMaxTotal(2);
1570 genericObjectPool.setMaxTotal(2);
1571 genericObjectPool.setMinIdle(1);
1572 genericObjectPool.borrowObject();
1573
1574
1575 final TestThread<String> borrower = new TestThread<>(genericObjectPool, 1, 150, false);
1576 final Thread borrowerThread = new Thread(borrower);
1577
1578 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(100));
1579 borrowerThread.start();
1580 borrowerThread.join();
1581 assertFalse(borrower.failed());
1582 }
1583
1584 @Test
1585 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1586 void testEvictFIFO() throws Exception {
1587 checkEvict(false);
1588 }
1589
1590 @Test
1591 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1592 void testEviction() throws Exception {
1593 genericObjectPool.setMaxIdle(500);
1594 genericObjectPool.setMaxTotal(500);
1595 genericObjectPool.setNumTestsPerEvictionRun(100);
1596 genericObjectPool.setMinEvictableIdleTime(Duration.ofMillis(250));
1597 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(500));
1598 genericObjectPool.setTestWhileIdle(true);
1599 final String[] active = new String[500];
1600 for (int i = 0; i < 500; i++) {
1601 active[i] = genericObjectPool.borrowObject();
1602 }
1603 for (int i = 0; i < 500; i++) {
1604 genericObjectPool.returnObject(active[i]);
1605 }
1606 Waiter.sleepQuietly(1000L);
1607 assertTrue(genericObjectPool.getNumIdle() < 500, "Should be less than 500 idle, found " + genericObjectPool.getNumIdle());
1608 Waiter.sleepQuietly(600L);
1609 assertTrue(genericObjectPool.getNumIdle() < 400, "Should be less than 400 idle, found " + genericObjectPool.getNumIdle());
1610 Waiter.sleepQuietly(600L);
1611 assertTrue(genericObjectPool.getNumIdle() < 300, "Should be less than 300 idle, found " + genericObjectPool.getNumIdle());
1612 Waiter.sleepQuietly(600L);
1613 assertTrue(genericObjectPool.getNumIdle() < 200, "Should be less than 200 idle, found " + genericObjectPool.getNumIdle());
1614 Waiter.sleepQuietly(600L);
1615 assertTrue(genericObjectPool.getNumIdle() < 100, "Should be less than 100 idle, found " + genericObjectPool.getNumIdle());
1616 Waiter.sleepQuietly(600L);
1617 assertEquals(0, genericObjectPool.getNumIdle(), "Should be zero idle, found " + genericObjectPool.getNumIdle());
1618 for (int i = 0; i < 500; i++) {
1619 active[i] = genericObjectPool.borrowObject();
1620 }
1621 for (int i = 0; i < 500; i++) {
1622 genericObjectPool.returnObject(active[i]);
1623 }
1624 Waiter.sleepQuietly(1000L);
1625 assertTrue(genericObjectPool.getNumIdle() < 500, "Should be less than 500 idle, found " + genericObjectPool.getNumIdle());
1626 Waiter.sleepQuietly(600L);
1627 assertTrue(genericObjectPool.getNumIdle() < 400, "Should be less than 400 idle, found " + genericObjectPool.getNumIdle());
1628 Waiter.sleepQuietly(600L);
1629 assertTrue(genericObjectPool.getNumIdle() < 300, "Should be less than 300 idle, found " + genericObjectPool.getNumIdle());
1630 Waiter.sleepQuietly(600L);
1631 assertTrue(genericObjectPool.getNumIdle() < 200, "Should be less than 200 idle, found " + genericObjectPool.getNumIdle());
1632 Waiter.sleepQuietly(600L);
1633 assertTrue(genericObjectPool.getNumIdle() < 100, "Should be less than 100 idle, found " + genericObjectPool.getNumIdle());
1634 Waiter.sleepQuietly(600L);
1635 assertEquals(0, genericObjectPool.getNumIdle(), "Should be zero idle, found " + genericObjectPool.getNumIdle());
1636 }
1637
1638 @Test
1639 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1640 void testEvictionInvalid() throws Exception {
1641 try (GenericObjectPool<Object> invalidFactoryPool = new GenericObjectPool<>(new InvalidFactory())) {
1642 invalidFactoryPool.setMaxIdle(1);
1643 invalidFactoryPool.setMaxTotal(1);
1644 invalidFactoryPool.setTestOnBorrow(false);
1645 invalidFactoryPool.setTestOnReturn(false);
1646 invalidFactoryPool.setTestWhileIdle(true);
1647 invalidFactoryPool.setMinEvictableIdleTime(Duration.ofSeconds(100));
1648 invalidFactoryPool.setNumTestsPerEvictionRun(1);
1649 final Object p = invalidFactoryPool.borrowObject();
1650 invalidFactoryPool.returnObject(p);
1651
1652 final Thread t = new EvictionThread<>(invalidFactoryPool);
1653 t.start();
1654
1655 Thread.sleep(300);
1656 try {
1657 invalidFactoryPool.borrowObject(1);
1658 } catch (final NoSuchElementException nsee) {
1659
1660 }
1661
1662 Thread.sleep(1000);
1663
1664 assertEquals(0, invalidFactoryPool.getNumIdle(), "Idle count different than expected.");
1665 assertEquals(0, invalidFactoryPool.getNumActive(), "Total count different than expected.");
1666 }
1667 }
1668
1669
1670
1671
1672
1673
1674
1675
1676 @Test
1677 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1678 void testEvictionOrder() throws Exception {
1679 checkEvictionOrder(false);
1680 tearDown();
1681 setUp();
1682 checkEvictionOrder(true);
1683 }
1684
1685 @Test
1686 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1687 void testEvictionPolicy() throws Exception {
1688 genericObjectPool.setMaxIdle(500);
1689 genericObjectPool.setMaxTotal(500);
1690 genericObjectPool.setNumTestsPerEvictionRun(500);
1691 genericObjectPool.setMinEvictableIdleTime(Duration.ofMillis(250));
1692 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(500));
1693 genericObjectPool.setTestWhileIdle(true);
1694
1695 assertThrows(IllegalArgumentException.class, () -> genericObjectPool.setEvictionPolicyClassName(Long.toString(System.currentTimeMillis())),
1696 "setEvictionPolicyClassName must throw an error if the class name is invalid.");
1697
1698 assertThrows(IllegalArgumentException.class, () -> genericObjectPool.setEvictionPolicyClassName(Serializable.class.getName()),
1699 "setEvictionPolicyClassName must throw an error if the class name is invalid.");
1700
1701 assertThrows(IllegalArgumentException.class, () -> genericObjectPool.setEvictionPolicyClassName(Collections.class.getName()),
1702 "setEvictionPolicyClassName must throw an error if the class name is invalid.");
1703 assertThrows(IllegalArgumentException.class, () -> genericObjectPool.setEvictionPolicyClassName(String.class.getName()),
1704 () -> "setEvictionPolicyClassName must throw an error if a class that does not implement EvictionPolicy is specified.");
1705 genericObjectPool.setEvictionPolicy(new TestEvictionPolicy<>());
1706 assertEquals(TestEvictionPolicy.class.getName(), genericObjectPool.getEvictionPolicyClassName());
1707 genericObjectPool.setEvictionPolicyClassName(TestEvictionPolicy.class.getName());
1708 assertEquals(TestEvictionPolicy.class.getName(), genericObjectPool.getEvictionPolicyClassName());
1709 final String[] active = new String[500];
1710 for (int i = 0; i < 500; i++) {
1711 active[i] = genericObjectPool.borrowObject();
1712 }
1713 for (int i = 0; i < 500; i++) {
1714 genericObjectPool.returnObject(active[i]);
1715 }
1716
1717
1718
1719 Waiter.sleepQuietly(1000L);
1720 assertEquals(500, genericObjectPool.getNumIdle(), "Should be 500 idle");
1721
1722
1723 Waiter.sleepQuietly(2000L);
1724 assertEquals(0, genericObjectPool.getNumIdle(), "Should be 0 idle");
1725 }
1726
1727 @Test
1728 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1729 void testEvictionSoftMinIdle() throws Exception {
1730 final class TimeTest extends BasePooledObjectFactory<TimeTest> {
1731 private final long createTimeMillis;
1732
1733 TimeTest() {
1734 createTimeMillis = System.currentTimeMillis();
1735 }
1736
1737 @Override
1738 public TimeTest create() {
1739 return new TimeTest();
1740 }
1741
1742 public long getCreateTimeMillis() {
1743 return createTimeMillis;
1744 }
1745
1746 @Override
1747 public PooledObject<TimeTest> wrap(final TimeTest value) {
1748 return new DefaultPooledObject<>(value);
1749 }
1750 }
1751 try (GenericObjectPool<TimeTest> timePool = new GenericObjectPool<>(new TimeTest())) {
1752 timePool.setMaxIdle(5);
1753 timePool.setMaxTotal(5);
1754 timePool.setNumTestsPerEvictionRun(5);
1755 timePool.setMinEvictableIdleDuration(Duration.ofSeconds(3));
1756 timePool.setMinEvictableIdle(Duration.ofSeconds(3));
1757 timePool.setMinEvictableIdleTime(Duration.ofSeconds(3));
1758 timePool.setSoftMinEvictableIdleTime(TestConstants.ONE_SECOND_DURATION);
1759 timePool.setMinIdle(2);
1760 final TimeTest[] active = new TimeTest[5];
1761 final Long[] creationTime = new Long[5];
1762 for (int i = 0; i < 5; i++) {
1763 active[i] = timePool.borrowObject();
1764 creationTime[i] = Long.valueOf(active[i].getCreateTimeMillis());
1765 }
1766 for (int i = 0; i < 5; i++) {
1767 timePool.returnObject(active[i]);
1768 }
1769
1770 Thread.sleep(1500L);
1771 timePool.evict();
1772 assertEquals(2, timePool.getNumIdle(), "Idle count different than expected.");
1773
1774 Thread.sleep(2000L);
1775 timePool.evict();
1776 assertEquals(0, timePool.getNumIdle(), "Idle count different than expected.");
1777 }
1778 }
1779
1780 @Test
1781 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1782 void testEvictionWithNegativeNumTests() throws Exception {
1783
1784 genericObjectPool.setMaxIdle(6);
1785 genericObjectPool.setMaxTotal(6);
1786 genericObjectPool.setNumTestsPerEvictionRun(-2);
1787 genericObjectPool.setMinEvictableIdleTime(Duration.ofMillis(50));
1788 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(100));
1789 final String[] active = new String[6];
1790 for (int i = 0; i < 6; i++) {
1791 active[i] = genericObjectPool.borrowObject();
1792 }
1793 for (int i = 0; i < 6; i++) {
1794 genericObjectPool.returnObject(active[i]);
1795 }
1796 Waiter.sleepQuietly(100L);
1797 assertTrue(genericObjectPool.getNumIdle() <= 6, "Should at most 6 idle, found " + genericObjectPool.getNumIdle());
1798 Waiter.sleepQuietly(100L);
1799 assertTrue(genericObjectPool.getNumIdle() <= 3, "Should at most 3 idle, found " + genericObjectPool.getNumIdle());
1800 Waiter.sleepQuietly(100L);
1801 assertTrue(genericObjectPool.getNumIdle() <= 2, "Should be at most 2 idle, found " + genericObjectPool.getNumIdle());
1802 Waiter.sleepQuietly(100L);
1803 assertEquals(0, genericObjectPool.getNumIdle(), "Should be zero idle, found " + genericObjectPool.getNumIdle());
1804 }
1805
1806 @Test
1807 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1808 void testEvictLIFO() throws Exception {
1809 checkEvict(true);
1810 }
1811
1812
1813
1814
1815
1816
1817 @Test
1818 void testEvictorVisiting() throws Exception {
1819 checkEvictorVisiting(true);
1820 checkEvictorVisiting(false);
1821 }
1822
1823 @Test
1824 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1825 void testEvictWhileEmpty() throws Exception {
1826 genericObjectPool.evict();
1827 genericObjectPool.evict();
1828 genericObjectPool.close();
1829 }
1830
1831 @Test
1832 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1833 void testExceptionInValidationDuringEviction() throws Exception {
1834 genericObjectPool.setMaxIdle(1);
1835 genericObjectPool.setMinEvictableIdleTime(Duration.ZERO);
1836 genericObjectPool.setTestWhileIdle(true);
1837 final String active = genericObjectPool.borrowObject();
1838 genericObjectPool.returnObject(active);
1839 simpleFactory.setThrowExceptionOnValidate(true);
1840 assertThrows(RuntimeException.class, () -> genericObjectPool.evict());
1841 assertEquals(0, genericObjectPool.getNumActive());
1842 assertEquals(0, genericObjectPool.getNumIdle());
1843 }
1844
1845 @Test
1846 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1847 void testExceptionOnActivateDuringBorrow() throws Exception {
1848 final String obj1 = genericObjectPool.borrowObject();
1849 final String obj2 = genericObjectPool.borrowObject();
1850 genericObjectPool.returnObject(obj1);
1851 genericObjectPool.returnObject(obj2);
1852 simpleFactory.setThrowExceptionOnActivate(true);
1853 simpleFactory.setEvenValid(false);
1854
1855
1856 final String obj = genericObjectPool.borrowObject();
1857 assertEquals(1, genericObjectPool.getNumActive());
1858 assertEquals(0, genericObjectPool.getNumIdle());
1859 genericObjectPool.returnObject(obj);
1860 simpleFactory.setValid(false);
1861
1862
1863 assertThrows(NoSuchElementException.class, () -> genericObjectPool.borrowObject());
1864 assertEquals(0, genericObjectPool.getNumActive());
1865 assertEquals(0, genericObjectPool.getNumIdle());
1866 }
1867
1868 @Test
1869 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1870 void testExceptionOnDestroyDuringBorrow() throws Exception {
1871 simpleFactory.setThrowExceptionOnDestroy(true);
1872 genericObjectPool.setTestOnBorrow(true);
1873 genericObjectPool.borrowObject();
1874 simpleFactory.setValid(false);
1875 assertThrows(NoSuchElementException.class, () -> genericObjectPool.borrowObject());
1876 assertEquals(1, genericObjectPool.getNumActive());
1877 assertEquals(0, genericObjectPool.getNumIdle());
1878 }
1879
1880 @Test
1881 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1882 void testExceptionOnDestroyDuringReturn() throws Exception {
1883 simpleFactory.setThrowExceptionOnDestroy(true);
1884 genericObjectPool.setTestOnReturn(true);
1885 final String obj1 = genericObjectPool.borrowObject();
1886 genericObjectPool.borrowObject();
1887 simpleFactory.setValid(false);
1888 genericObjectPool.returnObject(obj1);
1889 assertEquals(1, genericObjectPool.getNumActive());
1890 assertEquals(0, genericObjectPool.getNumIdle());
1891 }
1892
1893 @Test
1894 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1895 void testExceptionOnPassivateDuringReturn() throws Exception {
1896 final String obj = genericObjectPool.borrowObject();
1897 simpleFactory.setThrowExceptionOnPassivate(true);
1898 genericObjectPool.returnObject(obj);
1899 assertEquals(0, genericObjectPool.getNumIdle());
1900 }
1901
1902 @Test
1903 void testFailingFactoryDoesNotBlockThreads() throws Exception {
1904 final CreateFailFactory factory = new CreateFailFactory();
1905 try (GenericObjectPool<String> createFailFactoryPool = new GenericObjectPool<>(factory)) {
1906 createFailFactoryPool.setMaxTotal(1);
1907
1908 final WaitingTestThread thread1 = new WaitingTestThread(createFailFactoryPool, 0);
1909 thread1.start();
1910
1911 while (!factory.hasQueuedThreads()) {
1912 Thread.sleep(200);
1913 }
1914
1915 final WaitingTestThread thread2 = new WaitingTestThread(createFailFactoryPool, 0);
1916 thread2.start();
1917
1918
1919
1920
1921 Thread.sleep(1000);
1922
1923 factory.release();
1924
1925 factory.release();
1926
1927 boolean threadRunning = true;
1928 int count = 0;
1929 while (threadRunning && count < 15) {
1930 threadRunning = thread1.isAlive();
1931 threadRunning = thread2.isAlive();
1932 Thread.sleep(200);
1933 count++;
1934 }
1935 assertFalse(thread1.isAlive());
1936 assertFalse(thread2.isAlive());
1937 assertTrue(thread1.thrown instanceof UnsupportedCharsetException);
1938 assertTrue(thread2.thrown instanceof UnsupportedCharsetException);
1939 }
1940 }
1941
1942 @Test
1943 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
1944 void testFIFO() throws Exception {
1945 genericObjectPool.setLifo(false);
1946 genericObjectPool.addObject();
1947 genericObjectPool.addObject();
1948 genericObjectPool.addObject();
1949 assertEquals("0", genericObjectPool.borrowObject(), "Oldest");
1950 assertEquals("1", genericObjectPool.borrowObject(), "Middle");
1951 assertEquals("2", genericObjectPool.borrowObject(), "Youngest");
1952 final String o = genericObjectPool.borrowObject();
1953 assertEquals("3", o, "new-3");
1954 genericObjectPool.returnObject(o);
1955 assertEquals(o, genericObjectPool.borrowObject(), "returned-3");
1956 assertEquals("4", genericObjectPool.borrowObject(), "new-4");
1957 }
1958
1959 @Test
1960 void testGetFactoryType_DefaultPooledObjectFactory() {
1961 try (GenericObjectPool<String> pool = new GenericObjectPool<>(createDefaultPooledObjectFactory())) {
1962 assertNotNull(pool.getFactoryType());
1963 }
1964 }
1965
1966 @Test
1967 void testGetFactoryType_NullPooledObjectFactory() {
1968 try (GenericObjectPool<String> pool = new GenericObjectPool<>(createNullPooledObjectFactory())) {
1969 assertNotNull(pool.getFactoryType());
1970 }
1971 }
1972
1973 @Test
1974 void testGetFactoryType_PoolUtilsSynchronizedDefaultPooledFactory() {
1975 try (GenericObjectPool<String> pool = new GenericObjectPool<>(PoolUtils.synchronizedPooledFactory(createDefaultPooledObjectFactory()))) {
1976 assertNotNull(pool.getFactoryType());
1977 }
1978 }
1979
1980 @Test
1981 void testGetFactoryType_PoolUtilsSynchronizedNullPooledFactory() {
1982 try (GenericObjectPool<String> pool = new GenericObjectPool<>(PoolUtils.synchronizedPooledFactory(createNullPooledObjectFactory()))) {
1983 assertNotNull(pool.getFactoryType());
1984 }
1985 }
1986
1987 @Test
1988 void testGetFactoryType_SynchronizedDefaultPooledObjectFactory() {
1989 try (GenericObjectPool<String> pool = new GenericObjectPool<>(new TestSynchronizedPooledObjectFactory<>(createDefaultPooledObjectFactory()))) {
1990 assertNotNull(pool.getFactoryType());
1991 }
1992 }
1993
1994 @Test
1995 void testGetFactoryType_SynchronizedNullPooledObjectFactory() {
1996 try (GenericObjectPool<String> pool = new GenericObjectPool<>(new TestSynchronizedPooledObjectFactory<>(createNullPooledObjectFactory()))) {
1997 assertNotNull(pool.getFactoryType());
1998 }
1999 }
2000
2001 @Test
2002 void testGetStatsString() {
2003 try (GenericObjectPool<String> pool = new GenericObjectPool<>(new TestSynchronizedPooledObjectFactory<>(createNullPooledObjectFactory()))) {
2004 assertNotNull(pool.getStatsString());
2005 }
2006 }
2007
2008
2009
2010
2011
2012
2013
2014
2015 @Test
2016 void testInvalidateFreesCapacity() throws Exception {
2017 final SimpleFactory factory = new SimpleFactory();
2018 try (GenericObjectPool<String> pool = new GenericObjectPool<>(factory)) {
2019 pool.setMaxTotal(2);
2020 pool.setMaxWaitMillis(500);
2021
2022 final WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
2023 thread1.start();
2024
2025 final String obj = pool.borrowObject();
2026
2027 final WaitingTestThread thread2 = new WaitingTestThread(pool, 100);
2028 thread2.start();
2029
2030 Thread.sleep(20);
2031 pool.invalidateObject(obj);
2032 Thread.sleep(600);
2033 if (thread2.thrown != null) {
2034 fail(thread2.thrown.toString());
2035 }
2036 }
2037 }
2038
2039
2040
2041
2042 @Test
2043 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2044 void testJmxRegistration() {
2045 final ObjectName oname = genericObjectPool.getJmxName();
2046 final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
2047 final Set<ObjectName> result = mbs.queryNames(oname, null);
2048 assertEquals(1, result.size());
2049 genericObjectPool.jmxUnregister();
2050 final GenericObjectPoolConfig<String> config = new GenericObjectPoolConfig<>();
2051 config.setJmxEnabled(false);
2052 try (GenericObjectPool<String> poolWithoutJmx = new GenericObjectPool<>(simpleFactory, config)) {
2053 assertNull(poolWithoutJmx.getJmxName());
2054 config.setJmxEnabled(true);
2055 poolWithoutJmx.jmxUnregister();
2056 }
2057 config.setJmxNameBase(null);
2058 try (GenericObjectPool<String> poolWithDefaultJmxNameBase = new GenericObjectPool<>(simpleFactory, config)) {
2059 assertNotNull(poolWithDefaultJmxNameBase.getJmxName());
2060 }
2061 }
2062
2063 @Test
2064 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2065 void testLIFO() throws Exception {
2066 final String o;
2067 genericObjectPool.setLifo(true);
2068 genericObjectPool.addObject();
2069 genericObjectPool.addObject();
2070 genericObjectPool.addObject();
2071 assertEquals("2", genericObjectPool.borrowObject(), "Youngest");
2072 assertEquals("1", genericObjectPool.borrowObject(), "Middle");
2073 assertEquals("0", genericObjectPool.borrowObject(), "Oldest");
2074 o = genericObjectPool.borrowObject();
2075 assertEquals("3", o, "new-3");
2076 genericObjectPool.returnObject(o);
2077 assertEquals(o, genericObjectPool.borrowObject(), "returned-3");
2078 assertEquals("4", genericObjectPool.borrowObject(), "new-4");
2079 }
2080
2081
2082
2083
2084
2085 @Test
2086 @Disabled
2087 @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS)
2088 void testLivenessOnTransientFactoryFailure() throws Exception {
2089 final DisconnectingWaiterFactory<String> factory = new DisconnectingWaiterFactory<>(DisconnectingWaiterFactory.DEFAULT_DISCONNECTED_CREATE_ACTION,
2090 DisconnectingWaiterFactory.DEFAULT_DISCONNECTED_LIFECYCLE_ACTION, obj -> false
2091 );
2092 final AtomicBoolean failed = new AtomicBoolean();
2093 try (GenericObjectPool<Waiter> pool = new GenericObjectPool<>(factory)) {
2094 pool.setMaxWait(Duration.ofMillis(100));
2095 pool.setTestOnReturn(true);
2096 pool.setMaxTotal(1);
2097 final Waiter w = pool.borrowObject();
2098 final Thread t = new Thread(() -> {
2099 try {
2100 pool.borrowObject();
2101 } catch (final Exception e) {
2102 failed.set(true);
2103 }
2104 });
2105 Thread.sleep(10);
2106 t.start();
2107
2108 Thread.sleep(10);
2109 factory.disconnect();
2110 pool.returnObject(w);
2111 Thread.sleep(10);
2112 factory.connect();
2113
2114 t.join();
2115 }
2116 if (failed.get()) {
2117 fail("Borrower timed out waiting for an instance");
2118 }
2119 }
2120
2121
2122
2123
2124
2125
2126
2127 @Test
2128 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2129 void testMakeConcurrentWithReturn() throws Exception {
2130 genericObjectPool.setTestOnBorrow(true);
2131 simpleFactory.setValid(true);
2132
2133 final WaitingTestThread thread1 = new WaitingTestThread(genericObjectPool, 200);
2134 thread1.start();
2135 Thread.sleep(50);
2136
2137 simpleFactory.setValidateLatency(400);
2138 final String instance = genericObjectPool.borrowObject();
2139
2140 assertEquals(simpleFactory.getMakeCounter(), genericObjectPool.getNumIdle() + 1);
2141 genericObjectPool.returnObject(instance);
2142 assertEquals(simpleFactory.getMakeCounter(), genericObjectPool.getNumIdle());
2143 }
2144
2145 @Test
2146 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2147 void testMaxIdle() throws Exception {
2148 genericObjectPool.setMaxTotal(100);
2149 genericObjectPool.setMaxIdle(8);
2150 final String[] active = new String[100];
2151 for (int i = 0; i < 100; i++) {
2152 active[i] = genericObjectPool.borrowObject();
2153 }
2154 assertEquals(100, genericObjectPool.getNumActive());
2155 assertEquals(0, genericObjectPool.getNumIdle());
2156 for (int i = 0; i < 100; i++) {
2157 genericObjectPool.returnObject(active[i]);
2158 assertEquals(99 - i, genericObjectPool.getNumActive());
2159 assertEquals(i < 8 ? i + 1 : 8, genericObjectPool.getNumIdle());
2160 }
2161 }
2162
2163 @Test
2164 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2165 void testMaxIdleZero() throws Exception {
2166 genericObjectPool.setMaxTotal(100);
2167 genericObjectPool.setMaxIdle(0);
2168 final String[] active = new String[100];
2169 for (int i = 0; i < 100; i++) {
2170 active[i] = genericObjectPool.borrowObject();
2171 }
2172 assertEquals(100, genericObjectPool.getNumActive());
2173 assertEquals(0, genericObjectPool.getNumIdle());
2174 for (int i = 0; i < 100; i++) {
2175 genericObjectPool.returnObject(active[i]);
2176 assertEquals(99 - i, genericObjectPool.getNumActive());
2177 assertEquals(0, genericObjectPool.getNumIdle());
2178 }
2179 }
2180
2181
2182
2183
2184 @Test
2185 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2186 @SuppressWarnings("rawtypes")
2187 void testMaxIdleZeroUnderLoad() {
2188
2189 final int numThreads = 199;
2190 final int numIter = 20;
2191 final int delay = 25;
2192 final int maxTotal = 10;
2193 simpleFactory.setMaxTotal(maxTotal);
2194 genericObjectPool.setMaxTotal(maxTotal);
2195 genericObjectPool.setBlockWhenExhausted(true);
2196 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(-1));
2197
2198 genericObjectPool.setMaxIdle(0);
2199
2200 final TestThread[] threads = new TestThread[numThreads];
2201 for (int i = 0; i < numThreads; i++) {
2202
2203
2204
2205 threads[i] = new TestThread<>(genericObjectPool, numIter * 2, delay * 2);
2206 final Thread t = new Thread(threads[i]);
2207 t.start();
2208 }
2209
2210 Waiter.sleepQuietly(100L);
2211 for (int i = 0; i < numIter; i++) {
2212 String obj = null;
2213 try {
2214 Waiter.sleepQuietly(delay);
2215 obj = genericObjectPool.borrowObject();
2216
2217 if (genericObjectPool.getNumActive() > genericObjectPool.getMaxTotal()) {
2218 throw new IllegalStateException("Too many active objects");
2219 }
2220 Waiter.sleepQuietly(delay);
2221 } catch (final Exception e) {
2222
2223 e.printStackTrace();
2224 fail("Exception on borrow");
2225 } finally {
2226 if (obj != null) {
2227 try {
2228 genericObjectPool.returnObject(obj);
2229 } catch (final Exception e) {
2230
2231 }
2232 }
2233 }
2234 }
2235 for (int i = 0; i < numThreads; i++) {
2236 while (!threads[i].complete()) {
2237 Waiter.sleepQuietly(500L);
2238 }
2239 if (threads[i].failed()) {
2240 threads[i].error.printStackTrace();
2241 fail("Thread " + i + " failed: " + threads[i].error.toString());
2242 }
2243 }
2244 }
2245
2246 @Test
2247 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2248 void testMaxTotal() throws Exception {
2249 genericObjectPool.setMaxTotal(3);
2250 genericObjectPool.setBlockWhenExhausted(false);
2251 genericObjectPool.borrowObject();
2252 genericObjectPool.borrowObject();
2253 genericObjectPool.borrowObject();
2254 assertThrows(NoSuchElementException.class, () -> genericObjectPool.borrowObject());
2255 }
2256
2257
2258
2259
2260
2261 @Test
2262 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2263 void testMaxTotalInvariant() {
2264 final int maxTotal = 15;
2265 simpleFactory.setEvenValid(false);
2266 simpleFactory.setDestroyLatency(100);
2267 simpleFactory.setMaxTotal(maxTotal);
2268 simpleFactory.setValidationEnabled(true);
2269 genericObjectPool.setMaxTotal(maxTotal);
2270 genericObjectPool.setMaxIdle(-1);
2271 genericObjectPool.setTestOnReturn(true);
2272 genericObjectPool.setMaxWaitMillis(1000L);
2273 runTestThreads(5, 10, 50, genericObjectPool);
2274 }
2275
2276 @Test
2277 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2278 @SuppressWarnings("rawtypes")
2279 void testMaxTotalUnderLoad() {
2280
2281 final int numThreads = 199;
2282 final int numIter = 20;
2283 final int delay = 25;
2284 final int maxTotal = 10;
2285 simpleFactory.setMaxTotal(maxTotal);
2286 genericObjectPool.setMaxTotal(maxTotal);
2287 genericObjectPool.setBlockWhenExhausted(true);
2288 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(-1));
2289
2290 final TestThread[] threads = new TestThread[numThreads];
2291 for (int i = 0; i < numThreads; i++) {
2292
2293
2294
2295 threads[i] = new TestThread<>(genericObjectPool, numIter * 2, delay * 2);
2296 final Thread t = new Thread(threads[i]);
2297 t.start();
2298 }
2299
2300 Waiter.sleepQuietly(5000);
2301 for (int i = 0; i < numIter; i++) {
2302 String obj = null;
2303 try {
2304 Waiter.sleepQuietly(delay);
2305 obj = genericObjectPool.borrowObject();
2306
2307 if (genericObjectPool.getNumActive() > genericObjectPool.getMaxTotal()) {
2308 throw new IllegalStateException("Too many active objects");
2309 }
2310 Waiter.sleepQuietly(delay);
2311 } catch (final Exception e) {
2312
2313 e.printStackTrace();
2314 fail("Exception on borrow");
2315 } finally {
2316 if (obj != null) {
2317 try {
2318 genericObjectPool.returnObject(obj);
2319 } catch (final Exception e) {
2320
2321 }
2322 }
2323 }
2324 }
2325 for (int i = 0; i < numThreads; i++) {
2326 while (!threads[i].complete()) {
2327 Waiter.sleepQuietly(500L);
2328 }
2329 if (threads[i].failed()) {
2330 fail("Thread " + i + " failed: " + threads[i].error.toString());
2331 }
2332 }
2333 }
2334
2335 @Test
2336 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2337 void testMaxTotalZero() throws Exception {
2338 genericObjectPool.setMaxTotal(0);
2339 genericObjectPool.setBlockWhenExhausted(false);
2340 assertThrows(NoSuchElementException.class, () -> genericObjectPool.borrowObject());
2341 }
2342
2343
2344
2345
2346
2347
2348
2349 @Test
2350 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2351 void testMaxWaitMultiThreaded() throws Exception {
2352 final long maxWait = 500;
2353 final long holdTime = 2 * maxWait;
2354 final int threads = 10;
2355 genericObjectPool.setBlockWhenExhausted(true);
2356 genericObjectPool.setMaxWaitMillis(maxWait);
2357 genericObjectPool.setMaxTotal(threads);
2358
2359 final WaitingTestThread[] wtt = new WaitingTestThread[threads * 2];
2360 for (int i = 0; i < wtt.length; i++) {
2361 wtt[i] = new WaitingTestThread(genericObjectPool, holdTime);
2362 }
2363 final long originMillis = System.currentTimeMillis() - 1000;
2364 for (final WaitingTestThread element : wtt) {
2365 element.start();
2366 }
2367 int failed = 0;
2368 for (final WaitingTestThread element : wtt) {
2369 element.join();
2370 if (element.thrown != null) {
2371 failed++;
2372 }
2373 }
2374 if (DISPLAY_THREAD_DETAILS || wtt.length / 2 != failed) {
2375 System.out.println("MaxWait: " + maxWait + " HoldTime: " + holdTime + " MaxTotal: " + threads + " Threads: " + wtt.length + " Failed: " + failed);
2376 for (final WaitingTestThread wt : wtt) {
2377 System.out.println("PreBorrow: " + (wt.preBorrowMillis - originMillis) + " PostBorrow: "
2378 + (wt.postBorrowMillis != 0 ? wt.postBorrowMillis - originMillis : -1) + " BorrowTime: "
2379 + (wt.postBorrowMillis != 0 ? wt.postBorrowMillis - wt.preBorrowMillis : -1) + " PostReturn: "
2380 + (wt.postReturnMillis != 0 ? wt.postReturnMillis - originMillis : -1) + " Ended: " + (wt.endedMillis - originMillis) + " ObjId: "
2381 + wt.objectId);
2382 }
2383 }
2384 assertEquals(wtt.length / 2, failed, "Expected half the threads to fail");
2385 }
2386
2387 @Test
2388 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2389 void testMinIdle() throws Exception {
2390 genericObjectPool.setMaxIdle(500);
2391 genericObjectPool.setMinIdle(5);
2392 genericObjectPool.setMaxTotal(10);
2393 genericObjectPool.setNumTestsPerEvictionRun(0);
2394 genericObjectPool.setMinEvictableIdleTime(Duration.ofMillis(50));
2395 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(100));
2396 genericObjectPool.setTestWhileIdle(true);
2397 Waiter.sleepQuietly(150L);
2398 assertEquals(5, genericObjectPool.getNumIdle(), "Should be 5 idle, found " + genericObjectPool.getNumIdle());
2399 final String[] active = new String[5];
2400 active[0] = genericObjectPool.borrowObject();
2401 Waiter.sleepQuietly(150L);
2402 assertEquals(5, genericObjectPool.getNumIdle(), "Should be 5 idle, found " + genericObjectPool.getNumIdle());
2403 for (int i = 1; i < 5; i++) {
2404 active[i] = genericObjectPool.borrowObject();
2405 }
2406 Waiter.sleepQuietly(150L);
2407 assertEquals(5, genericObjectPool.getNumIdle(), "Should be 5 idle, found " + genericObjectPool.getNumIdle());
2408 for (int i = 0; i < 5; i++) {
2409 genericObjectPool.returnObject(active[i]);
2410 }
2411 Waiter.sleepQuietly(150L);
2412 assertEquals(10, genericObjectPool.getNumIdle(), "Should be 10 idle, found " + genericObjectPool.getNumIdle());
2413 }
2414
2415 @Test
2416 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2417 void testMinIdleMaxTotal() throws Exception {
2418 genericObjectPool.setMaxIdle(500);
2419 genericObjectPool.setMinIdle(5);
2420 genericObjectPool.setMaxTotal(10);
2421 genericObjectPool.setNumTestsPerEvictionRun(0);
2422 genericObjectPool.setMinEvictableIdleTime(Duration.ofMillis(50));
2423 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(100));
2424 genericObjectPool.setTestWhileIdle(true);
2425 Waiter.sleepQuietly(150L);
2426 assertEquals(5, genericObjectPool.getNumIdle(), "Should be 5 idle, found " + genericObjectPool.getNumIdle());
2427 final String[] active = new String[10];
2428 Waiter.sleepQuietly(150L);
2429 assertEquals(5, genericObjectPool.getNumIdle(), "Should be 5 idle, found " + genericObjectPool.getNumIdle());
2430 for (int i = 0; i < 5; i++) {
2431 active[i] = genericObjectPool.borrowObject();
2432 }
2433 Waiter.sleepQuietly(150L);
2434 assertEquals(5, genericObjectPool.getNumIdle(), "Should be 5 idle, found " + genericObjectPool.getNumIdle());
2435 for (int i = 0; i < 5; i++) {
2436 genericObjectPool.returnObject(active[i]);
2437 }
2438 Waiter.sleepQuietly(150L);
2439 assertEquals(10, genericObjectPool.getNumIdle(), "Should be 10 idle, found " + genericObjectPool.getNumIdle());
2440 for (int i = 0; i < 10; i++) {
2441 active[i] = genericObjectPool.borrowObject();
2442 }
2443 Waiter.sleepQuietly(150L);
2444 assertEquals(0, genericObjectPool.getNumIdle(), "Should be 0 idle, found " + genericObjectPool.getNumIdle());
2445 for (int i = 0; i < 10; i++) {
2446 genericObjectPool.returnObject(active[i]);
2447 }
2448 Waiter.sleepQuietly(150L);
2449 assertEquals(10, genericObjectPool.getNumIdle(), "Should be 10 idle, found " + genericObjectPool.getNumIdle());
2450 }
2451
2452
2453
2454
2455
2456
2457 @Test
2458 void testMultipleReturn() throws Exception {
2459 final WaiterFactory<String> factory = new WaiterFactory<>(0, 0, 0, 0, 0, 0);
2460 try (GenericObjectPool<Waiter> pool = new GenericObjectPool<>(factory)) {
2461 pool.setTestOnReturn(true);
2462 final Waiter waiter = pool.borrowObject();
2463 pool.returnObject(waiter);
2464 assertEquals(1, waiter.getValidationCount());
2465 assertEquals(1, waiter.getPassivationCount());
2466 try {
2467 pool.returnObject(waiter);
2468 fail("Expecting IllegalStateException from multiple return");
2469 } catch (final IllegalStateException ex) {
2470
2471 assertEquals(1, waiter.getValidationCount());
2472 assertEquals(1, waiter.getPassivationCount());
2473 }
2474 }
2475 }
2476
2477
2478 @Test
2479 void testMultipleReturnOfSameObject() throws Exception {
2480 try (GenericObjectPool<String> pool = new GenericObjectPool<>(simpleFactory, new GenericObjectPoolConfig<>())) {
2481 assertEquals(0, pool.getNumActive());
2482 assertEquals(0, pool.getNumIdle());
2483 final String obj = pool.borrowObject();
2484 assertEquals(1, pool.getNumActive());
2485 assertEquals(0, pool.getNumIdle());
2486 pool.returnObject(obj);
2487 assertEquals(0, pool.getNumActive());
2488 assertEquals(1, pool.getNumIdle());
2489 assertThrows(IllegalStateException.class, () -> pool.returnObject(obj));
2490 assertEquals(0, pool.getNumActive());
2491 assertEquals(1, pool.getNumIdle());
2492 }
2493 }
2494
2495
2496
2497
2498
2499
2500 @Test
2501 void testMutable() throws Exception {
2502 final HashSetFactory factory = new HashSetFactory();
2503 try (GenericObjectPool<HashSet<String>> pool = new GenericObjectPool<>(factory, new GenericObjectPoolConfig<>())) {
2504 final HashSet<String> s1 = pool.borrowObject();
2505 final HashSet<String> s2 = pool.borrowObject();
2506 s1.add("One");
2507 s2.add("One");
2508 pool.returnObject(s1);
2509 pool.returnObject(s2);
2510 }
2511 }
2512
2513 @Test
2514 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2515 void testNegativeMaxTotal() throws Exception {
2516 genericObjectPool.setMaxTotal(-1);
2517 genericObjectPool.setBlockWhenExhausted(false);
2518 final String obj = genericObjectPool.borrowObject();
2519 assertEquals(getNthObject(0), obj);
2520 genericObjectPool.returnObject(obj);
2521 }
2522
2523
2524
2525
2526 @Test
2527 void testNoInstanceOverlap() {
2528 final int maxTotal = 5;
2529 final int numThreads = 100;
2530 final int delay = 1;
2531 final int iterations = 1000;
2532 final AtomicIntegerFactory factory = new AtomicIntegerFactory();
2533 try (GenericObjectPool<AtomicInteger> pool = new GenericObjectPool<>(factory)) {
2534 pool.setMaxTotal(maxTotal);
2535 pool.setMaxIdle(maxTotal);
2536 pool.setTestOnBorrow(true);
2537 pool.setBlockWhenExhausted(true);
2538 pool.setMaxWaitMillis(-1);
2539 runTestThreads(numThreads, iterations, delay, pool);
2540 assertEquals(0, pool.getDestroyedByBorrowValidationCount());
2541 }
2542 }
2543
2544
2545
2546
2547 @Test
2548 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2549 void testNoInvalidateNPE() throws Exception {
2550 genericObjectPool.setMaxTotal(1);
2551 genericObjectPool.setTestOnCreate(true);
2552 genericObjectPool.setMaxWaitMillis(-1);
2553 final String obj = genericObjectPool.borrowObject();
2554
2555 simpleFactory.setValid(false);
2556
2557 final WaitingTestThread wtt = new WaitingTestThread(genericObjectPool, 200);
2558 wtt.start();
2559
2560 Thread.sleep(200);
2561 genericObjectPool.invalidateObject(obj);
2562
2563 simpleFactory.setValid(true);
2564 }
2565
2566
2567
2568
2569
2570
2571 @Test
2572 @Timeout(value = 1000, unit = TimeUnit.MILLISECONDS)
2573 void testNPEOnFactoryNull() throws Exception {
2574
2575 final DisconnectingWaiterFactory<String> factory = new DisconnectingWaiterFactory<>(Suppliers.nul(),
2576 DisconnectingWaiterFactory.DEFAULT_DISCONNECTED_LIFECYCLE_ACTION, DisconnectingWaiterFactory.DEFAULT_DISCONNECTED_VALIDATION_ACTION);
2577 try (GenericObjectPool<Waiter> pool = new GenericObjectPool<>(factory)) {
2578 pool.setTestOnBorrow(true);
2579 pool.setMaxTotal(-1);
2580 pool.setMinIdle(1);
2581
2582 factory.disconnect();
2583 assertThrows(NullPointerException.class, pool::borrowObject);
2584 assertThrows(NullPointerException.class, pool::addObject);
2585 assertThrows(NullPointerException.class, pool::ensureMinIdle);
2586 }
2587 }
2588
2589
2590
2591
2592
2593 @Test
2594 void testPool419() throws Exception {
2595
2596 final ExecutorService executor = Executors.newFixedThreadPool(100);
2597
2598 final GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>();
2599
2600 final int maxConnections = 10000;
2601
2602 config.setMaxTotal(maxConnections);
2603 config.setMaxIdle(maxConnections);
2604 config.setMinIdle(1);
2605
2606 final BasePooledObjectFactory<Object> pof = createPooledObjectFactory();
2607
2608 try (ObjectPool<Object> connectionPool = new GenericObjectPool<>(pof, config)) {
2609 assertNotNull(connectionPool);
2610
2611 final CountDownLatch startLatch = new CountDownLatch(1);
2612
2613 final List<Object> poolObjects = new ArrayList<>();
2614
2615 final List<FutureTask<Boolean>> tasks = new ArrayList<>();
2616
2617 for (int i = 0; i < maxConnections; i++) {
2618 poolObjects.add(connectionPool.borrowObject());
2619 }
2620
2621 for (final Object poolObject : poolObjects) {
2622
2623 tasks.add(new FutureTask<>(() -> {
2624 startLatch.await();
2625 connectionPool.invalidateObject(poolObject);
2626 return true;
2627 }));
2628
2629 tasks.add(new FutureTask<>(() -> {
2630 startLatch.await();
2631 connectionPool.returnObject(poolObject);
2632 return true;
2633 }));
2634 }
2635
2636 tasks.forEach(executor::submit);
2637
2638 startLatch.countDown();
2639
2640 executor.shutdown();
2641 assertTrue(executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS));
2642
2643 assertEquals(0, connectionPool.getNumActive(), "getNumActive() must not return a negative value");
2644
2645 }
2646 }
2647
2648 @Test
2649 void testPreparePool() throws Exception {
2650 genericObjectPool.setMinIdle(1);
2651 genericObjectPool.setMaxTotal(1);
2652 genericObjectPool.preparePool();
2653 assertEquals(1, genericObjectPool.getNumIdle());
2654 final String obj = genericObjectPool.borrowObject();
2655 genericObjectPool.preparePool();
2656 assertEquals(0, genericObjectPool.getNumIdle());
2657 genericObjectPool.setMinIdle(0);
2658 genericObjectPool.returnObject(obj);
2659 genericObjectPool.preparePool();
2660 assertEquals(1, genericObjectPool.getNumIdle());
2661 }
2662
2663
2664
2665
2666
2667
2668 @Test
2669 @Timeout(value = 10_000, unit = TimeUnit.MILLISECONDS)
2670 void testReturnAndInvalidateServesWaiters() throws Exception {
2671 genericObjectPool.setMaxTotal(2);
2672 genericObjectPool.setBlockWhenExhausted(true);
2673 genericObjectPool.setMaxWait(Duration.ofMillis(100));
2674
2675
2676 final String obj1 = genericObjectPool.borrowObject();
2677 final String obj2 = genericObjectPool.borrowObject();
2678
2679
2680 final AtomicInteger successfulBorrows = new AtomicInteger(0);
2681
2682
2683 final Thread borrower1 = new Thread(() -> {
2684 try {
2685 genericObjectPool.borrowObject();
2686 successfulBorrows.incrementAndGet();
2687 } catch (final Exception e) {
2688
2689 }
2690 });
2691
2692 final Thread borrower2 = new Thread(() -> {
2693 try {
2694 genericObjectPool.borrowObject();
2695 successfulBorrows.incrementAndGet();
2696 } catch (final Exception e) {
2697
2698 }
2699 });
2700
2701
2702 borrower1.start();
2703 borrower2.start();
2704 Thread.sleep(50);
2705
2706
2707 genericObjectPool.invalidateObject(obj1);
2708 genericObjectPool.invalidateObject(obj2);
2709
2710
2711 borrower1.join();
2712 borrower2.join();
2713
2714
2715 assertEquals(2, successfulBorrows.get(),
2716 "Both waiting threads should have been served, but only " + successfulBorrows.get() + " were served");
2717 }
2718
2719 @Test
2720 @Timeout(value = 1200, unit = TimeUnit.MILLISECONDS)
2721 void testReturnBorrowObjectWithingMaxWaitDuration() throws Exception {
2722 final Duration maxWaitDuration = Duration.ofMillis(500);
2723 try (GenericObjectPool<String> createSlowObjectFactoryPool = new GenericObjectPool<>(createSlowObjectFactory(Duration.ofSeconds(60)))) {
2724 createSlowObjectFactoryPool.setMaxTotal(1);
2725 createSlowObjectFactoryPool.setMaxWait(maxWaitDuration);
2726
2727 final WaitingTestThread thread1 = new WaitingTestThread(createSlowObjectFactoryPool, 0);
2728 thread1.start();
2729
2730 Thread.sleep(100);
2731
2732 assertThrows(NoSuchElementException.class, () -> createSlowObjectFactoryPool.borrowObject(maxWaitDuration),
2733 "borrowObject must fail due to timeout by maxWait");
2734 assertTrue(thread1.isAlive());
2735 }
2736 }
2737
2738 @Test
2739 @Timeout(value = 1200, unit = TimeUnit.MILLISECONDS)
2740 void testReturnBorrowObjectWithingMaxWaitMillis() throws Exception {
2741 final long maxWaitMillis = 500;
2742 try (GenericObjectPool<String> createSlowObjectFactoryPool = new GenericObjectPool<>(createSlowObjectFactory(Duration.ofSeconds(60)))) {
2743 createSlowObjectFactoryPool.setMaxTotal(1);
2744 createSlowObjectFactoryPool.setMaxWaitMillis(maxWaitMillis);
2745
2746 final WaitingTestThread thread1 = new WaitingTestThread(createSlowObjectFactoryPool, 0);
2747 thread1.start();
2748
2749 Thread.sleep(100);
2750
2751 assertThrows(NoSuchElementException.class, () -> createSlowObjectFactoryPool.borrowObject(maxWaitMillis),
2752 "borrowObject must fail due to timeout by maxWait");
2753 assertTrue(thread1.isAlive());
2754 }
2755 }
2756
2757
2758
2759
2760
2761
2762
2763 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2764 void testReturnObject() throws Exception {
2765 genericObjectPool.setMaxTotal(1);
2766 genericObjectPool.setMaxIdle(-1);
2767 final String active = genericObjectPool.borrowObject();
2768 assertEquals(1, genericObjectPool.getNumActive());
2769 assertEquals(0, genericObjectPool.getNumIdle());
2770 final Thread t = new Thread(() -> genericObjectPool.close());
2771 t.start();
2772 genericObjectPool.returnObject(active);
2773
2774 while (t.isAlive()) {
2775 Thread.sleep(50);
2776 }
2777 assertEquals(0, genericObjectPool.getNumIdle());
2778 }
2779
2780 @Test
2781 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2782 void testSetConfig() throws Exception {
2783 final GenericObjectPoolConfig<String> expected = new GenericObjectPoolConfig<>();
2784 assertConfiguration(expected, genericObjectPool);
2785 expected.setMaxTotal(2);
2786 expected.setMaxIdle(3);
2787 expected.setMaxWait(Duration.ofMillis(5));
2788 expected.setMinEvictableIdleDuration(Duration.ofMillis(7L));
2789 expected.setNumTestsPerEvictionRun(9);
2790 expected.setTestOnCreate(true);
2791 expected.setTestOnBorrow(true);
2792 expected.setTestOnReturn(true);
2793 expected.setTestWhileIdle(true);
2794 expected.setTimeBetweenEvictionRuns(Duration.ofMillis(11L));
2795 expected.setBlockWhenExhausted(false);
2796 genericObjectPool.setConfig(expected);
2797 assertConfiguration(expected, genericObjectPool);
2798 }
2799
2800 @Test
2801 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2802 void testSettersAndGetters() throws Exception {
2803 {
2804
2805
2806 assertNotEquals("", genericObjectPool.getCreationStackTrace());
2807 }
2808 {
2809 assertEquals(0, genericObjectPool.getBorrowedCount());
2810 }
2811 {
2812 assertEquals(0, genericObjectPool.getReturnedCount());
2813 }
2814 {
2815 assertEquals(0, genericObjectPool.getCreatedCount());
2816 }
2817 {
2818 assertEquals(0, genericObjectPool.getDestroyedCount());
2819 }
2820 {
2821 assertEquals(0, genericObjectPool.getDestroyedByEvictorCount());
2822 }
2823 {
2824 assertEquals(0, genericObjectPool.getDestroyedByBorrowValidationCount());
2825 }
2826 {
2827 assertEquals(0, genericObjectPool.getMeanActiveTimeMillis());
2828 }
2829 {
2830 assertEquals(0, genericObjectPool.getMeanIdleTimeMillis());
2831 }
2832 {
2833 assertEquals(0, genericObjectPool.getMeanBorrowWaitTimeMillis());
2834 }
2835 {
2836 assertEquals(0, genericObjectPool.getMaxBorrowWaitTimeMillis());
2837 }
2838 {
2839 assertEquals(0, genericObjectPool.getNumIdle());
2840 }
2841 {
2842 genericObjectPool.setMaxTotal(123);
2843 assertEquals(123, genericObjectPool.getMaxTotal());
2844 }
2845 {
2846 genericObjectPool.setMaxIdle(12);
2847 assertEquals(12, genericObjectPool.getMaxIdle());
2848 }
2849 {
2850 genericObjectPool.setMaxWaitMillis(1234L);
2851 assertEquals(1234L, genericObjectPool.getMaxWaitMillis());
2852 }
2853 {
2854 genericObjectPool.setMinEvictableIdleTimeMillis(12345L);
2855 assertEquals(12345L, genericObjectPool.getMinEvictableIdleDuration().toMillis());
2856 assertEquals(12345L, genericObjectPool.getMinEvictableIdleTimeMillis());
2857 assertEquals(12345L, genericObjectPool.getMinEvictableIdleTime().toMillis());
2858 }
2859 {
2860 genericObjectPool.setNumTestsPerEvictionRun(11);
2861 assertEquals(11, genericObjectPool.getNumTestsPerEvictionRun());
2862 }
2863 {
2864 genericObjectPool.setTestOnBorrow(true);
2865 assertTrue(genericObjectPool.getTestOnBorrow());
2866 genericObjectPool.setTestOnBorrow(false);
2867 assertFalse(genericObjectPool.getTestOnBorrow());
2868 }
2869 {
2870 genericObjectPool.setTestOnReturn(true);
2871 assertTrue(genericObjectPool.getTestOnReturn());
2872 genericObjectPool.setTestOnReturn(false);
2873 assertFalse(genericObjectPool.getTestOnReturn());
2874 }
2875 {
2876 genericObjectPool.setTestWhileIdle(true);
2877 assertTrue(genericObjectPool.getTestWhileIdle());
2878 genericObjectPool.setTestWhileIdle(false);
2879 assertFalse(genericObjectPool.getTestWhileIdle());
2880 }
2881 {
2882 genericObjectPool.setTimeBetweenEvictionRunsMillis(11235L);
2883 assertEquals(11235L, genericObjectPool.getDurationBetweenEvictionRuns().toMillis());
2884 assertEquals(11235L, genericObjectPool.getTimeBetweenEvictionRunsMillis());
2885 assertEquals(11235L, genericObjectPool.getTimeBetweenEvictionRuns().toMillis());
2886 }
2887 {
2888 genericObjectPool.setSoftMinEvictableIdleTimeMillis(12135L);
2889 assertEquals(12135L, genericObjectPool.getSoftMinEvictableIdleDuration().toMillis());
2890 assertEquals(12135L, genericObjectPool.getSoftMinEvictableIdleTimeMillis());
2891 assertEquals(12135L, genericObjectPool.getSoftMinEvictableIdleTime().toMillis());
2892 }
2893 {
2894 genericObjectPool.setBlockWhenExhausted(true);
2895 assertTrue(genericObjectPool.getBlockWhenExhausted());
2896 genericObjectPool.setBlockWhenExhausted(false);
2897 assertFalse(genericObjectPool.getBlockWhenExhausted());
2898 }
2899 }
2900
2901 @Test
2902 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2903 void testStartAndStopEvictor() throws Exception {
2904
2905 genericObjectPool.setMaxIdle(6);
2906 genericObjectPool.setMaxTotal(6);
2907 genericObjectPool.setNumTestsPerEvictionRun(6);
2908 genericObjectPool.setMinEvictableIdleTime(Duration.ofMillis(100));
2909 for (int j = 0; j < 2; j++) {
2910
2911 {
2912 final String[] active = new String[6];
2913 for (int i = 0; i < 6; i++) {
2914 active[i] = genericObjectPool.borrowObject();
2915 }
2916 for (int i = 0; i < 6; i++) {
2917 genericObjectPool.returnObject(active[i]);
2918 }
2919 }
2920
2921 assertEquals(6, genericObjectPool.getNumIdle(), "Should have 6 idle");
2922
2923 genericObjectPool.setTimeBetweenEvictionRuns(Duration.ofMillis(50));
2924
2925 Waiter.sleepQuietly(200L);
2926
2927 assertEquals(0, genericObjectPool.getNumIdle(), "Should have 0 idle");
2928
2929 genericObjectPool.startEvictor(Duration.ZERO);
2930 }
2931 }
2932
2933
2934 @Test
2935 void testSwallowedExceptionListener() {
2936 genericObjectPool.setSwallowedExceptionListener(null);
2937 final List<Exception> swallowedExceptions = new ArrayList<>();
2938
2939
2940
2941 final SwallowedExceptionListener listener = e -> {
2942 if (swallowedExceptions.size() == 2) {
2943 throw new OutOfMemoryError();
2944 }
2945 swallowedExceptions.add(e);
2946 };
2947 genericObjectPool.setSwallowedExceptionListener(listener);
2948 final Exception e1 = new Exception();
2949 final Exception e2 = new ArrayIndexOutOfBoundsException();
2950 genericObjectPool.swallowException(e1);
2951 genericObjectPool.swallowException(e2);
2952 assertThrows(OutOfMemoryError.class, () -> genericObjectPool.swallowException(e1));
2953 assertEquals(2, swallowedExceptions.size());
2954 }
2955
2956 @Test
2957 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2958 void testThreaded1() throws Exception {
2959 genericObjectPool.setMaxTotal(15);
2960 genericObjectPool.setMaxIdle(15);
2961 genericObjectPool.setMaxWaitMillis(1000L);
2962 runTestThreads(20, 100, 50, genericObjectPool);
2963 }
2964
2965 @Test
2966 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
2967 void testTimeoutNoLeak() throws Exception {
2968 genericObjectPool.setMaxTotal(2);
2969 genericObjectPool.setMaxWaitMillis(10);
2970 genericObjectPool.setBlockWhenExhausted(true);
2971 final String obj = genericObjectPool.borrowObject();
2972 final String obj2 = genericObjectPool.borrowObject();
2973 assertThrows(NoSuchElementException.class, () -> genericObjectPool.borrowObject());
2974 genericObjectPool.returnObject(obj2);
2975 genericObjectPool.returnObject(obj);
2976 genericObjectPool.borrowObject();
2977 genericObjectPool.borrowObject();
2978 }
2979
2980
2981
2982
2983 @Test
2984 void testValidateOnCreate() throws Exception {
2985 genericObjectPool.setTestOnCreate(true);
2986 genericObjectPool.addObject();
2987 assertEquals(1, simpleFactory.validateCounter);
2988 }
2989
2990
2991
2992
2993 @Test
2994 void testValidateOnCreateFailure() throws Exception {
2995 genericObjectPool.setTestOnCreate(true);
2996 genericObjectPool.setTestOnBorrow(false);
2997 genericObjectPool.setMaxTotal(2);
2998 simpleFactory.setValid(false);
2999
3000 genericObjectPool.addObject();
3001 genericObjectPool.addObject();
3002 assertEquals(0, genericObjectPool.getNumIdle());
3003 assertEquals(0, genericObjectPool.getNumActive());
3004 simpleFactory.setValid(true);
3005 final String obj = genericObjectPool.borrowObject();
3006 assertNotNull(obj);
3007 genericObjectPool.addObject();
3008
3009 assertEquals(1, genericObjectPool.getNumIdle());
3010 assertEquals(1, genericObjectPool.getNumActive());
3011 }
3012
3013
3014
3015
3016
3017
3018
3019
3020 @Test
3021 void testValidationFailureOnReturnFreesCapacity() throws Exception {
3022 final SimpleFactory factory = new SimpleFactory();
3023 factory.setValid(false);
3024 factory.setValidationEnabled(true);
3025 try (GenericObjectPool<String> pool = new GenericObjectPool<>(factory)) {
3026 pool.setMaxTotal(2);
3027 pool.setMaxWaitMillis(1500);
3028 pool.setTestOnReturn(true);
3029 pool.setTestOnBorrow(false);
3030
3031 final WaitingTestThread thread1 = new WaitingTestThread(pool, 5000);
3032 thread1.start();
3033
3034 final WaitingTestThread thread2 = new WaitingTestThread(pool, 500);
3035 thread2.start();
3036 Thread.sleep(50);
3037
3038 final String obj = pool.borrowObject();
3039 pool.returnObject(obj);
3040 }
3041 }
3042
3043
3044 @Test
3045 void testValidationOnCreateOnly() throws Exception {
3046 genericObjectPool.setMaxTotal(1);
3047 genericObjectPool.setTestOnCreate(true);
3048 genericObjectPool.setTestOnBorrow(false);
3049 genericObjectPool.setTestOnReturn(false);
3050 genericObjectPool.setTestWhileIdle(false);
3051 final String o1 = genericObjectPool.borrowObject();
3052 assertEquals("0", o1);
3053 final Timer t = new Timer();
3054 t.schedule(new TimerTask() {
3055 @Override
3056 public void run() {
3057 genericObjectPool.returnObject(o1);
3058 }
3059 }, 3000);
3060 final String o2 = genericObjectPool.borrowObject();
3061 assertEquals("0", o2);
3062 assertEquals(1, simpleFactory.validateCounter);
3063 }
3064
3065 @Test
3066 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
3067 void testWhenExhaustedBlock() throws Exception {
3068 genericObjectPool.setMaxTotal(1);
3069 genericObjectPool.setBlockWhenExhausted(true);
3070 genericObjectPool.setMaxWaitMillis(10L);
3071 final String obj1 = genericObjectPool.borrowObject();
3072 assertNotNull(obj1);
3073 assertThrows(NoSuchElementException.class, () -> genericObjectPool.borrowObject());
3074 genericObjectPool.returnObject(obj1);
3075 genericObjectPool.close();
3076 }
3077
3078
3079
3080
3081
3082
3083 @Test
3084 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
3085 void testWhenExhaustedBlockClosePool() throws Exception {
3086 genericObjectPool.setMaxTotal(1);
3087 genericObjectPool.setBlockWhenExhausted(true);
3088 genericObjectPool.setMaxWaitMillis(-1);
3089 final Object obj1 = genericObjectPool.borrowObject();
3090
3091 assertNotNull(obj1);
3092
3093 final WaitingTestThread wtt = new WaitingTestThread(genericObjectPool, 200);
3094 wtt.start();
3095
3096 Thread.sleep(200);
3097
3098 genericObjectPool.close();
3099
3100 Thread.sleep(200);
3101
3102 assertTrue(wtt.thrown instanceof InterruptedException);
3103 }
3104
3105 @Test
3106 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
3107 void testWhenExhaustedBlockInterrupt() throws Exception {
3108 genericObjectPool.setMaxTotal(1);
3109 genericObjectPool.setBlockWhenExhausted(true);
3110 genericObjectPool.setMaxWaitMillis(-1);
3111 final String obj1 = genericObjectPool.borrowObject();
3112
3113 assertNotNull(obj1);
3114
3115 final WaitingTestThread wtt = new WaitingTestThread(genericObjectPool, 200000);
3116 wtt.start();
3117
3118 Thread.sleep(200);
3119 wtt.interrupt();
3120
3121 Thread.sleep(200);
3122
3123 assertTrue(wtt.thrown instanceof InterruptedException);
3124
3125 genericObjectPool.returnObject(obj1);
3126
3127 genericObjectPool.setMaxWaitMillis(10L);
3128 String obj2 = null;
3129 try {
3130 obj2 = genericObjectPool.borrowObject();
3131 assertNotNull(obj2);
3132 } catch (final NoSuchElementException e) {
3133
3134 fail("NoSuchElementException not expected");
3135 }
3136 genericObjectPool.returnObject(obj2);
3137 genericObjectPool.close();
3138 }
3139
3140 @Test
3141 @Timeout(value = 60000, unit = TimeUnit.MILLISECONDS)
3142 void testWhenExhaustedFail() throws Exception {
3143 genericObjectPool.setMaxTotal(1);
3144 genericObjectPool.setBlockWhenExhausted(false);
3145 final String obj1 = genericObjectPool.borrowObject();
3146 assertNotNull(obj1);
3147 assertThrows(NoSuchElementException.class, () -> genericObjectPool.borrowObject());
3148 genericObjectPool.returnObject(obj1);
3149 assertEquals(1, genericObjectPool.getNumIdle());
3150 genericObjectPool.close();
3151 }
3152 }