1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.hc.core5.pool;
28
29 import java.util.Collections;
30 import java.util.concurrent.CancellationException;
31 import java.util.concurrent.CountDownLatch;
32 import java.util.concurrent.ExecutionException;
33 import java.util.concurrent.Future;
34 import java.util.concurrent.TimeUnit;
35
36 import org.apache.hc.core5.http.HttpConnection;
37 import org.apache.hc.core5.io.CloseMode;
38 import org.apache.hc.core5.util.DeadlineTimeoutException;
39 import org.apache.hc.core5.util.TimeValue;
40 import org.apache.hc.core5.util.Timeout;
41 import org.junit.jupiter.api.Assertions;
42 import org.junit.jupiter.api.Test;
43 import org.mockito.ArgumentMatchers;
44 import org.mockito.Mockito;
45
46 public class TestStrictConnPool {
47
48 @Test
49 public void testEmptyPool() throws Exception {
50 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(2, 10);
51 final PoolStats totals = pool.getTotalStats();
52 Assertions.assertEquals(0, totals.getAvailable());
53 Assertions.assertEquals(0, totals.getLeased());
54 Assertions.assertEquals(0, totals.getPending());
55 Assertions.assertEquals(10, totals.getMax());
56 Assertions.assertEquals(Collections.emptySet(), pool.getRoutes());
57 final PoolStats stats = pool.getStats("somehost");
58 Assertions.assertEquals(0, stats.getAvailable());
59 Assertions.assertEquals(0, stats.getLeased());
60 Assertions.assertEquals(0, stats.getPending());
61 Assertions.assertEquals(2, stats.getMax());
62 Assertions.assertEquals("[leased: 0][available: 0][pending: 0]", pool.toString());
63 }
64
65 @Test
66 public void testInvalidConstruction() throws Exception {
67 Assertions.assertThrows(IllegalArgumentException.class, () ->
68 new StrictConnPool<String, HttpConnection>(-1, 1));
69 Assertions.assertThrows(IllegalArgumentException.class, () ->
70 new StrictConnPool<String, HttpConnection>(1, -1));
71 }
72
73 @Test
74 public void testLeaseRelease() throws Exception {
75 final HttpConnection conn1 = Mockito.mock(HttpConnection.class);
76 final HttpConnection conn2 = Mockito.mock(HttpConnection.class);
77 final HttpConnection conn3 = Mockito.mock(HttpConnection.class);
78
79 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(2, 10);
80 final Future<PoolEntry<String, HttpConnection>> future1 = pool.lease("somehost", null);
81 final Future<PoolEntry<String, HttpConnection>> future2 = pool.lease("somehost", null);
82 final Future<PoolEntry<String, HttpConnection>> future3 = pool.lease("otherhost", null);
83
84 final PoolEntry<String, HttpConnection> entry1 = future1.get();
85 Assertions.assertNotNull(entry1);
86 entry1.assignConnection(conn1);
87 final PoolEntry<String, HttpConnection> entry2 = future2.get();
88 Assertions.assertNotNull(entry2);
89 entry2.assignConnection(conn2);
90 final PoolEntry<String, HttpConnection> entry3 = future3.get();
91 Assertions.assertNotNull(entry3);
92 entry3.assignConnection(conn3);
93
94 pool.release(entry1, true);
95 pool.release(entry2, true);
96 pool.release(entry3, false);
97 Mockito.verify(conn1, Mockito.never()).close(ArgumentMatchers.any());
98 Mockito.verify(conn2, Mockito.never()).close(ArgumentMatchers.any());
99 Mockito.verify(conn3, Mockito.times(1)).close(CloseMode.GRACEFUL);
100
101 final PoolStats totals = pool.getTotalStats();
102 Assertions.assertEquals(2, totals.getAvailable());
103 Assertions.assertEquals(0, totals.getLeased());
104 Assertions.assertEquals(0, totals.getPending());
105 }
106
107 @Test
108 public void testLeaseInvalid() throws Exception {
109 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(2, 10);
110 Assertions.assertThrows(NullPointerException.class, () ->
111 pool.lease(null, null, Timeout.ZERO_MILLISECONDS, null));
112 Assertions.assertThrows(NullPointerException.class, () ->
113 pool.lease("somehost", null, null, null));
114 }
115
116 @Test
117 public void testReleaseUnknownEntry() throws Exception {
118 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(2, 2);
119 Assertions.assertThrows(IllegalStateException.class, () ->
120 pool.release(new PoolEntry<>("somehost"), true));
121 }
122
123 @Test
124 public void testMaxLimits() throws Exception {
125 final HttpConnection conn1 = Mockito.mock(HttpConnection.class);
126 final HttpConnection conn2 = Mockito.mock(HttpConnection.class);
127 final HttpConnection conn3 = Mockito.mock(HttpConnection.class);
128
129 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(2, 10);
130 pool.setMaxPerRoute("somehost", 2);
131 pool.setMaxPerRoute("otherhost", 1);
132 pool.setMaxTotal(3);
133
134 final Future<PoolEntry<String, HttpConnection>> future1 = pool.lease("somehost", null);
135 final Future<PoolEntry<String, HttpConnection>> future2 = pool.lease("somehost", null);
136 final Future<PoolEntry<String, HttpConnection>> future3 = pool.lease("otherhost", null);
137
138 final PoolEntry<String, HttpConnection> entry1 = future1.get();
139 Assertions.assertNotNull(entry1);
140 entry1.assignConnection(conn1);
141 final PoolEntry<String, HttpConnection> entry2 = future2.get();
142 Assertions.assertNotNull(entry2);
143 entry2.assignConnection(conn2);
144 final PoolEntry<String, HttpConnection> entry3 = future3.get();
145 Assertions.assertNotNull(entry3);
146 entry3.assignConnection(conn3);
147
148 pool.release(entry1, true);
149 pool.release(entry2, true);
150 pool.release(entry3, true);
151
152 final PoolStats totals = pool.getTotalStats();
153 Assertions.assertEquals(3, totals.getAvailable());
154 Assertions.assertEquals(0, totals.getLeased());
155 Assertions.assertEquals(0, totals.getPending());
156
157 final Future<PoolEntry<String, HttpConnection>> future4 = pool.lease("somehost", null);
158 final Future<PoolEntry<String, HttpConnection>> future5 = pool.lease("somehost", null);
159 final Future<PoolEntry<String, HttpConnection>> future6 = pool.lease("otherhost", null);
160 final Future<PoolEntry<String, HttpConnection>> future7 = pool.lease("somehost", null);
161 final Future<PoolEntry<String, HttpConnection>> future8 = pool.lease("somehost", null);
162 final Future<PoolEntry<String, HttpConnection>> future9 = pool.lease("otherhost", null);
163
164 Assertions.assertTrue(future4.isDone());
165 final PoolEntry<String, HttpConnection> entry4 = future4.get();
166 Assertions.assertNotNull(entry4);
167 Assertions.assertSame(conn2, entry4.getConnection());
168
169 Assertions.assertTrue(future5.isDone());
170 final PoolEntry<String, HttpConnection> entry5 = future5.get();
171 Assertions.assertNotNull(entry5);
172 Assertions.assertSame(conn1, entry5.getConnection());
173
174 Assertions.assertTrue(future6.isDone());
175 final PoolEntry<String, HttpConnection> entry6 = future6.get();
176 Assertions.assertNotNull(entry6);
177 Assertions.assertSame(conn3, entry6.getConnection());
178
179 Assertions.assertFalse(future7.isDone());
180 Assertions.assertFalse(future8.isDone());
181 Assertions.assertFalse(future9.isDone());
182
183 pool.release(entry4, true);
184 pool.release(entry5, false);
185 pool.release(entry6, true);
186
187 Assertions.assertTrue(future7.isDone());
188 final PoolEntry<String, HttpConnection> entry7 = future7.get();
189 Assertions.assertNotNull(entry7);
190 Assertions.assertSame(conn2, entry7.getConnection());
191
192 Assertions.assertTrue(future8.isDone());
193 final PoolEntry<String, HttpConnection> entry8 = future8.get();
194 Assertions.assertNotNull(entry8);
195 Assertions.assertNull(entry8.getConnection());
196
197 Assertions.assertTrue(future9.isDone());
198 final PoolEntry<String, HttpConnection> entry9 = future9.get();
199 Assertions.assertNotNull(entry9);
200 Assertions.assertSame(conn3, entry9.getConnection());
201 }
202
203 @Test
204 public void testConnectionRedistributionOnTotalMaxLimit() throws Exception {
205 final HttpConnection conn1 = Mockito.mock(HttpConnection.class);
206 final HttpConnection conn2 = Mockito.mock(HttpConnection.class);
207 final HttpConnection conn3 = Mockito.mock(HttpConnection.class);
208 final HttpConnection conn4 = Mockito.mock(HttpConnection.class);
209 final HttpConnection conn5 = Mockito.mock(HttpConnection.class);
210
211 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(2, 10);
212 pool.setMaxPerRoute("somehost", 2);
213 pool.setMaxPerRoute("otherhost", 2);
214 pool.setMaxTotal(2);
215
216 final Future<PoolEntry<String, HttpConnection>> future1 = pool.lease("somehost", null);
217 final Future<PoolEntry<String, HttpConnection>> future2 = pool.lease("somehost", null);
218 final Future<PoolEntry<String, HttpConnection>> future3 = pool.lease("otherhost", null);
219 final Future<PoolEntry<String, HttpConnection>> future4 = pool.lease("otherhost", null);
220
221 Assertions.assertTrue(future1.isDone());
222 final PoolEntry<String, HttpConnection> entry1 = future1.get();
223 Assertions.assertNotNull(entry1);
224 Assertions.assertFalse(entry1.hasConnection());
225 entry1.assignConnection(conn1);
226 Assertions.assertTrue(future2.isDone());
227 final PoolEntry<String, HttpConnection> entry2 = future2.get();
228 Assertions.assertNotNull(entry2);
229 Assertions.assertFalse(entry2.hasConnection());
230 entry2.assignConnection(conn2);
231
232 Assertions.assertFalse(future3.isDone());
233 Assertions.assertFalse(future4.isDone());
234
235 PoolStats totals = pool.getTotalStats();
236 Assertions.assertEquals(0, totals.getAvailable());
237 Assertions.assertEquals(2, totals.getLeased());
238 Assertions.assertEquals(2, totals.getPending());
239
240 pool.release(entry1, true);
241 pool.release(entry2, true);
242
243 Assertions.assertTrue(future3.isDone());
244 final PoolEntry<String, HttpConnection> entry3 = future3.get();
245 Assertions.assertNotNull(entry3);
246 Assertions.assertFalse(entry3.hasConnection());
247 entry3.assignConnection(conn3);
248 Assertions.assertTrue(future4.isDone());
249 final PoolEntry<String, HttpConnection> entry4 = future4.get();
250 Assertions.assertNotNull(entry4);
251 Assertions.assertFalse(entry4.hasConnection());
252 entry4.assignConnection(conn4);
253
254 totals = pool.getTotalStats();
255 Assertions.assertEquals(0, totals.getAvailable());
256 Assertions.assertEquals(2, totals.getLeased());
257 Assertions.assertEquals(0, totals.getPending());
258
259 final Future<PoolEntry<String, HttpConnection>> future5 = pool.lease("somehost", null);
260 final Future<PoolEntry<String, HttpConnection>> future6 = pool.lease("otherhost", null);
261
262 pool.release(entry3, true);
263 pool.release(entry4, true);
264
265 Assertions.assertTrue(future5.isDone());
266 final PoolEntry<String, HttpConnection> entry5 = future5.get();
267 Assertions.assertNotNull(entry5);
268 Assertions.assertFalse(entry5.hasConnection());
269 entry5.assignConnection(conn5);
270 Assertions.assertTrue(future6.isDone());
271 final PoolEntry<String, HttpConnection> entry6 = future6.get();
272 Assertions.assertNotNull(entry6);
273 Assertions.assertTrue(entry6.hasConnection());
274 Assertions.assertSame(conn4, entry6.getConnection());
275
276 totals = pool.getTotalStats();
277 Assertions.assertEquals(0, totals.getAvailable());
278 Assertions.assertEquals(2, totals.getLeased());
279 Assertions.assertEquals(0, totals.getPending());
280
281 pool.release(entry5, true);
282 pool.release(entry6, true);
283
284 totals = pool.getTotalStats();
285 Assertions.assertEquals(2, totals.getAvailable());
286 Assertions.assertEquals(0, totals.getLeased());
287 Assertions.assertEquals(0, totals.getPending());
288 }
289
290 @Test
291 public void testStatefulConnectionRedistributionOnPerRouteMaxLimit() throws Exception {
292 final HttpConnection conn1 = Mockito.mock(HttpConnection.class);
293 final HttpConnection conn2 = Mockito.mock(HttpConnection.class);
294
295 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(2, 10);
296 pool.setMaxPerRoute("somehost", 2);
297 pool.setMaxTotal(2);
298
299 final Future<PoolEntry<String, HttpConnection>> future1 = pool.lease("somehost", null);
300 final Future<PoolEntry<String, HttpConnection>> future2 = pool.lease("somehost", null);
301
302 Assertions.assertTrue(future1.isDone());
303 final PoolEntry<String, HttpConnection> entry1 = future1.get();
304 entry1.assignConnection(conn1);
305 Assertions.assertNotNull(entry1);
306 Assertions.assertTrue(future2.isDone());
307 final PoolEntry<String, HttpConnection> entry2 = future2.get();
308 Assertions.assertNotNull(entry2);
309 entry2.assignConnection(conn2);
310
311 PoolStats totals = pool.getTotalStats();
312 Assertions.assertEquals(0, totals.getAvailable());
313 Assertions.assertEquals(2, totals.getLeased());
314 Assertions.assertEquals(0, totals.getPending());
315
316 entry1.updateState("some-stuff");
317 pool.release(entry1, true);
318 entry2.updateState("some-stuff");
319 pool.release(entry2, true);
320
321 final Future<PoolEntry<String, HttpConnection>> future3 = pool.lease("somehost", "some-stuff");
322 final Future<PoolEntry<String, HttpConnection>> future4 = pool.lease("somehost", "some-stuff");
323
324 Assertions.assertTrue(future1.isDone());
325 final PoolEntry<String, HttpConnection> entry3 = future3.get();
326 Assertions.assertNotNull(entry3);
327 Assertions.assertSame(conn2, entry3.getConnection());
328 Assertions.assertTrue(future4.isDone());
329 final PoolEntry<String, HttpConnection> entry4 = future4.get();
330 Assertions.assertNotNull(entry4);
331 Assertions.assertSame(conn1, entry4.getConnection());
332
333 pool.release(entry3, true);
334 pool.release(entry4, true);
335
336 totals = pool.getTotalStats();
337 Assertions.assertEquals(2, totals.getAvailable());
338 Assertions.assertEquals(0, totals.getLeased());
339 Assertions.assertEquals(0, totals.getPending());
340
341 final Future<PoolEntry<String, HttpConnection>> future5 = pool.lease("somehost", "some-other-stuff");
342
343 Assertions.assertTrue(future5.isDone());
344
345 Mockito.verify(conn2).close(CloseMode.GRACEFUL);
346 Mockito.verify(conn1, Mockito.never()).close(ArgumentMatchers.any());
347
348 totals = pool.getTotalStats();
349 Assertions.assertEquals(1, totals.getAvailable());
350 Assertions.assertEquals(1, totals.getLeased());
351 }
352
353 @Test
354 public void testCreateNewIfExpired() throws Exception {
355 final HttpConnection conn1 = Mockito.mock(HttpConnection.class);
356
357 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(2, 2);
358
359 final Future<PoolEntry<String, HttpConnection>> future1 = pool.lease("somehost", null);
360
361 Assertions.assertTrue(future1.isDone());
362 final PoolEntry<String, HttpConnection> entry1 = future1.get();
363 Assertions.assertNotNull(entry1);
364 entry1.assignConnection(conn1);
365
366 entry1.updateExpiry(TimeValue.of(1, TimeUnit.MILLISECONDS));
367 pool.release(entry1, true);
368
369 Thread.sleep(200L);
370
371 final Future<PoolEntry<String, HttpConnection>> future2 = pool.lease("somehost", null);
372
373 Assertions.assertTrue(future2.isDone());
374
375 Mockito.verify(conn1).close(CloseMode.GRACEFUL);
376
377 final PoolStats totals = pool.getTotalStats();
378 Assertions.assertEquals(0, totals.getAvailable());
379 Assertions.assertEquals(1, totals.getLeased());
380 Assertions.assertEquals(Collections.singleton("somehost"), pool.getRoutes());
381 final PoolStats stats = pool.getStats("somehost");
382 Assertions.assertEquals(0, stats.getAvailable());
383 Assertions.assertEquals(1, stats.getLeased());
384 }
385
386 @Test
387 public void testCloseExpired() throws Exception {
388 final HttpConnection conn1 = Mockito.mock(HttpConnection.class);
389 final HttpConnection conn2 = Mockito.mock(HttpConnection.class);
390
391 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(2, 2);
392
393 final Future<PoolEntry<String, HttpConnection>> future1 = pool.lease("somehost", null);
394 final Future<PoolEntry<String, HttpConnection>> future2 = pool.lease("somehost", null);
395
396 Assertions.assertTrue(future1.isDone());
397 final PoolEntry<String, HttpConnection> entry1 = future1.get();
398 Assertions.assertNotNull(entry1);
399 entry1.assignConnection(conn1);
400 Assertions.assertTrue(future2.isDone());
401 final PoolEntry<String, HttpConnection> entry2 = future2.get();
402 Assertions.assertNotNull(entry2);
403 entry2.assignConnection(conn2);
404
405 entry1.updateExpiry(TimeValue.of(1, TimeUnit.MILLISECONDS));
406 pool.release(entry1, true);
407
408 Thread.sleep(200);
409
410 entry2.updateExpiry(TimeValue.of(1000, TimeUnit.SECONDS));
411 pool.release(entry2, true);
412
413 pool.closeExpired();
414
415 Mockito.verify(conn1).close(CloseMode.GRACEFUL);
416 Mockito.verify(conn2, Mockito.never()).close(ArgumentMatchers.any());
417
418 final PoolStats totals = pool.getTotalStats();
419 Assertions.assertEquals(1, totals.getAvailable());
420 Assertions.assertEquals(0, totals.getLeased());
421 Assertions.assertEquals(0, totals.getPending());
422 final PoolStats stats = pool.getStats("somehost");
423 Assertions.assertEquals(1, stats.getAvailable());
424 Assertions.assertEquals(0, stats.getLeased());
425 Assertions.assertEquals(0, stats.getPending());
426 }
427
428 @Test
429 public void testCloseIdle() throws Exception {
430 final HttpConnection conn1 = Mockito.mock(HttpConnection.class);
431 final HttpConnection conn2 = Mockito.mock(HttpConnection.class);
432
433 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(2, 2);
434
435 final Future<PoolEntry<String, HttpConnection>> future1 = pool.lease("somehost", null);
436 final Future<PoolEntry<String, HttpConnection>> future2 = pool.lease("somehost", null);
437
438 Assertions.assertTrue(future1.isDone());
439 final PoolEntry<String, HttpConnection> entry1 = future1.get();
440 Assertions.assertNotNull(entry1);
441 entry1.assignConnection(conn1);
442 Assertions.assertTrue(future2.isDone());
443 final PoolEntry<String, HttpConnection> entry2 = future2.get();
444 Assertions.assertNotNull(entry2);
445 entry2.assignConnection(conn2);
446
447 entry1.updateState(null);
448 pool.release(entry1, true);
449
450 Thread.sleep(200L);
451
452 entry2.updateState(null);
453 pool.release(entry2, true);
454
455 pool.closeIdle(TimeValue.of(50, TimeUnit.MILLISECONDS));
456
457 Mockito.verify(conn1).close(CloseMode.GRACEFUL);
458 Mockito.verify(conn2, Mockito.never()).close(ArgumentMatchers.any());
459
460 PoolStats totals = pool.getTotalStats();
461 Assertions.assertEquals(1, totals.getAvailable());
462 Assertions.assertEquals(0, totals.getLeased());
463 Assertions.assertEquals(0, totals.getPending());
464 PoolStats stats = pool.getStats("somehost");
465 Assertions.assertEquals(1, stats.getAvailable());
466 Assertions.assertEquals(0, stats.getLeased());
467 Assertions.assertEquals(0, stats.getPending());
468
469 pool.closeIdle(TimeValue.of(-1, TimeUnit.MILLISECONDS));
470
471 Mockito.verify(conn2).close(CloseMode.GRACEFUL);
472
473 totals = pool.getTotalStats();
474 Assertions.assertEquals(0, totals.getAvailable());
475 Assertions.assertEquals(0, totals.getLeased());
476 Assertions.assertEquals(0, totals.getPending());
477 stats = pool.getStats("somehost");
478 Assertions.assertEquals(0, stats.getAvailable());
479 Assertions.assertEquals(0, stats.getLeased());
480 Assertions.assertEquals(0, stats.getPending());
481 }
482
483 @Test
484 public void testLeaseRequestTimeout() throws Exception {
485 final HttpConnection conn1 = Mockito.mock(HttpConnection.class);
486
487 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(1, 1);
488
489 final Future<PoolEntry<String, HttpConnection>> future1 = pool.lease("somehost", null, Timeout.ofMilliseconds(0), null);
490 final Future<PoolEntry<String, HttpConnection>> future2 = pool.lease("somehost", null, Timeout.ofMilliseconds(0), null);
491 final Future<PoolEntry<String, HttpConnection>> future3 = pool.lease("somehost", null, Timeout.ofMilliseconds(10), null);
492
493 Assertions.assertTrue(future1.isDone());
494 final PoolEntry<String, HttpConnection> entry1 = future1.get();
495 Assertions.assertNotNull(entry1);
496 entry1.assignConnection(conn1);
497 Assertions.assertFalse(future2.isDone());
498 Assertions.assertFalse(future3.isDone());
499
500 Thread.sleep(100);
501
502 pool.validatePendingRequests();
503
504 Assertions.assertFalse(future2.isDone());
505 Assertions.assertTrue(future3.isDone());
506 }
507
508 private static class HoldInternalLockThread extends Thread {
509 private HoldInternalLockThread(final StrictConnPool<String, HttpConnection> pool, final CountDownLatch lockHeld) {
510 super(() -> {
511 pool.lease("somehost", null);
512 pool.enumLeased(object -> {
513 try {
514 lockHeld.countDown();
515 Thread.sleep(Long.MAX_VALUE);
516 } catch (final InterruptedException ignored) {
517 }
518 });
519 });
520 }
521 }
522
523 @Test
524 public void testLeaseRequestLockTimeout() throws Exception {
525 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(1, 1);
526 final CountDownLatch lockHeld = new CountDownLatch(1);
527 final Thread holdInternalLock = new HoldInternalLockThread(pool, lockHeld);
528
529 holdInternalLock.start();
530 lockHeld.await();
531
532
533 final Future<PoolEntry<String, HttpConnection>> future2 = pool.lease("somehost", null, Timeout.ofMilliseconds(10), null);
534
535 final ExecutionException executionException = Assertions.assertThrows(ExecutionException.class, () ->
536 future2.get());
537 Assertions.assertTrue(executionException.getCause() instanceof DeadlineTimeoutException);
538 holdInternalLock.interrupt();
539 }
540
541 @Test
542 public void testLeaseRequestInterrupted() throws Exception {
543 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(1, 1);
544 final CountDownLatch lockHeld = new CountDownLatch(1);
545 final Thread holdInternalLock = new HoldInternalLockThread(pool, lockHeld);
546
547 holdInternalLock.start();
548 lockHeld.await();
549
550 Thread.currentThread().interrupt();
551
552 final Future<PoolEntry<String, HttpConnection>> future2 = pool.lease("somehost", null, Timeout.ofMilliseconds(10), null);
553
554 Assertions.assertTrue(Thread.interrupted());
555 Assertions.assertThrows(CancellationException.class, () -> future2.get());
556 holdInternalLock.interrupt();
557 }
558
559 @Test
560 public void testLeaseRequestCanceled() throws Exception {
561 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(1, 1);
562
563 final Future<PoolEntry<String, HttpConnection>> future1 = pool.lease("somehost", null, Timeout.ofMilliseconds(0), null);
564
565 Assertions.assertTrue(future1.isDone());
566 final PoolEntry<String, HttpConnection> entry1 = future1.get();
567 Assertions.assertNotNull(entry1);
568 entry1.assignConnection(Mockito.mock(HttpConnection.class));
569
570 final Future<PoolEntry<String, HttpConnection>> future2 = pool.lease("somehost", null, Timeout.ofMilliseconds(0), null);
571 future2.cancel(true);
572
573 pool.release(entry1, true);
574
575 final PoolStats totals = pool.getTotalStats();
576 Assertions.assertEquals(1, totals.getAvailable());
577 Assertions.assertEquals(0, totals.getLeased());
578 }
579
580 @Test
581 public void testGetStatsInvalid() throws Exception {
582 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(2, 2);
583 Assertions.assertThrows(NullPointerException.class, () ->
584 pool.getStats(null));
585 }
586
587 @Test
588 public void testSetMaxInvalid() throws Exception {
589 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(2, 2);
590 Assertions.assertThrows(IllegalArgumentException.class, () ->
591 pool.setMaxTotal(-1));
592 Assertions.assertThrows(NullPointerException.class, () ->
593 pool.setMaxPerRoute(null, 1));
594 Assertions.assertThrows(IllegalArgumentException.class, () ->
595 pool.setDefaultMaxPerRoute(-1));
596 }
597
598 @Test
599 public void testSetMaxPerRoute() throws Exception {
600 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(2, 2);
601 pool.setMaxPerRoute("somehost", 1);
602 Assertions.assertEquals(1, pool.getMaxPerRoute("somehost"));
603 pool.setMaxPerRoute("somehost", 0);
604 Assertions.assertEquals(0, pool.getMaxPerRoute("somehost"));
605 pool.setMaxPerRoute("somehost", -1);
606 Assertions.assertEquals(2, pool.getMaxPerRoute("somehost"));
607 }
608
609 @Test
610 public void testShutdown() throws Exception {
611 final StrictConnPool<String, HttpConnection> pool = new StrictConnPool<>(2, 2);
612 pool.close(CloseMode.GRACEFUL);
613 Assertions.assertThrows(IllegalStateException.class, () -> pool.lease("somehost", null));
614
615 pool.release(new PoolEntry<>("somehost"), true);
616 }
617
618 }