|
21 | 21 | import static org.junit.jupiter.api.Assertions.assertEquals; |
22 | 22 | import static org.junit.jupiter.api.Assertions.assertNotNull; |
23 | 23 | import static org.junit.jupiter.api.Assertions.assertThrows; |
| 24 | +import static org.junit.jupiter.api.Assertions.assertTrue; |
24 | 25 | import static org.junit.jupiter.api.Assertions.fail; |
25 | 26 |
|
26 | 27 | import java.lang.reflect.InvocationHandler; |
|
33 | 34 | import java.util.List; |
34 | 35 | import java.util.Map; |
35 | 36 | import java.util.TimerTask; |
| 37 | +import java.util.concurrent.CountDownLatch; |
| 38 | +import java.util.concurrent.ExecutorService; |
| 39 | +import java.util.concurrent.Executors; |
| 40 | +import java.util.concurrent.FutureTask; |
| 41 | +import java.util.concurrent.TimeUnit; |
36 | 42 |
|
37 | 43 | import org.apache.commons.pool3.impl.DefaultPooledObject; |
38 | 44 | import org.apache.commons.pool3.impl.GenericKeyedObjectPool; |
39 | 45 | import org.apache.commons.pool3.impl.GenericObjectPool; |
| 46 | +import org.apache.commons.pool3.impl.GenericObjectPoolConfig; |
40 | 47 | import org.junit.jupiter.api.Test; |
41 | 48 | import org.opentest4j.AssertionFailedError; |
42 | 49 |
|
@@ -684,4 +691,60 @@ public void testTimerHolder() { |
684 | 691 | assertNotNull(h); |
685 | 692 | assertNotNull(PoolUtils.TimerHolder.MIN_IDLE_TIMER); |
686 | 693 | } |
| 694 | + |
| 695 | + /* |
| 696 | + * Test for POOL-419. |
| 697 | + * https://issues.apache.org/jira/browse/POOL-419 |
| 698 | + */ |
| 699 | + @Test |
| 700 | + void testPool419() throws Exception{ |
| 701 | + |
| 702 | + ExecutorService executor = Executors.newFixedThreadPool(100); |
| 703 | + |
| 704 | + final List<String> calledMethods = new ArrayList<>(); |
| 705 | + |
| 706 | + final GenericObjectPoolConfig<Object> config = new GenericObjectPoolConfig<>(); |
| 707 | + |
| 708 | + config.setMaxTotal(10000); |
| 709 | + config.setMaxIdle(10000); |
| 710 | + config.setMinIdle(10000); |
| 711 | + |
| 712 | + @SuppressWarnings("unchecked") |
| 713 | + final PooledObjectFactory<Object, RuntimeException> pof = createProxy(PooledObjectFactory.class, calledMethods); |
| 714 | + try (final ObjectPool<Object, RuntimeException> connectionPool = new GenericObjectPool<>(pof, config)) { |
| 715 | + assertNotNull(connectionPool); |
| 716 | + |
| 717 | + CountDownLatch startLatch = new CountDownLatch(1); |
| 718 | + |
| 719 | + for (int i = 0; i < 10000; i++) { |
| 720 | + Object poolObject = connectionPool.borrowObject(); |
| 721 | + |
| 722 | + FutureTask<Boolean> invalidateObject = new FutureTask<>(() -> { |
| 723 | + startLatch.await(); |
| 724 | + connectionPool.invalidateObject(poolObject); |
| 725 | + return true; |
| 726 | + }); |
| 727 | + |
| 728 | + FutureTask<Boolean> returnObject = new FutureTask<>(() -> { |
| 729 | + startLatch.await(); |
| 730 | + connectionPool.returnObject(poolObject); |
| 731 | + return true; |
| 732 | + }); |
| 733 | + |
| 734 | + executor.submit(returnObject); |
| 735 | + executor.submit(invalidateObject); |
| 736 | + |
| 737 | + } |
| 738 | + |
| 739 | + startLatch.countDown(); // Start all tasks simultaneously |
| 740 | + |
| 741 | + executor.shutdown(); |
| 742 | + assertTrue(executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS)); |
| 743 | + |
| 744 | + assertEquals(0, connectionPool.getNumActive(), "getNumActive() must not return a negative value"); |
| 745 | + |
| 746 | + } |
| 747 | + } |
| 748 | + |
687 | 749 | } |
| 750 | + |
0 commit comments