View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.http.nio.pool;
28  
29  import java.io.IOException;
30  import java.net.ConnectException;
31  import java.net.InetAddress;
32  import java.net.InetSocketAddress;
33  import java.net.SocketAddress;
34  import java.net.UnknownHostException;
35  import java.util.Collections;
36  import java.util.concurrent.CancellationException;
37  import java.util.concurrent.ExecutionException;
38  import java.util.concurrent.Future;
39  import java.util.concurrent.TimeUnit;
40  
41  import org.apache.http.concurrent.BasicFuture;
42  import org.apache.http.nio.reactor.ConnectingIOReactor;
43  import org.apache.http.nio.reactor.IOReactorStatus;
44  import org.apache.http.nio.reactor.IOSession;
45  import org.apache.http.nio.reactor.SessionRequest;
46  import org.apache.http.nio.reactor.SessionRequestCallback;
47  import org.apache.http.pool.PoolEntry;
48  import org.apache.http.pool.PoolStats;
49  import org.junit.Assert;
50  import org.junit.Test;
51  import org.mockito.Matchers;
52  import org.mockito.Mockito;
53  
54  public class TestNIOConnPool {
55  
56      static class LocalPoolEntry extends PoolEntry<String, IOSession> {
57  
58          private boolean closed;
59  
60          public LocalPoolEntry(final String route, final IOSession conn) {
61              super(null, route, conn);
62          }
63  
64          @Override
65          public void close() {
66              if (this.closed) {
67                  return;
68              }
69              this.closed = true;
70              getConnection().close();
71          }
72  
73          @Override
74          public boolean isClosed() {
75              return this.closed;
76          }
77  
78      }
79  
80      static class LocalConnFactory implements NIOConnFactory<String, IOSession> {
81  
82          @Override
83          public IOSession create(final String route, final IOSession session) throws IOException {
84              return session;
85          }
86  
87      }
88  
89      static class LocalAddressResolver implements SocketAddressResolver<String> {
90  
91          @Override
92          public SocketAddress resolveLocalAddress(final String route) {
93              return null;
94          }
95  
96          @Override
97          public SocketAddress resolveRemoteAddress(final String route) {
98              return InetSocketAddress.createUnresolved(route, 80);
99          }
100 
101     }
102 
103     static class LocalSessionPool extends AbstractNIOConnPool<String, IOSession, LocalPoolEntry> {
104 
105         public LocalSessionPool(
106                 final ConnectingIOReactor ioreactor, final int defaultMaxPerRoute, final int maxTotal) {
107             super(ioreactor, new LocalConnFactory(), new LocalAddressResolver(), defaultMaxPerRoute, maxTotal);
108         }
109 
110         public LocalSessionPool(
111                 final ConnectingIOReactor ioreactor,
112                 final SocketAddressResolver<String> addressResolver,
113                 final int defaultMaxPerRoute, final int maxTotal) {
114             super(ioreactor, new LocalConnFactory(), addressResolver, defaultMaxPerRoute, maxTotal);
115         }
116 
117         @Override
118         protected LocalPoolEntry createEntry(final String route, final IOSession session) {
119             return new LocalPoolEntry(route, session);
120         }
121 
122     }
123 
124     @Test
125     public void testEmptyPool() throws Exception {
126         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
127         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 10);
128         final PoolStats totals = pool.getTotalStats();
129         Assert.assertEquals(0, totals.getAvailable());
130         Assert.assertEquals(0, totals.getLeased());
131         Assert.assertEquals(0, totals.getPending());
132         Assert.assertEquals(10, totals.getMax());
133         Assert.assertEquals(Collections.emptySet(), pool.getRoutes());
134         final PoolStats stats = pool.getStats("somehost");
135         Assert.assertEquals(0, stats.getAvailable());
136         Assert.assertEquals(0, stats.getLeased());
137         Assert.assertEquals(0, stats.getPending());
138         Assert.assertEquals(2, stats.getMax());
139         Assert.assertEquals("[leased: []][available: []][pending: []]", pool.toString());
140     }
141 
142     @Test
143     public void testInternalLeaseRequest() throws Exception {
144         final LeaseRequest<String, IOSession, LocalPoolEntry> leaseRequest =
145             new LeaseRequest<String, IOSession, LocalPoolEntry>("somehost", null, 0, 0,
146                     new BasicFuture<LocalPoolEntry>(null));
147         Assert.assertEquals("[somehost][null]", leaseRequest.toString());
148     }
149 
150     @Test
151     public void testInvalidConstruction() throws Exception {
152         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
153         try {
154             new LocalSessionPool(null, 1, 1);
155             Assert.fail("IllegalArgumentException should have been thrown");
156         } catch (final IllegalArgumentException expected) {
157         }
158         try {
159             new LocalSessionPool(ioreactor, -1, 1);
160             Assert.fail("IllegalArgumentException should have been thrown");
161         } catch (final IllegalArgumentException expected) {
162         }
163         try {
164             new LocalSessionPool(ioreactor, 1, -1);
165             Assert.fail("IllegalArgumentException should have been thrown");
166         } catch (final IllegalArgumentException expected) {
167         }
168     }
169 
170     @Test
171     public void testSuccessfulConnect() throws Exception {
172         final IOSession iosession = Mockito.mock(IOSession.class);
173         final SessionRequest sessionRequest = Mockito.mock(SessionRequest.class);
174         Mockito.when(sessionRequest.getAttachment()).thenReturn("somehost");
175         Mockito.when(sessionRequest.getSession()).thenReturn(iosession);
176         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
177         Mockito.when(ioreactor.connect(
178                 Matchers.any(SocketAddress.class),
179                 Matchers.any(SocketAddress.class),
180                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
181                 thenReturn(sessionRequest);
182         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 10);
183         final Future<LocalPoolEntry> future = pool.lease("somehost", null, 100, TimeUnit.MILLISECONDS, null);
184         Mockito.verify(sessionRequest).setConnectTimeout(100);
185 
186         PoolStats totals = pool.getTotalStats();
187         Assert.assertEquals(0, totals.getAvailable());
188         Assert.assertEquals(0, totals.getLeased());
189         Assert.assertEquals(1, totals.getPending());
190 
191         pool.requestCompleted(sessionRequest);
192 
193         Assert.assertTrue(future.isDone());
194         Assert.assertFalse(future.isCancelled());
195         final LocalPoolEntry entry = future.get();
196         Assert.assertNotNull(entry);
197 
198         totals = pool.getTotalStats();
199         Assert.assertEquals(0, totals.getAvailable());
200         Assert.assertEquals(1, totals.getLeased());
201         Assert.assertEquals(0, totals.getPending());
202     }
203 
204     @Test
205     public void testFailedConnect() throws Exception {
206         final SessionRequest sessionRequest = Mockito.mock(SessionRequest.class);
207         Mockito.when(sessionRequest.getAttachment()).thenReturn("somehost");
208         Mockito.when(sessionRequest.getException()).thenReturn(new IOException());
209         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
210         Mockito.when(ioreactor.connect(
211                 Matchers.any(SocketAddress.class),
212                 Matchers.any(SocketAddress.class),
213                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
214                 thenReturn(sessionRequest);
215         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 10);
216         final Future<LocalPoolEntry> future = pool.lease("somehost", null);
217 
218         PoolStats totals = pool.getTotalStats();
219         Assert.assertEquals(0, totals.getAvailable());
220         Assert.assertEquals(0, totals.getLeased());
221         Assert.assertEquals(1, totals.getPending());
222 
223         pool.requestFailed(sessionRequest);
224 
225         Assert.assertTrue(future.isDone());
226         Assert.assertFalse(future.isCancelled());
227         try {
228             future.get();
229             Assert.fail("ExecutionException should have been thrown");
230         } catch (final ExecutionException ex) {
231             Assert.assertTrue(ex.getCause() instanceof IOException);
232         }
233 
234         totals = pool.getTotalStats();
235         Assert.assertEquals(0, totals.getAvailable());
236         Assert.assertEquals(0, totals.getLeased());
237         Assert.assertEquals(0, totals.getPending());
238     }
239 
240     @Test
241     public void testCencelledConnect() throws Exception {
242         final IOSession iosession = Mockito.mock(IOSession.class);
243         final SessionRequest sessionRequest = Mockito.mock(SessionRequest.class);
244         Mockito.when(sessionRequest.getAttachment()).thenReturn("somehost");
245         Mockito.when(sessionRequest.getSession()).thenReturn(iosession);
246         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
247         Mockito.when(ioreactor.connect(
248                 Matchers.any(SocketAddress.class),
249                 Matchers.any(SocketAddress.class),
250                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
251                 thenReturn(sessionRequest);
252         Mockito.when(ioreactor.getStatus()).thenReturn(IOReactorStatus.ACTIVE);
253         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 10);
254         final Future<LocalPoolEntry> future = pool.lease("somehost", null);
255 
256         PoolStats totals = pool.getTotalStats();
257         Assert.assertEquals(0, totals.getAvailable());
258         Assert.assertEquals(0, totals.getLeased());
259         Assert.assertEquals(1, totals.getPending());
260 
261         pool.requestCancelled(sessionRequest);
262 
263         Assert.assertTrue(future.isDone());
264         Assert.assertTrue(future.isCancelled());
265         try {
266             future.get();
267             Assert.fail("CancellationException expected");
268         } catch (final CancellationException ignore) {
269         }
270 
271         totals = pool.getTotalStats();
272         Assert.assertEquals(0, totals.getAvailable());
273         Assert.assertEquals(0, totals.getLeased());
274         Assert.assertEquals(0, totals.getPending());
275     }
276 
277     @Test
278     public void testTimeoutConnect() throws Exception {
279         final IOSession iosession = Mockito.mock(IOSession.class);
280         final SessionRequest sessionRequest = Mockito.mock(SessionRequest.class);
281         Mockito.when(sessionRequest.getAttachment()).thenReturn("somehost");
282         Mockito.when(sessionRequest.getRemoteAddress())
283                 .thenReturn(new InetSocketAddress(InetAddress.getByAddress(new byte[]{127, 0, 0, 1}), 80));
284         Mockito.when(sessionRequest.getSession()).thenReturn(iosession);
285         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
286         Mockito.when(ioreactor.connect(
287                 Matchers.any(SocketAddress.class),
288                 Matchers.any(SocketAddress.class),
289                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
290                 thenReturn(sessionRequest);
291         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 10);
292         final Future<LocalPoolEntry> future = pool.lease("somehost", null);
293 
294         PoolStats totals = pool.getTotalStats();
295         Assert.assertEquals(0, totals.getAvailable());
296         Assert.assertEquals(0, totals.getLeased());
297         Assert.assertEquals(1, totals.getPending());
298 
299         pool.requestTimeout(sessionRequest);
300 
301         Assert.assertTrue(future.isDone());
302         Assert.assertFalse(future.isCancelled());
303         try {
304             future.get();
305             Assert.fail("ExecutionException should have been thrown");
306         } catch (final ExecutionException ex) {
307             Assert.assertTrue(ex.getCause() instanceof ConnectException);
308             Assert.assertEquals("Timeout connecting to [/127.0.0.1:80]", ex.getCause().getMessage());
309         }
310 
311         totals = pool.getTotalStats();
312         Assert.assertEquals(0, totals.getAvailable());
313         Assert.assertEquals(0, totals.getLeased());
314         Assert.assertEquals(0, totals.getPending());
315     }
316 
317     @Test
318     public void testConnectUnknownHost() throws Exception {
319         final SessionRequest sessionRequest = Mockito.mock(SessionRequest.class);
320         Mockito.when(sessionRequest.getAttachment()).thenReturn("somehost");
321         Mockito.when(sessionRequest.getException()).thenReturn(new IOException());
322         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
323         @SuppressWarnings("unchecked")
324         final SocketAddressResolver<String> addressResolver = Mockito.mock(SocketAddressResolver.class);
325         Mockito.when(addressResolver.resolveRemoteAddress("somehost")).thenThrow(new UnknownHostException());
326         final LocalSessionPool pool = new LocalSessionPool(ioreactor, addressResolver, 2, 10);
327         final Future<LocalPoolEntry> future = pool.lease("somehost", null);
328 
329         Assert.assertTrue(future.isDone());
330         Assert.assertFalse(future.isCancelled());
331         try {
332             future.get();
333             Assert.fail("ExecutionException should have been thrown");
334         } catch (final ExecutionException ex) {
335             Assert.assertTrue(ex.getCause() instanceof UnknownHostException);
336         }
337     }
338 
339     @Test
340     public void testLeaseRelease() throws Exception {
341         final IOSession iosession1 = Mockito.mock(IOSession.class);
342         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
343         Mockito.when(sessionRequest1.getAttachment()).thenReturn("somehost");
344         Mockito.when(sessionRequest1.getSession()).thenReturn(iosession1);
345 
346         final IOSession iosession2 = Mockito.mock(IOSession.class);
347         final SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
348         Mockito.when(sessionRequest2.getAttachment()).thenReturn("otherhost");
349         Mockito.when(sessionRequest2.getSession()).thenReturn(iosession2);
350 
351         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
352         Mockito.when(ioreactor.connect(
353                 Matchers.eq(InetSocketAddress.createUnresolved("somehost", 80)),
354                 Matchers.any(SocketAddress.class),
355                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
356                 thenReturn(sessionRequest1);
357         Mockito.when(ioreactor.connect(
358                 Matchers.eq(InetSocketAddress.createUnresolved("otherhost", 80)),
359                 Matchers.any(SocketAddress.class),
360                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
361                 thenReturn(sessionRequest2);
362 
363         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 10);
364         final Future<LocalPoolEntry> future1 = pool.lease("somehost", null);
365         pool.requestCompleted(sessionRequest1);
366         final Future<LocalPoolEntry> future2 = pool.lease("somehost", null);
367         pool.requestCompleted(sessionRequest1);
368         final Future<LocalPoolEntry> future3 = pool.lease("otherhost", null);
369         pool.requestCompleted(sessionRequest2);
370 
371         final LocalPoolEntry entry1 = future1.get();
372         Assert.assertNotNull(entry1);
373         final LocalPoolEntry entry2 = future2.get();
374         Assert.assertNotNull(entry2);
375         final LocalPoolEntry entry3 = future3.get();
376         Assert.assertNotNull(entry3);
377 
378         pool.release(entry1, true);
379         pool.release(entry2, true);
380         pool.release(entry3, false);
381         Mockito.verify(iosession1, Mockito.never()).close();
382         Mockito.verify(iosession2, Mockito.times(1)).close();
383 
384         final PoolStats totals = pool.getTotalStats();
385         Assert.assertEquals(2, totals.getAvailable());
386         Assert.assertEquals(0, totals.getLeased());
387         Assert.assertEquals(0, totals.getPending());
388     }
389 
390     @Test
391     public void testLeaseIllegal() throws Exception {
392         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
393         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 10);
394         try {
395             pool.lease(null, null, 0, TimeUnit.MILLISECONDS, null);
396             Assert.fail("IllegalArgumentException should have been thrown");
397         } catch (final IllegalArgumentException expected) {
398         }
399         try {
400             pool.lease("somehost", null, 0, null, null);
401             Assert.fail("IllegalArgumentException should have been thrown");
402         } catch (final IllegalArgumentException expected) {
403         }
404     }
405 
406     @Test
407     public void testReleaseUnknownEntry() throws Exception {
408         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
409         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 2);
410         pool.release(new LocalPoolEntry("somehost", Mockito.mock(IOSession.class)), true);
411     }
412 
413     @Test
414     public void testMaxLimits() throws Exception {
415         final IOSession iosession1 = Mockito.mock(IOSession.class);
416         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
417         Mockito.when(sessionRequest1.getAttachment()).thenReturn("somehost");
418         Mockito.when(sessionRequest1.getSession()).thenReturn(iosession1);
419 
420         final IOSession iosession2 = Mockito.mock(IOSession.class);
421         final SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
422         Mockito.when(sessionRequest2.getAttachment()).thenReturn("otherhost");
423         Mockito.when(sessionRequest2.getSession()).thenReturn(iosession2);
424 
425         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
426         Mockito.when(ioreactor.connect(
427                 Matchers.eq(InetSocketAddress.createUnresolved("somehost", 80)),
428                 Matchers.any(SocketAddress.class),
429                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
430                 thenReturn(sessionRequest1);
431         Mockito.when(ioreactor.connect(
432                 Matchers.eq(InetSocketAddress.createUnresolved("otherhost", 80)),
433                 Matchers.any(SocketAddress.class),
434                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
435                 thenReturn(sessionRequest2);
436 
437         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 10);
438         pool.setMaxPerRoute("somehost", 2);
439         pool.setMaxPerRoute("otherhost", 1);
440         pool.setMaxTotal(3);
441 
442         final Future<LocalPoolEntry> future1 = pool.lease("somehost", null);
443         pool.requestCompleted(sessionRequest1);
444         final Future<LocalPoolEntry> future2 = pool.lease("somehost", null);
445         pool.requestCompleted(sessionRequest1);
446         final Future<LocalPoolEntry> future3 = pool.lease("otherhost", null);
447         pool.requestCompleted(sessionRequest2);
448 
449         final LocalPoolEntry entry1 = future1.get();
450         Assert.assertNotNull(entry1);
451         final LocalPoolEntry entry2 = future2.get();
452         Assert.assertNotNull(entry2);
453         final LocalPoolEntry entry3 = future3.get();
454         Assert.assertNotNull(entry3);
455 
456         pool.release(entry1, true);
457         pool.release(entry2, true);
458         pool.release(entry3, true);
459 
460         final PoolStats totals = pool.getTotalStats();
461         Assert.assertEquals(3, totals.getAvailable());
462         Assert.assertEquals(0, totals.getLeased());
463         Assert.assertEquals(0, totals.getPending());
464 
465         final Future<LocalPoolEntry> future4 = pool.lease("somehost", null);
466         final Future<LocalPoolEntry> future5 = pool.lease("somehost", null);
467         final Future<LocalPoolEntry> future6 = pool.lease("otherhost", null);
468         final Future<LocalPoolEntry> future7 = pool.lease("somehost", null);
469         final Future<LocalPoolEntry> future8 = pool.lease("somehost", null);
470         final Future<LocalPoolEntry> future9 = pool.lease("otherhost", null);
471 
472         Assert.assertTrue(future4.isDone());
473         final LocalPoolEntry entry4 = future4.get();
474         Assert.assertNotNull(entry4);
475         Assert.assertTrue(future5.isDone());
476         final LocalPoolEntry entry5 = future5.get();
477         Assert.assertNotNull(entry5);
478         Assert.assertTrue(future6.isDone());
479         final LocalPoolEntry entry6 = future6.get();
480         Assert.assertNotNull(entry6);
481         Assert.assertFalse(future7.isDone());
482         Assert.assertFalse(future8.isDone());
483         Assert.assertFalse(future9.isDone());
484 
485         Mockito.verify(ioreactor, Mockito.times(3)).connect(
486                 Matchers.any(SocketAddress.class), Matchers.any(SocketAddress.class),
487                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
488 
489         pool.release(entry4, true);
490         pool.release(entry5, false);
491         pool.release(entry6, true);
492 
493         Assert.assertTrue(future7.isDone());
494         Assert.assertFalse(future8.isDone());
495         Assert.assertTrue(future9.isDone());
496 
497         Mockito.verify(ioreactor, Mockito.times(4)).connect(
498                 Matchers.any(SocketAddress.class), Matchers.any(SocketAddress.class),
499                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
500     }
501 
502     @Test
503     public void testConnectionRedistributionOnTotalMaxLimit() throws Exception {
504         final IOSession iosession1 = Mockito.mock(IOSession.class);
505         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
506         Mockito.when(sessionRequest1.getAttachment()).thenReturn("somehost");
507         Mockito.when(sessionRequest1.getSession()).thenReturn(iosession1);
508 
509         final IOSession iosession2 = Mockito.mock(IOSession.class);
510         final SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
511         Mockito.when(sessionRequest2.getAttachment()).thenReturn("somehost");
512         Mockito.when(sessionRequest2.getSession()).thenReturn(iosession2);
513 
514         final IOSession iosession3 = Mockito.mock(IOSession.class);
515         final SessionRequest sessionRequest3 = Mockito.mock(SessionRequest.class);
516         Mockito.when(sessionRequest3.getAttachment()).thenReturn("otherhost");
517         Mockito.when(sessionRequest3.getSession()).thenReturn(iosession3);
518 
519         final IOSession iosession4 = Mockito.mock(IOSession.class);
520         final SessionRequest sessionRequest4 = Mockito.mock(SessionRequest.class);
521         Mockito.when(sessionRequest4.getAttachment()).thenReturn("otherhost");
522         Mockito.when(sessionRequest4.getSession()).thenReturn(iosession4);
523 
524         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
525         Mockito.when(ioreactor.connect(
526                 Matchers.eq(InetSocketAddress.createUnresolved("somehost", 80)),
527                 Matchers.any(SocketAddress.class),
528                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
529                 thenReturn(sessionRequest1, sessionRequest2, sessionRequest1);
530         Mockito.when(ioreactor.connect(
531                 Matchers.eq(InetSocketAddress.createUnresolved("otherhost", 80)),
532                 Matchers.any(SocketAddress.class),
533                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
534                 thenReturn(sessionRequest3, sessionRequest4, sessionRequest3);
535 
536         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 10);
537         pool.setMaxPerRoute("somehost", 2);
538         pool.setMaxPerRoute("otherhost", 2);
539         pool.setMaxTotal(2);
540 
541         final Future<LocalPoolEntry> future1 = pool.lease("somehost", null);
542         final Future<LocalPoolEntry> future2 = pool.lease("somehost", null);
543         final Future<LocalPoolEntry> future3 = pool.lease("otherhost", null);
544         final Future<LocalPoolEntry> future4 = pool.lease("otherhost", null);
545 
546         Mockito.verify(ioreactor, Mockito.times(2)).connect(
547                 Matchers.eq(InetSocketAddress.createUnresolved("somehost", 80)),
548                 Matchers.any(SocketAddress.class),
549                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
550 
551         Mockito.verify(ioreactor, Mockito.never()).connect(
552                 Matchers.eq(InetSocketAddress.createUnresolved("otherhost", 80)),
553                 Matchers.any(SocketAddress.class),
554                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
555 
556         pool.requestCompleted(sessionRequest1);
557         pool.requestCompleted(sessionRequest2);
558 
559         Assert.assertTrue(future1.isDone());
560         final LocalPoolEntry entry1 = future1.get();
561         Assert.assertNotNull(entry1);
562         Assert.assertTrue(future2.isDone());
563         final LocalPoolEntry entry2 = future2.get();
564         Assert.assertNotNull(entry2);
565 
566         Assert.assertFalse(future3.isDone());
567         Assert.assertFalse(future4.isDone());
568 
569         PoolStats totals = pool.getTotalStats();
570         Assert.assertEquals(0, totals.getAvailable());
571         Assert.assertEquals(2, totals.getLeased());
572         Assert.assertEquals(0, totals.getPending());
573 
574         pool.release(entry1, true);
575         pool.release(entry2, true);
576 
577         Mockito.verify(ioreactor, Mockito.times(2)).connect(
578                 Matchers.eq(InetSocketAddress.createUnresolved("somehost", 80)),
579                 Matchers.any(SocketAddress.class),
580                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
581 
582         Mockito.verify(ioreactor, Mockito.times(2)).connect(
583                 Matchers.eq(InetSocketAddress.createUnresolved("otherhost", 80)),
584                 Matchers.any(SocketAddress.class),
585                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
586 
587         pool.requestCompleted(sessionRequest3);
588         pool.requestCompleted(sessionRequest4);
589 
590         Assert.assertTrue(future3.isDone());
591         final LocalPoolEntry entry3 = future3.get();
592         Assert.assertNotNull(entry3);
593         Assert.assertTrue(future4.isDone());
594         final LocalPoolEntry entry4 = future4.get();
595         Assert.assertNotNull(entry4);
596 
597         totals = pool.getTotalStats();
598         Assert.assertEquals(0, totals.getAvailable());
599         Assert.assertEquals(2, totals.getLeased());
600         Assert.assertEquals(0, totals.getPending());
601 
602         final Future<LocalPoolEntry> future5 = pool.lease("somehost", null);
603         final Future<LocalPoolEntry> future6 = pool.lease("otherhost", null);
604 
605         Mockito.verify(ioreactor, Mockito.times(2)).connect(
606                 Matchers.eq(InetSocketAddress.createUnresolved("somehost", 80)),
607                 Matchers.any(SocketAddress.class),
608                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
609 
610         Mockito.verify(ioreactor, Mockito.times(2)).connect(
611                 Matchers.eq(InetSocketAddress.createUnresolved("otherhost", 80)),
612                 Matchers.any(SocketAddress.class),
613                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
614 
615         pool.release(entry3, true);
616         pool.release(entry4, true);
617 
618         Mockito.verify(ioreactor, Mockito.times(3)).connect(
619                 Matchers.eq(InetSocketAddress.createUnresolved("somehost", 80)),
620                 Matchers.any(SocketAddress.class),
621                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
622 
623         Mockito.verify(ioreactor, Mockito.times(2)).connect(
624                 Matchers.eq(InetSocketAddress.createUnresolved("otherhost", 80)),
625                 Matchers.any(SocketAddress.class),
626                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
627 
628         pool.requestCompleted(sessionRequest1);
629 
630         Assert.assertTrue(future5.isDone());
631         final LocalPoolEntry entry5 = future5.get();
632         Assert.assertNotNull(entry5);
633         Assert.assertTrue(future6.isDone());
634         final LocalPoolEntry entry6 = future6.get();
635         Assert.assertNotNull(entry6);
636 
637         totals = pool.getTotalStats();
638         Assert.assertEquals(0, totals.getAvailable());
639         Assert.assertEquals(2, totals.getLeased());
640         Assert.assertEquals(0, totals.getPending());
641 
642         pool.release(entry5, true);
643         pool.release(entry6, true);
644 
645         Mockito.verify(ioreactor, Mockito.times(3)).connect(
646                 Matchers.eq(InetSocketAddress.createUnresolved("somehost", 80)),
647                 Matchers.any(SocketAddress.class),
648                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
649 
650         Mockito.verify(ioreactor, Mockito.times(2)).connect(
651                 Matchers.eq(InetSocketAddress.createUnresolved("otherhost", 80)),
652                 Matchers.any(SocketAddress.class),
653                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
654 
655         totals = pool.getTotalStats();
656         Assert.assertEquals(2, totals.getAvailable());
657         Assert.assertEquals(0, totals.getLeased());
658         Assert.assertEquals(0, totals.getPending());
659     }
660 
661     @Test
662     public void testStatefulConnectionRedistributionOnPerRouteMaxLimit() throws Exception {
663         final IOSession iosession1 = Mockito.mock(IOSession.class);
664         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
665         Mockito.when(sessionRequest1.getAttachment()).thenReturn("somehost");
666         Mockito.when(sessionRequest1.getSession()).thenReturn(iosession1);
667 
668         final IOSession iosession2 = Mockito.mock(IOSession.class);
669         final SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
670         Mockito.when(sessionRequest2.getAttachment()).thenReturn("somehost");
671         Mockito.when(sessionRequest2.getSession()).thenReturn(iosession2);
672 
673         final IOSession iosession3 = Mockito.mock(IOSession.class);
674         final SessionRequest sessionRequest3 = Mockito.mock(SessionRequest.class);
675         Mockito.when(sessionRequest3.getAttachment()).thenReturn("somehost");
676         Mockito.when(sessionRequest3.getSession()).thenReturn(iosession3);
677 
678         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
679         Mockito.when(ioreactor.connect(
680                 Matchers.eq(InetSocketAddress.createUnresolved("somehost", 80)),
681                 Matchers.any(SocketAddress.class),
682                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
683                 thenReturn(sessionRequest1, sessionRequest2, sessionRequest3);
684 
685         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 10);
686         pool.setMaxPerRoute("somehost", 2);
687         pool.setMaxTotal(2);
688 
689         final Future<LocalPoolEntry> future1 = pool.lease("somehost", null);
690         final Future<LocalPoolEntry> future2 = pool.lease("somehost", null);
691 
692         Mockito.verify(ioreactor, Mockito.times(2)).connect(
693                 Matchers.eq(InetSocketAddress.createUnresolved("somehost", 80)),
694                 Matchers.any(SocketAddress.class),
695                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
696 
697         pool.requestCompleted(sessionRequest1);
698         pool.requestCompleted(sessionRequest2);
699 
700         Assert.assertTrue(future1.isDone());
701         final LocalPoolEntry entry1 = future1.get();
702         Assert.assertNotNull(entry1);
703         Assert.assertTrue(future2.isDone());
704         final LocalPoolEntry entry2 = future2.get();
705         Assert.assertNotNull(entry2);
706 
707         PoolStats totals = pool.getTotalStats();
708         Assert.assertEquals(0, totals.getAvailable());
709         Assert.assertEquals(2, totals.getLeased());
710         Assert.assertEquals(0, totals.getPending());
711 
712         entry1.setState("some-stuff");
713         pool.release(entry1, true);
714         entry2.setState("some-stuff");
715         pool.release(entry2, true);
716 
717         final Future<LocalPoolEntry> future3 = pool.lease("somehost", "some-stuff");
718         final Future<LocalPoolEntry> future4 = pool.lease("somehost", "some-stuff");
719 
720         Assert.assertTrue(future1.isDone());
721         final LocalPoolEntry entry3 = future3.get();
722         Assert.assertNotNull(entry3);
723         Assert.assertTrue(future4.isDone());
724         final LocalPoolEntry entry4 = future4.get();
725         Assert.assertNotNull(entry4);
726 
727         Mockito.verify(ioreactor, Mockito.times(2)).connect(
728                 Matchers.eq(InetSocketAddress.createUnresolved("somehost", 80)),
729                 Matchers.any(SocketAddress.class),
730                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
731 
732         pool.release(entry3, true);
733         pool.release(entry4, true);
734 
735         totals = pool.getTotalStats();
736         Assert.assertEquals(2, totals.getAvailable());
737         Assert.assertEquals(0, totals.getLeased());
738         Assert.assertEquals(0, totals.getPending());
739 
740         final Future<LocalPoolEntry> future5 = pool.lease("somehost", "some-other-stuff");
741 
742         Assert.assertFalse(future5.isDone());
743 
744         Mockito.verify(ioreactor, Mockito.times(3)).connect(
745                 Matchers.eq(InetSocketAddress.createUnresolved("somehost", 80)),
746                 Matchers.any(SocketAddress.class),
747                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
748 
749         Mockito.verify(iosession2).close();
750         Mockito.verify(iosession1, Mockito.never()).close();
751 
752         totals = pool.getTotalStats();
753         Assert.assertEquals(1, totals.getAvailable());
754         Assert.assertEquals(0, totals.getLeased());
755         Assert.assertEquals(1, totals.getPending());
756     }
757 
758     @Test
759     public void testCreateNewIfExpired() throws Exception {
760         final IOSession iosession1 = Mockito.mock(IOSession.class);
761         Mockito.when(iosession1.isClosed()).thenReturn(Boolean.TRUE);
762         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
763         Mockito.when(sessionRequest1.getAttachment()).thenReturn("somehost");
764         Mockito.when(sessionRequest1.getSession()).thenReturn(iosession1);
765 
766         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
767         Mockito.when(ioreactor.connect(
768                 Matchers.eq(InetSocketAddress.createUnresolved("somehost", 80)),
769                 Matchers.any(SocketAddress.class),
770                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
771                 thenReturn(sessionRequest1);
772 
773         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 2);
774 
775         final Future<LocalPoolEntry> future1 = pool.lease("somehost", null);
776 
777         Mockito.verify(ioreactor, Mockito.times(1)).connect(
778                 Matchers.any(SocketAddress.class), Matchers.any(SocketAddress.class),
779                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
780 
781         pool.requestCompleted(sessionRequest1);
782 
783         Assert.assertTrue(future1.isDone());
784         final LocalPoolEntry entry1 = future1.get();
785         Assert.assertNotNull(entry1);
786 
787         entry1.updateExpiry(1, TimeUnit.MILLISECONDS);
788         pool.release(entry1, true);
789 
790         Thread.sleep(200L);
791 
792         final Future<LocalPoolEntry> future2 = pool.lease("somehost", null);
793 
794         Assert.assertFalse(future2.isDone());
795 
796         Mockito.verify(iosession1).close();
797         Mockito.verify(ioreactor, Mockito.times(2)).connect(
798                 Matchers.any(SocketAddress.class), Matchers.any(SocketAddress.class),
799                 Matchers.any(), Matchers.any(SessionRequestCallback.class));
800 
801         final PoolStats totals = pool.getTotalStats();
802         Assert.assertEquals(0, totals.getAvailable());
803         Assert.assertEquals(0, totals.getLeased());
804         Assert.assertEquals(1, totals.getPending());
805         Assert.assertEquals(Collections.singleton("somehost"), pool.getRoutes());
806         final PoolStats stats = pool.getStats("somehost");
807         Assert.assertEquals(0, stats.getAvailable());
808         Assert.assertEquals(0, stats.getLeased());
809         Assert.assertEquals(1, stats.getPending());
810     }
811 
812     @Test
813     public void testCloseExpired() throws Exception {
814         final IOSession iosession1 = Mockito.mock(IOSession.class);
815         Mockito.when(iosession1.isClosed()).thenReturn(Boolean.TRUE);
816         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
817         Mockito.when(sessionRequest1.getAttachment()).thenReturn("somehost");
818         Mockito.when(sessionRequest1.getSession()).thenReturn(iosession1);
819 
820         final IOSession iosession2 = Mockito.mock(IOSession.class);
821         final SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
822         Mockito.when(sessionRequest2.getAttachment()).thenReturn("somehost");
823         Mockito.when(sessionRequest2.getSession()).thenReturn(iosession2);
824 
825         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
826         Mockito.when(ioreactor.connect(
827                 Matchers.any(SocketAddress.class), Matchers.any(SocketAddress.class),
828                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
829                 thenReturn(sessionRequest1, sessionRequest2);
830 
831         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 2);
832 
833         final Future<LocalPoolEntry> future1 = pool.lease("somehost", null);
834         final Future<LocalPoolEntry> future2 = pool.lease("somehost", null);
835 
836         pool.requestCompleted(sessionRequest1);
837         pool.requestCompleted(sessionRequest2);
838 
839         Assert.assertTrue(future1.isDone());
840         final LocalPoolEntry entry1 = future1.get();
841         Assert.assertNotNull(entry1);
842         Assert.assertTrue(future2.isDone());
843         final LocalPoolEntry entry2 = future2.get();
844         Assert.assertNotNull(entry2);
845 
846         entry1.updateExpiry(1, TimeUnit.MILLISECONDS);
847         pool.release(entry1, true);
848 
849         Thread.sleep(200);
850 
851         entry2.updateExpiry(1000, TimeUnit.SECONDS);
852         pool.release(entry2, true);
853 
854         pool.closeExpired();
855 
856         Mockito.verify(iosession1).close();
857         Mockito.verify(iosession2, Mockito.never()).close();
858 
859         final PoolStats totals = pool.getTotalStats();
860         Assert.assertEquals(1, totals.getAvailable());
861         Assert.assertEquals(0, totals.getLeased());
862         Assert.assertEquals(0, totals.getPending());
863         final PoolStats stats = pool.getStats("somehost");
864         Assert.assertEquals(1, stats.getAvailable());
865         Assert.assertEquals(0, stats.getLeased());
866         Assert.assertEquals(0, stats.getPending());
867     }
868 
869     @Test
870     public void testCloseIdle() throws Exception {
871         final IOSession iosession1 = Mockito.mock(IOSession.class);
872         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
873         Mockito.when(sessionRequest1.getAttachment()).thenReturn("somehost");
874         Mockito.when(sessionRequest1.getSession()).thenReturn(iosession1);
875 
876         final IOSession iosession2 = Mockito.mock(IOSession.class);
877         final SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
878         Mockito.when(sessionRequest2.getAttachment()).thenReturn("somehost");
879         Mockito.when(sessionRequest2.getSession()).thenReturn(iosession2);
880 
881         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
882         Mockito.when(ioreactor.connect(
883                 Matchers.any(SocketAddress.class), Matchers.any(SocketAddress.class),
884                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
885                 thenReturn(sessionRequest1, sessionRequest2);
886 
887         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 2);
888 
889         final Future<LocalPoolEntry> future1 = pool.lease("somehost", null);
890         final Future<LocalPoolEntry> future2 = pool.lease("somehost", null);
891 
892         pool.requestCompleted(sessionRequest1);
893         pool.requestCompleted(sessionRequest2);
894 
895         Assert.assertTrue(future1.isDone());
896         final LocalPoolEntry entry1 = future1.get();
897         Assert.assertNotNull(entry1);
898         Assert.assertTrue(future2.isDone());
899         final LocalPoolEntry entry2 = future2.get();
900         Assert.assertNotNull(entry2);
901 
902         entry1.updateExpiry(0, TimeUnit.MILLISECONDS);
903         pool.release(entry1, true);
904 
905         Thread.sleep(200L);
906 
907         entry2.updateExpiry(0, TimeUnit.MILLISECONDS);
908         pool.release(entry2, true);
909 
910         pool.closeIdle(50, TimeUnit.MILLISECONDS);
911 
912         Mockito.verify(iosession1).close();
913         Mockito.verify(iosession2, Mockito.never()).close();
914 
915         PoolStats totals = pool.getTotalStats();
916         Assert.assertEquals(1, totals.getAvailable());
917         Assert.assertEquals(0, totals.getLeased());
918         Assert.assertEquals(0, totals.getPending());
919         PoolStats stats = pool.getStats("somehost");
920         Assert.assertEquals(1, stats.getAvailable());
921         Assert.assertEquals(0, stats.getLeased());
922         Assert.assertEquals(0, stats.getPending());
923 
924         pool.closeIdle(-1, TimeUnit.MILLISECONDS);
925 
926         Mockito.verify(iosession2).close();
927 
928         totals = pool.getTotalStats();
929         Assert.assertEquals(0, totals.getAvailable());
930         Assert.assertEquals(0, totals.getLeased());
931         Assert.assertEquals(0, totals.getPending());
932         stats = pool.getStats("somehost");
933         Assert.assertEquals(0, stats.getAvailable());
934         Assert.assertEquals(0, stats.getLeased());
935         Assert.assertEquals(0, stats.getPending());
936     }
937 
938     @Test
939     public void testLeaseRequestTimeout() throws Exception {
940         final IOSession iosession1 = Mockito.mock(IOSession.class);
941         Mockito.when(iosession1.isClosed()).thenReturn(Boolean.TRUE);
942         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
943         Mockito.when(sessionRequest1.getAttachment()).thenReturn("somehost");
944         Mockito.when(sessionRequest1.getSession()).thenReturn(iosession1);
945 
946         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
947         Mockito.when(ioreactor.connect(
948                 Matchers.any(SocketAddress.class), Matchers.any(SocketAddress.class),
949                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
950                 thenReturn(sessionRequest1);
951 
952         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 1, 1);
953 
954         final Future<LocalPoolEntry> future1 = pool.lease("somehost", null, 0, TimeUnit.MILLISECONDS, null);
955         final Future<LocalPoolEntry> future2 = pool.lease("somehost", null, 0, TimeUnit.MILLISECONDS, null);
956         final Future<LocalPoolEntry> future3 = pool.lease("somehost", null, 10, TimeUnit.MILLISECONDS, null);
957 
958         pool.requestCompleted(sessionRequest1);
959 
960         Assert.assertTrue(future1.isDone());
961         final LocalPoolEntry entry1 = future1.get();
962         Assert.assertNotNull(entry1);
963         Assert.assertFalse(future2.isDone());
964         Assert.assertFalse(future3.isDone());
965 
966         Thread.sleep(100);
967 
968         pool.validatePendingRequests();
969 
970         Assert.assertFalse(future2.isDone());
971         Assert.assertTrue(future3.isDone());
972     }
973 
974     @Test(expected=IllegalArgumentException.class)
975     public void testCloseIdleInvalid() throws Exception {
976         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
977         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 2);
978         pool.closeIdle(50, null);
979     }
980 
981     @Test(expected=IllegalArgumentException.class)
982     public void testGetStatsInvalid() throws Exception {
983         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
984         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 2);
985         pool.getStats(null);
986     }
987 
988     @Test
989     public void testSetMaxInvalid() throws Exception {
990         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
991         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 2);
992         try {
993             pool.setMaxTotal(-1);
994             Assert.fail("IllegalArgumentException should have been thrown");
995         } catch (final IllegalArgumentException expected) {
996         }
997         try {
998             pool.setMaxPerRoute(null, 1);
999             Assert.fail("IllegalArgumentException should have been thrown");
1000         } catch (final IllegalArgumentException expected) {
1001         }
1002         try {
1003             pool.setDefaultMaxPerRoute(-1);
1004             Assert.fail("IllegalArgumentException should have been thrown");
1005         } catch (final IllegalArgumentException expected) {
1006         }
1007     }
1008 
1009     @Test
1010     public void testSetMaxPerRoute() throws Exception {
1011         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
1012         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 2);
1013         pool.setMaxPerRoute("somehost", 1);
1014         Assert.assertEquals(1, pool.getMaxPerRoute("somehost"));
1015         pool.setMaxPerRoute("somehost", 0);
1016         Assert.assertEquals(0, pool.getMaxPerRoute("somehost"));
1017         pool.setMaxPerRoute("somehost", -1);
1018         Assert.assertEquals(2, pool.getMaxPerRoute("somehost"));
1019     }
1020 
1021     @Test
1022     public void testShutdown() throws Exception {
1023         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
1024         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 2, 2);
1025         pool.shutdown(1000);
1026         Mockito.verify(ioreactor, Mockito.times(1)).shutdown(1000);
1027         pool.shutdown(1000);
1028         Mockito.verify(ioreactor, Mockito.times(1)).shutdown(1000);
1029         try {
1030             pool.lease("somehost", null);
1031             Assert.fail("IllegalStateException should have been thrown");
1032         } catch (final IllegalStateException expected) {
1033         }
1034         // Ignored if shut down
1035         pool.release(new LocalPoolEntry("somehost", Mockito.mock(IOSession.class)), true);
1036         pool.requestCompleted(Mockito.mock(SessionRequest.class));
1037         pool.requestFailed(Mockito.mock(SessionRequest.class));
1038         pool.requestCancelled(Mockito.mock(SessionRequest.class));
1039         pool.requestTimeout(Mockito.mock(SessionRequest.class));
1040     }
1041 
1042     @Test
1043     public void testLeaseRequestCanceled() throws Exception {
1044         final IOSession iosession1 = Mockito.mock(IOSession.class);
1045         Mockito.when(iosession1.isClosed()).thenReturn(Boolean.TRUE);
1046         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
1047         Mockito.when(sessionRequest1.getAttachment()).thenReturn("somehost");
1048         Mockito.when(sessionRequest1.getSession()).thenReturn(iosession1);
1049 
1050         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
1051         Mockito.when(ioreactor.connect(
1052                 Matchers.any(SocketAddress.class), Matchers.any(SocketAddress.class),
1053                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
1054                 thenReturn(sessionRequest1);
1055         Mockito.when(ioreactor.getStatus()).thenReturn(IOReactorStatus.ACTIVE);
1056 
1057         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 1, 1);
1058 
1059         final Future<LocalPoolEntry> future1 = pool.lease("somehost", null, 0, TimeUnit.MILLISECONDS, null);
1060         future1.cancel(true);
1061 
1062         pool.requestCompleted(sessionRequest1);
1063 
1064         Assert.assertTrue(future1.isDone());
1065         try {
1066             future1.get();
1067             Assert.fail("CancellationException expected");
1068         } catch (final CancellationException ignore) {
1069         }
1070 
1071         final PoolStats totals = pool.getTotalStats();
1072         Assert.assertEquals(1, totals.getAvailable());
1073         Assert.assertEquals(0, totals.getLeased());
1074     }
1075 
1076     @Test
1077     public void testLeaseRequestCanceledWhileConnecting() throws Exception {
1078         final IOSession iosession1 = Mockito.mock(IOSession.class);
1079         Mockito.when(iosession1.isClosed()).thenReturn(Boolean.TRUE);
1080         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
1081         Mockito.when(sessionRequest1.getAttachment()).thenReturn("somehost");
1082         Mockito.when(sessionRequest1.getSession()).thenReturn(iosession1);
1083 
1084         final ConnectingIOReactor ioreactor = Mockito.mock(ConnectingIOReactor.class);
1085         Mockito.when(ioreactor.connect(
1086                 Matchers.any(SocketAddress.class), Matchers.any(SocketAddress.class),
1087                 Matchers.any(), Matchers.any(SessionRequestCallback.class))).
1088                 thenReturn(sessionRequest1);
1089         Mockito.when(ioreactor.getStatus()).thenReturn(IOReactorStatus.ACTIVE);
1090 
1091         final LocalSessionPool pool = new LocalSessionPool(ioreactor, 1, 1);
1092 
1093         final Future<LocalPoolEntry> future1 = pool.lease("somehost", null, 0, TimeUnit.MILLISECONDS, null);
1094 
1095         pool.requestCompleted(sessionRequest1);
1096 
1097         Assert.assertTrue(future1.isDone());
1098         final LocalPoolEntry entry1 = future1.get();
1099         Assert.assertNotNull(entry1);
1100 
1101         final Future<LocalPoolEntry> future2 = pool.lease("somehost", null, 0, TimeUnit.MILLISECONDS, null);
1102         future2.cancel(true);
1103 
1104         pool.release(entry1, true);
1105 
1106         final PoolStats totals = pool.getTotalStats();
1107         Assert.assertEquals(1, totals.getAvailable());
1108         Assert.assertEquals(0, totals.getLeased());
1109     }
1110 
1111 }