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