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  
28  package org.apache.http.impl.conn;
29  
30  import java.net.InetAddress;
31  import java.net.InetSocketAddress;
32  import java.net.Socket;
33  import java.util.concurrent.ExecutionException;
34  import java.util.concurrent.Future;
35  import java.util.concurrent.TimeUnit;
36  import java.util.concurrent.TimeoutException;
37  
38  import org.apache.commons.logging.LogFactory;
39  import org.apache.http.HttpClientConnection;
40  import org.apache.http.HttpHost;
41  import org.apache.http.client.protocol.HttpClientContext;
42  import org.apache.http.config.ConnectionConfig;
43  import org.apache.http.config.Lookup;
44  import org.apache.http.config.SocketConfig;
45  import org.apache.http.conn.ConnectionPoolTimeoutException;
46  import org.apache.http.conn.ConnectionRequest;
47  import org.apache.http.conn.DnsResolver;
48  import org.apache.http.conn.SchemePortResolver;
49  import org.apache.http.conn.ManagedHttpClientConnection;
50  import org.apache.http.conn.routing.HttpRoute;
51  import org.apache.http.conn.socket.ConnectionSocketFactory;
52  import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
53  import org.apache.http.protocol.HttpContext;
54  import org.junit.Assert;
55  import org.junit.Before;
56  import org.junit.Test;
57  import org.mockito.Mock;
58  import org.mockito.Mockito;
59  import org.mockito.MockitoAnnotations;
60  
61  /**
62   * {@link PoolingHttpClientConnectionManager} tests.
63   */
64  @SuppressWarnings({"boxing","static-access","resource"}) // test code
65  public class TestPoolingHttpClientConnectionManager {
66  
67      @Mock
68      private ManagedHttpClientConnection conn;
69      @Mock
70      private Lookup<ConnectionSocketFactory> socketFactoryRegistry;
71      @Mock
72      private ConnectionSocketFactory plainSocketFactory;
73      @Mock
74      private ConnectionSocketFactory sslSocketFactory;
75      @Mock
76      private Socket socket;
77      @Mock
78      private SchemePortResolver schemePortResolver;
79      @Mock
80      private DnsResolver dnsResolver;
81      @Mock
82      private Future<CPoolEntry> future;
83      @Mock
84      private CPool pool;
85      private PoolingHttpClientConnectionManager mgr;
86  
87      @Before
88      public void setup() throws Exception {
89          MockitoAnnotations.initMocks(this);
90          mgr = new PoolingHttpClientConnectionManager(
91                  pool, socketFactoryRegistry, schemePortResolver, dnsResolver);
92      }
93  
94      @Test
95      public void testLeaseRelease() throws Exception {
96          final HttpHost target = new HttpHost("localhost", 80);
97          final HttpRoute route = new HttpRoute(target);
98  
99          final CPoolEntry entry = new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
100                 -1, TimeUnit.MILLISECONDS);
101         entry.markRouteComplete();
102 
103         Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
104         Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
105         Mockito.when(schemePortResolver.resolve(target)).thenReturn(80);
106         Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
107 
108         Mockito.when(conn.isOpen()).thenReturn(true);
109         Mockito.when(future.isCancelled()).thenReturn(false);
110         Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
111         Mockito.when(pool.lease(route, null, null)).thenReturn(future);
112 
113         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
114         final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
115         Assert.assertNotNull(conn1);
116         Assert.assertNotSame(conn, conn1);
117 
118         mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
119 
120         Mockito.verify(pool).release(entry, true);
121     }
122 
123     @Test
124     public void testReleaseRouteIncomplete() throws Exception {
125         final HttpHost target = new HttpHost("localhost", 80);
126         final HttpRoute route = new HttpRoute(target);
127 
128         final CPoolEntry entry = new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
129                 -1, TimeUnit.MILLISECONDS);
130 
131         Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
132         Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
133         Mockito.when(schemePortResolver.resolve(target)).thenReturn(80);
134         Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
135 
136         Mockito.when(conn.isOpen()).thenReturn(true);
137         Mockito.when(future.isCancelled()).thenReturn(false);
138         Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
139         Mockito.when(pool.lease(route, null, null)).thenReturn(future);
140 
141         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
142         final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
143         Assert.assertNotNull(conn1);
144         Assert.assertNotSame(conn, conn1);
145 
146         mgr.releaseConnection(conn1, null, 0, TimeUnit.MILLISECONDS);
147 
148         Mockito.verify(pool).release(entry, false);
149     }
150 
151     @Test(expected= ExecutionException.class)
152     public void testLeaseFutureCancelled() throws Exception {
153         final HttpHost target = new HttpHost("localhost", 80);
154         final HttpRoute route = new HttpRoute(target);
155 
156         final CPoolEntry entry = new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
157                 -1, TimeUnit.MILLISECONDS);
158         entry.markRouteComplete();
159 
160         Mockito.when(future.isCancelled()).thenReturn(Boolean.TRUE);
161         Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
162         Mockito.when(pool.lease(route, null, null)).thenReturn(future);
163 
164         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
165         connRequest1.get(1, TimeUnit.SECONDS);
166     }
167 
168     @Test(expected=ConnectionPoolTimeoutException.class)
169     public void testLeaseFutureTimeout() throws Exception {
170         final HttpHost target = new HttpHost("localhost", 80);
171         final HttpRoute route = new HttpRoute(target);
172 
173         Mockito.when(future.isCancelled()).thenReturn(Boolean.TRUE);
174         Mockito.when(future.get(1, TimeUnit.SECONDS)).thenThrow(new TimeoutException());
175         Mockito.when(pool.lease(route, null, null)).thenReturn(future);
176 
177         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
178         connRequest1.get(1, TimeUnit.SECONDS);
179     }
180 
181     @Test
182     public void testReleaseReusable() throws Exception {
183         final HttpHost target = new HttpHost("localhost", 80);
184         final HttpRoute route = new HttpRoute(target);
185 
186         final CPoolEntry entry = Mockito.spy(new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
187                 -1, TimeUnit.MILLISECONDS));
188         entry.markRouteComplete();
189 
190         Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
191         Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
192         Mockito.when(pool.lease(route, null, null)).thenReturn(future);
193         Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
194 
195         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
196         final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
197         Assert.assertNotNull(conn1);
198         Assert.assertTrue(conn1.isOpen());
199 
200         mgr.releaseConnection(conn1, "some state", 0, TimeUnit.MILLISECONDS);
201 
202         Mockito.verify(pool).release(entry, true);
203         Mockito.verify(entry).setState("some state");
204         Mockito.verify(entry).updateExpiry(Mockito.anyLong(), Mockito.eq(TimeUnit.MILLISECONDS));
205     }
206 
207     @Test
208     public void testReleaseNonReusable() throws Exception {
209         final HttpHost target = new HttpHost("localhost", 80);
210         final HttpRoute route = new HttpRoute(target);
211 
212         final CPoolEntry entry = Mockito.spy(new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
213                 -1, TimeUnit.MILLISECONDS));
214         entry.markRouteComplete();
215 
216         Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
217         Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
218         Mockito.when(pool.lease(route, null, null)).thenReturn(future);
219         Mockito.when(conn.isOpen()).thenReturn(Boolean.FALSE);
220 
221         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
222         final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
223         Assert.assertNotNull(conn1);
224         Assert.assertFalse(conn1.isOpen());
225 
226         mgr.releaseConnection(conn1, "some state", 0, TimeUnit.MILLISECONDS);
227 
228         Mockito.verify(pool).release(entry, false);
229         Mockito.verify(entry, Mockito.never()).setState(Mockito.anyObject());
230         Mockito.verify(entry, Mockito.never()).updateExpiry(Mockito.anyLong(), Mockito.eq(TimeUnit.MILLISECONDS));
231     }
232 
233     @Test
234     public void testTargetConnect() throws Exception {
235         final HttpHost target = new HttpHost("somehost", 443, "https");
236         final InetAddress remote = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
237         final InetAddress local = InetAddress.getByAddress(new byte[]{127, 0, 0, 1});
238         final HttpRoute route = new HttpRoute(target, local, true);
239 
240         final CPoolEntry entry = new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
241                 -1, TimeUnit.MILLISECONDS);
242         entry.markRouteComplete();
243         Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
244         Mockito.when(conn.isOpen()).thenReturn(true);
245         Mockito.when(future.isCancelled()).thenReturn(false);
246         Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
247         Mockito.when(pool.lease(route, null, null)).thenReturn(future);
248 
249         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
250         final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
251         Assert.assertNotNull(conn1);
252 
253         final HttpClientContext context = HttpClientContext.create();
254         final SocketConfig sconfig = SocketConfig.custom().build();
255 
256         mgr.setDefaultSocketConfig(sconfig);
257 
258         Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[]{remote});
259         Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
260         Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(plainSocketFactory);
261         Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
262         Mockito.when(plainSocketFactory.connectSocket(
263                 Mockito.anyInt(),
264                 Mockito.eq(socket),
265                 Mockito.<HttpHost>any(),
266                 Mockito.<InetSocketAddress>any(),
267                 Mockito.<InetSocketAddress>any(),
268                 Mockito.<HttpContext>any())).thenReturn(socket);
269 
270         mgr.connect(conn1, route, 123, context);
271 
272         Mockito.verify(dnsResolver, Mockito.times(1)).resolve("somehost");
273         Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
274         Mockito.verify(plainSocketFactory, Mockito.times(1)).createSocket(context);
275         Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(123, socket, target,
276                 new InetSocketAddress(remote, 8443),
277                 new InetSocketAddress(local, 0), context);
278 
279         mgr.routeComplete(conn1, route, context);
280     }
281 
282     @Test
283     public void testProxyConnectAndUpgrade() throws Exception {
284         final HttpHost target = new HttpHost("somehost", 443, "https");
285         final HttpHost proxy = new HttpHost("someproxy", 8080);
286         final InetAddress remote = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
287         final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
288         final HttpRoute route = new HttpRoute(target, local, proxy, true);
289 
290         final CPoolEntry entry = new CPoolEntry(LogFactory.getLog(getClass()), "id", route, conn,
291                 -1, TimeUnit.MILLISECONDS);
292         entry.markRouteComplete();
293         Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
294         Mockito.when(conn.isOpen()).thenReturn(true);
295         Mockito.when(future.isCancelled()).thenReturn(false);
296         Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
297         Mockito.when(pool.lease(route, null, null)).thenReturn(future);
298 
299         final ConnectionRequest connRequest1 = mgr.requestConnection(route, null);
300         final HttpClientConnection conn1 = connRequest1.get(1, TimeUnit.SECONDS);
301         Assert.assertNotNull(conn1);
302 
303         final ConnectionSocketFactory plainsf = Mockito.mock(ConnectionSocketFactory.class);
304         final LayeredConnectionSocketFactory sslsf = Mockito.mock(LayeredConnectionSocketFactory.class);
305         final Socket mockSock = Mockito.mock(Socket.class);
306         final HttpClientContext context = HttpClientContext.create();
307         final SocketConfig sconfig = SocketConfig.custom().build();
308         final ConnectionConfig cconfig = ConnectionConfig.custom().build();
309 
310         mgr.setDefaultSocketConfig(sconfig);
311         mgr.setDefaultConnectionConfig(cconfig);
312 
313         Mockito.when(dnsResolver.resolve("someproxy")).thenReturn(new InetAddress[] {remote});
314         Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8080);
315         Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
316         Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainsf);
317         Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslsf);
318         Mockito.when(plainsf.createSocket(Mockito.<HttpContext>any())).thenReturn(mockSock);
319         Mockito.when(plainsf.connectSocket(
320                 Mockito.anyInt(),
321                 Mockito.eq(mockSock),
322                 Mockito.<HttpHost>any(),
323                 Mockito.<InetSocketAddress>any(),
324                 Mockito.<InetSocketAddress>any(),
325                 Mockito.<HttpContext>any())).thenReturn(mockSock);
326 
327         mgr.connect(conn1, route, 123, context);
328 
329         Mockito.verify(dnsResolver, Mockito.times(1)).resolve("someproxy");
330         Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
331         Mockito.verify(plainsf, Mockito.times(1)).createSocket(context);
332         Mockito.verify(plainsf, Mockito.times(1)).connectSocket(123, mockSock, proxy,
333                 new InetSocketAddress(remote, 8080),
334                 new InetSocketAddress(local, 0), context);
335 
336         Mockito.when(conn.getSocket()).thenReturn(mockSock);
337 
338         mgr.upgrade(conn1, route, context);
339 
340         Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
341         Mockito.verify(sslsf, Mockito.times(1)).createLayeredSocket(
342                 mockSock, "somehost", 8443, context);
343 
344         mgr.routeComplete(conn1, route, context);
345     }
346 
347 }