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.util.concurrent.ExecutionException;
34  
35  import org.apache.http.concurrent.BasicFuture;
36  import org.apache.http.nio.reactor.IOSession;
37  import org.apache.http.nio.reactor.SessionRequest;
38  import org.apache.http.pool.PoolEntry;
39  import org.junit.Assert;
40  import org.junit.Test;
41  import org.mockito.Mockito;
42  
43  public class TestRouteSpecificPool {
44  
45      static class LocalPoolEntry extends PoolEntry<String, IOSession> {
46  
47          public LocalPoolEntry(final String route, final IOSession conn) {
48              super(null, route, conn);
49          }
50  
51          @Override
52          public void close() {
53              getConnection().close();
54          }
55  
56          @Override
57          public boolean isClosed() {
58              return getConnection().isClosed();
59          }
60  
61      }
62  
63      static class LocalRoutePool extends RouteSpecificPool<String, IOSession, LocalPoolEntry> {
64  
65          public LocalRoutePool() {
66              super("whatever");
67          }
68  
69          @Override
70          protected LocalPoolEntry createEntry(final String route, final IOSession session) {
71              return new LocalPoolEntry(route, session);
72          }
73  
74      }
75  
76      @Test
77      public void testEmptyPool() throws Exception {
78          final LocalRoutePool pool = new LocalRoutePool();
79          Assert.assertEquals(0, pool.getAllocatedCount());
80          Assert.assertEquals(0, pool.getAvailableCount());
81          Assert.assertEquals(0, pool.getLeasedCount());
82          Assert.assertEquals(0, pool.getPendingCount());
83          Assert.assertNull(pool.getLastUsed());
84          Assert.assertEquals("[route: whatever][leased: 0][available: 0][pending: 0]", pool.toString());
85      }
86  
87      @Test
88      public void testSuccessfulConnect() throws Exception {
89          final LocalRoutePool pool = new LocalRoutePool();
90          final IOSession session = Mockito.mock(IOSession.class);
91          final SessionRequest sessionRequest = Mockito.mock(SessionRequest.class);
92          Mockito.when(sessionRequest.getSession()).thenReturn(session);
93          final BasicFuture<LocalPoolEntry> future = new BasicFuture<LocalPoolEntry>(null);
94          pool.addPending(sessionRequest, future);
95          Assert.assertEquals(1, pool.getAllocatedCount());
96          Assert.assertEquals(0, pool.getAvailableCount());
97          Assert.assertEquals(0, pool.getLeasedCount());
98          Assert.assertEquals(1, pool.getPendingCount());
99          final LocalPoolEntry entry = pool.createEntry(sessionRequest, session);
100         Assert.assertNotNull(entry);
101         Assert.assertSame(session, entry.getConnection());
102         Assert.assertFalse(future.isDone());
103         Assert.assertFalse(future.isCancelled());
104         pool.completed(sessionRequest, entry);
105         Assert.assertTrue(future.isDone());
106         Assert.assertFalse(future.isCancelled());
107 
108         Assert.assertEquals(1, pool.getAllocatedCount());
109         Assert.assertEquals(0, pool.getAvailableCount());
110         Assert.assertEquals(1, pool.getLeasedCount());
111         Assert.assertEquals(0, pool.getPendingCount());
112     }
113 
114     @Test
115     public void testFailedConnect() throws Exception {
116         final LocalRoutePool pool = new LocalRoutePool();
117         final SessionRequest sessionRequest = Mockito.mock(SessionRequest.class);
118         final BasicFuture<LocalPoolEntry> future = new BasicFuture<LocalPoolEntry>(null);
119         pool.addPending(sessionRequest, future);
120         Assert.assertEquals(1, pool.getAllocatedCount());
121         Assert.assertEquals(0, pool.getAvailableCount());
122         Assert.assertEquals(0, pool.getLeasedCount());
123         Assert.assertEquals(1, pool.getPendingCount());
124         pool.failed(sessionRequest, new IOException());
125         Assert.assertTrue(future.isDone());
126         Assert.assertFalse(future.isCancelled());
127         try {
128             future.get();
129             Assert.fail("ExecutionException should have been thrown");
130         } catch (final ExecutionException ex) {
131             Assert.assertTrue(ex.getCause() instanceof IOException);
132         }
133         Assert.assertEquals(0, pool.getAllocatedCount());
134         Assert.assertEquals(0, pool.getAvailableCount());
135         Assert.assertEquals(0, pool.getLeasedCount());
136         Assert.assertEquals(0, pool.getPendingCount());
137     }
138 
139     @Test
140     public void testCancelledConnect() throws Exception {
141         final LocalRoutePool pool = new LocalRoutePool();
142         final SessionRequest sessionRequest = Mockito.mock(SessionRequest.class);
143         final BasicFuture<LocalPoolEntry> future = new BasicFuture<LocalPoolEntry>(null);
144         pool.addPending(sessionRequest, future);
145         Assert.assertEquals(1, pool.getAllocatedCount());
146         Assert.assertEquals(0, pool.getAvailableCount());
147         Assert.assertEquals(0, pool.getLeasedCount());
148         Assert.assertEquals(1, pool.getPendingCount());
149         pool.cancelled(sessionRequest);
150         Assert.assertTrue(future.isDone());
151         Assert.assertTrue(future.isCancelled());
152 
153         Assert.assertEquals(0, pool.getAllocatedCount());
154         Assert.assertEquals(0, pool.getAvailableCount());
155         Assert.assertEquals(0, pool.getLeasedCount());
156         Assert.assertEquals(0, pool.getPendingCount());
157     }
158 
159     @Test
160     public void testConnectTimeout() throws Exception {
161         final LocalRoutePool pool = new LocalRoutePool();
162         final SessionRequest sessionRequest = Mockito.mock(SessionRequest.class);
163         Mockito.when(sessionRequest.getRemoteAddress())
164                 .thenReturn(new InetSocketAddress(InetAddress.getByAddress(new byte[]{127, 0, 0, 1}), 80));
165         final BasicFuture<LocalPoolEntry> future = new BasicFuture<LocalPoolEntry>(null);
166         pool.addPending(sessionRequest, future);
167         Assert.assertEquals(1, pool.getAllocatedCount());
168         Assert.assertEquals(0, pool.getAvailableCount());
169         Assert.assertEquals(0, pool.getLeasedCount());
170         Assert.assertEquals(1, pool.getPendingCount());
171         pool.timeout(sessionRequest);
172         Assert.assertTrue(future.isDone());
173         Assert.assertFalse(future.isCancelled());
174         try {
175             future.get();
176             Assert.fail("ExecutionException should have been thrown");
177         } catch (final ExecutionException ex) {
178             Assert.assertTrue(ex.getCause() instanceof ConnectException);
179             Assert.assertEquals("Timeout connecting to [/127.0.0.1:80]", ex.getCause().getMessage());
180         }
181         Assert.assertEquals(0, pool.getAllocatedCount());
182         Assert.assertEquals(0, pool.getAvailableCount());
183         Assert.assertEquals(0, pool.getLeasedCount());
184         Assert.assertEquals(0, pool.getPendingCount());
185     }
186 
187     @Test
188     public void testLeaseRelease() throws Exception {
189         final LocalRoutePool pool = new LocalRoutePool();
190         final IOSession session1 = Mockito.mock(IOSession.class);
191         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
192         Mockito.when(sessionRequest1.getSession()).thenReturn(session1);
193         final BasicFuture<LocalPoolEntry> future1 = new BasicFuture<LocalPoolEntry>(null);
194         pool.addPending(sessionRequest1, future1);
195         final IOSession session2 = Mockito.mock(IOSession.class);
196         final SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
197         Mockito.when(sessionRequest2.getSession()).thenReturn(session2);
198         final BasicFuture<LocalPoolEntry> future2 = new BasicFuture<LocalPoolEntry>(null);
199         pool.addPending(sessionRequest2, future2);
200         final IOSession session3 = Mockito.mock(IOSession.class);
201         final SessionRequest sessionRequest3 = Mockito.mock(SessionRequest.class);
202         Mockito.when(sessionRequest3.getSession()).thenReturn(session3);
203         final BasicFuture<LocalPoolEntry> future3 = new BasicFuture<LocalPoolEntry>(null);
204         pool.addPending(sessionRequest3, future3);
205 
206         Assert.assertEquals(3, pool.getAllocatedCount());
207         Assert.assertEquals(0, pool.getAvailableCount());
208         Assert.assertEquals(0, pool.getLeasedCount());
209         Assert.assertEquals(3, pool.getPendingCount());
210 
211         final LocalPoolEntry entry1 = pool.createEntry(sessionRequest1, session1);
212         pool.completed(sessionRequest1, entry1);
213         Assert.assertNotNull(entry1);
214         final LocalPoolEntry entry2 = pool.createEntry(sessionRequest2, session2);
215         pool.completed(sessionRequest2, entry2);
216         Assert.assertNotNull(entry2);
217         final LocalPoolEntry entry3 = pool.createEntry(sessionRequest3, session3);
218         pool.completed(sessionRequest3, entry3);
219         Assert.assertNotNull(entry3);
220 
221         Assert.assertEquals(3, pool.getAllocatedCount());
222         Assert.assertEquals(0, pool.getAvailableCount());
223         Assert.assertEquals(3, pool.getLeasedCount());
224         Assert.assertEquals(0, pool.getPendingCount());
225 
226         pool.free(entry1, true);
227         pool.free(entry2, false);
228         pool.free(entry3, true);
229 
230         Assert.assertSame(entry1, pool.getLastUsed());
231 
232         Assert.assertEquals(2, pool.getAllocatedCount());
233         Assert.assertEquals(2, pool.getAvailableCount());
234         Assert.assertEquals(0, pool.getLeasedCount());
235         Assert.assertEquals(0, pool.getPendingCount());
236 
237         Assert.assertNotNull(pool.getFree(null));
238         Assert.assertNotNull(pool.getFree(null));
239         Assert.assertNull(pool.getFree(null));
240 
241         Assert.assertEquals(2, pool.getAllocatedCount());
242         Assert.assertEquals(0, pool.getAvailableCount());
243         Assert.assertEquals(2, pool.getLeasedCount());
244         Assert.assertEquals(0, pool.getPendingCount());
245     }
246 
247     @Test
248     public void testLeaseOrder() throws Exception {
249         final LocalRoutePool pool = new LocalRoutePool();
250         final IOSession session1 = Mockito.mock(IOSession.class);
251         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
252         Mockito.when(sessionRequest1.getSession()).thenReturn(session1);
253         final BasicFuture<LocalPoolEntry> future1 = new BasicFuture<LocalPoolEntry>(null);
254         pool.addPending(sessionRequest1, future1);
255         final IOSession session2 = Mockito.mock(IOSession.class);
256         final SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
257         Mockito.when(sessionRequest2.getSession()).thenReturn(session2);
258         final BasicFuture<LocalPoolEntry> future2 = new BasicFuture<LocalPoolEntry>(null);
259         pool.addPending(sessionRequest2, future2);
260         final IOSession session3 = Mockito.mock(IOSession.class);
261         final SessionRequest sessionRequest3 = Mockito.mock(SessionRequest.class);
262         Mockito.when(sessionRequest3.getSession()).thenReturn(session3);
263         final BasicFuture<LocalPoolEntry> future3 = new BasicFuture<LocalPoolEntry>(null);
264         pool.addPending(sessionRequest3, future3);
265 
266         Assert.assertEquals(3, pool.getAllocatedCount());
267         Assert.assertEquals(0, pool.getAvailableCount());
268         Assert.assertEquals(0, pool.getLeasedCount());
269         Assert.assertEquals(3, pool.getPendingCount());
270 
271         final LocalPoolEntry entry1 = pool.createEntry(sessionRequest1, session1);
272         pool.completed(sessionRequest1, entry1);
273         Assert.assertNotNull(entry1);
274         final LocalPoolEntry entry2 = pool.createEntry(sessionRequest2, session2);
275         pool.completed(sessionRequest2, entry2);
276         Assert.assertNotNull(entry2);
277         final LocalPoolEntry entry3 = pool.createEntry(sessionRequest3, session3);
278         pool.completed(sessionRequest3, entry3);
279         Assert.assertNotNull(entry3);
280 
281         Assert.assertEquals(3, pool.getAllocatedCount());
282         Assert.assertEquals(0, pool.getAvailableCount());
283         Assert.assertEquals(3, pool.getLeasedCount());
284         Assert.assertEquals(0, pool.getPendingCount());
285 
286         pool.free(entry1, true);
287         pool.free(entry2, true);
288         pool.free(entry3, true);
289 
290         Assert.assertSame(entry1, pool.getLastUsed());
291 
292         Assert.assertSame(entry3, pool.getFree(null));
293         Assert.assertSame(entry2, pool.getFree(null));
294         Assert.assertSame(entry1, pool.getFree(null));
295     }
296 
297     @Test
298     public void testLeaseReleaseStateful() throws Exception {
299         final LocalRoutePool pool = new LocalRoutePool();
300 
301         final IOSession session1 = Mockito.mock(IOSession.class);
302         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
303         Mockito.when(sessionRequest1.getSession()).thenReturn(session1);
304         final BasicFuture<LocalPoolEntry> future1 = new BasicFuture<LocalPoolEntry>(null);
305         pool.addPending(sessionRequest1, future1);
306         final IOSession session2 = Mockito.mock(IOSession.class);
307         final SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
308         Mockito.when(sessionRequest2.getSession()).thenReturn(session2);
309         final BasicFuture<LocalPoolEntry> future2 = new BasicFuture<LocalPoolEntry>(null);
310         pool.addPending(sessionRequest2, future2);
311         final IOSession session3 = Mockito.mock(IOSession.class);
312         final SessionRequest sessionRequest3 = Mockito.mock(SessionRequest.class);
313         Mockito.when(sessionRequest3.getSession()).thenReturn(session3);
314         final BasicFuture<LocalPoolEntry> future3 = new BasicFuture<LocalPoolEntry>(null);
315         pool.addPending(sessionRequest3, future3);
316 
317         final LocalPoolEntry entry1 = pool.createEntry(sessionRequest1, session1);
318         pool.completed(sessionRequest1, entry1);
319         Assert.assertNotNull(entry1);
320         final LocalPoolEntry entry2 = pool.createEntry(sessionRequest2, session2);
321         pool.completed(sessionRequest2, entry2);
322         Assert.assertNotNull(entry2);
323         final LocalPoolEntry entry3 = pool.createEntry(sessionRequest3, session3);
324         pool.completed(sessionRequest3, entry3);
325         Assert.assertNotNull(entry3);
326 
327         entry2.setState(Boolean.FALSE);
328         pool.free(entry1, true);
329         pool.free(entry2, true);
330         pool.free(entry3, true);
331 
332         Assert.assertSame(entry2, pool.getFree(Boolean.FALSE));
333         Assert.assertSame(entry3, pool.getFree(Boolean.FALSE));
334         Assert.assertSame(entry1, pool.getFree(null));
335         Assert.assertSame(null, pool.getFree(null));
336 
337         entry1.setState(Boolean.TRUE);
338         entry2.setState(Boolean.FALSE);
339         entry3.setState(Boolean.TRUE);
340         pool.free(entry1, true);
341         pool.free(entry2, true);
342         pool.free(entry3, true);
343 
344         Assert.assertSame(null, pool.getFree(null));
345         Assert.assertSame(entry2, pool.getFree(Boolean.FALSE));
346         Assert.assertSame(null, pool.getFree(Boolean.FALSE));
347         Assert.assertSame(entry3, pool.getFree(Boolean.TRUE));
348         Assert.assertSame(entry1, pool.getFree(Boolean.TRUE));
349         Assert.assertSame(null, pool.getFree(Boolean.TRUE));
350     }
351 
352     @Test(expected=IllegalStateException.class)
353     public void testReleaseInvalidEntry() throws Exception {
354         final LocalRoutePool pool = new LocalRoutePool();
355         final IOSession session = Mockito.mock(IOSession.class);
356         final LocalPoolEntry entry = new LocalPoolEntry("whatever", session);
357         pool.free(entry, true);
358     }
359 
360     @Test
361     public void testRemove() throws Exception {
362         final LocalRoutePool pool = new LocalRoutePool();
363         final IOSession session1 = Mockito.mock(IOSession.class);
364         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
365         Mockito.when(sessionRequest1.getSession()).thenReturn(session1);
366         final BasicFuture<LocalPoolEntry> future1 = new BasicFuture<LocalPoolEntry>(null);
367         pool.addPending(sessionRequest1, future1);
368         final IOSession session2 = Mockito.mock(IOSession.class);
369         final SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
370         Mockito.when(sessionRequest2.getSession()).thenReturn(session2);
371         final BasicFuture<LocalPoolEntry> future2 = new BasicFuture<LocalPoolEntry>(null);
372         pool.addPending(sessionRequest2, future2);
373         final IOSession session3 = Mockito.mock(IOSession.class);
374         final SessionRequest sessionRequest3 = Mockito.mock(SessionRequest.class);
375         Mockito.when(sessionRequest3.getSession()).thenReturn(session3);
376         final BasicFuture<LocalPoolEntry> future3 = new BasicFuture<LocalPoolEntry>(null);
377         pool.addPending(sessionRequest3, future3);
378 
379         Assert.assertEquals(3, pool.getAllocatedCount());
380         Assert.assertEquals(0, pool.getAvailableCount());
381         Assert.assertEquals(0, pool.getLeasedCount());
382         Assert.assertEquals(3, pool.getPendingCount());
383 
384         final LocalPoolEntry entry1 = pool.createEntry(sessionRequest1, session1);
385         pool.completed(sessionRequest1, entry1);
386         Assert.assertNotNull(entry1);
387         final LocalPoolEntry entry2 = pool.createEntry(sessionRequest2, session2);
388         pool.completed(sessionRequest2, entry2);
389         Assert.assertNotNull(entry2);
390         final LocalPoolEntry entry3 = pool.createEntry(sessionRequest3, session3);
391         pool.completed(sessionRequest3, entry3);
392         Assert.assertNotNull(entry3);
393 
394         Assert.assertEquals(3, pool.getAllocatedCount());
395         Assert.assertEquals(0, pool.getAvailableCount());
396         Assert.assertEquals(3, pool.getLeasedCount());
397         Assert.assertEquals(0, pool.getPendingCount());
398 
399         Assert.assertTrue(pool.remove(entry2));
400         Assert.assertFalse(pool.remove(entry2));
401 
402         Assert.assertEquals(2, pool.getAllocatedCount());
403         Assert.assertEquals(0, pool.getAvailableCount());
404         Assert.assertEquals(2, pool.getLeasedCount());
405         Assert.assertEquals(0, pool.getPendingCount());
406 
407         pool.free(entry1, true);
408         pool.free(entry3, true);
409 
410         Assert.assertEquals(2, pool.getAllocatedCount());
411         Assert.assertEquals(2, pool.getAvailableCount());
412         Assert.assertEquals(0, pool.getLeasedCount());
413         Assert.assertEquals(0, pool.getPendingCount());
414 
415         Assert.assertTrue(pool.remove(entry1));
416         Assert.assertTrue(pool.remove(entry3));
417 
418         Assert.assertEquals(0, pool.getAllocatedCount());
419         Assert.assertEquals(0, pool.getAvailableCount());
420         Assert.assertEquals(0, pool.getLeasedCount());
421         Assert.assertEquals(0, pool.getPendingCount());
422     }
423 
424     @Test(expected=IllegalArgumentException.class)
425     public void testReleaseInvalid() throws Exception {
426         final LocalRoutePool pool = new LocalRoutePool();
427         pool.free(null, true);
428     }
429 
430     @Test(expected=IllegalArgumentException.class)
431     public void testRemoveInvalid() throws Exception {
432         final LocalRoutePool pool = new LocalRoutePool();
433         pool.remove(null);
434     }
435 
436     @Test
437     public void testShutdown() throws Exception {
438         final LocalRoutePool pool = new LocalRoutePool();
439         final IOSession session1 = Mockito.mock(IOSession.class);
440         final SessionRequest sessionRequest1 = Mockito.mock(SessionRequest.class);
441         Mockito.when(sessionRequest1.getSession()).thenReturn(session1);
442         final BasicFuture<LocalPoolEntry> future1 = new BasicFuture<LocalPoolEntry>(null);
443         pool.addPending(sessionRequest1, future1);
444         final IOSession session2 = Mockito.mock(IOSession.class);
445         final SessionRequest sessionRequest2 = Mockito.mock(SessionRequest.class);
446         Mockito.when(sessionRequest2.getSession()).thenReturn(session2);
447         final BasicFuture<LocalPoolEntry> future2 = new BasicFuture<LocalPoolEntry>(null);
448         pool.addPending(sessionRequest2, future2);
449         final IOSession session3 = Mockito.mock(IOSession.class);
450         final SessionRequest sessionRequest3 = Mockito.mock(SessionRequest.class);
451         Mockito.when(sessionRequest3.getSession()).thenReturn(session3);
452         final BasicFuture<LocalPoolEntry> future3 = new BasicFuture<LocalPoolEntry>(null);
453         pool.addPending(sessionRequest3, future3);
454 
455         final LocalPoolEntry entry1 = pool.createEntry(sessionRequest1, session1);
456         pool.completed(sessionRequest1, entry1);
457         Assert.assertNotNull(entry1);
458         final LocalPoolEntry entry2 = pool.createEntry(sessionRequest2, session2);
459         pool.completed(sessionRequest2, entry2);
460         Assert.assertNotNull(entry2);
461 
462         pool.free(entry1, true);
463 
464         Assert.assertEquals(3, pool.getAllocatedCount());
465         Assert.assertEquals(1, pool.getAvailableCount());
466         Assert.assertEquals(1, pool.getLeasedCount());
467         Assert.assertEquals(1, pool.getPendingCount());
468 
469         pool.shutdown();
470 
471         Assert.assertEquals(0, pool.getAllocatedCount());
472         Assert.assertEquals(0, pool.getAvailableCount());
473         Assert.assertEquals(0, pool.getLeasedCount());
474         Assert.assertEquals(0, pool.getPendingCount());
475 
476         Mockito.verify(sessionRequest3).cancel();
477         Mockito.verify(session2).close();
478         Mockito.verify(session1).close();
479     }
480 
481 }