1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.client5.http.impl.io;
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.hc.client5.http.DnsResolver;
39 import org.apache.hc.client5.http.HttpRoute;
40 import org.apache.hc.client5.http.SchemePortResolver;
41 import org.apache.hc.client5.http.io.ConnectionEndpoint;
42 import org.apache.hc.client5.http.io.LeaseRequest;
43 import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
44 import org.apache.hc.client5.http.protocol.HttpClientContext;
45 import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
46 import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
47 import org.apache.hc.core5.concurrent.FutureCallback;
48 import org.apache.hc.core5.http.HttpHost;
49 import org.apache.hc.core5.http.config.Lookup;
50 import org.apache.hc.core5.http.io.SocketConfig;
51 import org.apache.hc.core5.http.protocol.HttpContext;
52 import org.apache.hc.core5.pool.PoolEntry;
53 import org.apache.hc.core5.pool.StrictConnPool;
54 import org.apache.hc.core5.util.TimeValue;
55 import org.apache.hc.core5.util.Timeout;
56 import org.junit.Assert;
57 import org.junit.Before;
58 import org.junit.Test;
59 import org.mockito.Mock;
60 import org.mockito.Mockito;
61 import org.mockito.MockitoAnnotations;
62
63
64
65
66 @SuppressWarnings({"boxing","static-access","resource"})
67 public class TestPoolingHttpClientConnectionManager {
68
69 @Mock
70 private ManagedHttpClientConnection conn;
71 @Mock
72 private Lookup<ConnectionSocketFactory> socketFactoryRegistry;
73 @Mock
74 private ConnectionSocketFactory plainSocketFactory;
75 @Mock
76 private ConnectionSocketFactory sslSocketFactory;
77 @Mock
78 private Socket socket;
79 @Mock
80 private SchemePortResolver schemePortResolver;
81 @Mock
82 private DnsResolver dnsResolver;
83 @Mock
84 private Future<PoolEntry<HttpRoute, ManagedHttpClientConnection>> future;
85 @Mock
86 private StrictConnPool<HttpRoute, ManagedHttpClientConnection> pool;
87 private PoolingHttpClientConnectionManager mgr;
88
89 @Before
90 public void setup() throws Exception {
91 MockitoAnnotations.initMocks(this);
92 mgr = new PoolingHttpClientConnectionManager(
93 new DefaultHttpClientConnectionOperator(socketFactoryRegistry, schemePortResolver, dnsResolver), pool, null);
94 }
95
96 @Test
97 public void testLeaseRelease() throws Exception {
98 final HttpHost target = new HttpHost("localhost", 80);
99 final HttpRoute route = new HttpRoute(target);
100
101 final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = new PoolEntry<>(route, TimeValue.NEG_ONE_MILLISECOND);
102 entry.assignConnection(conn);
103
104 Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
105 Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
106 Mockito.when(schemePortResolver.resolve(target)).thenReturn(80);
107 Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
108
109 Mockito.when(conn.isOpen()).thenReturn(true);
110 Mockito.when(conn.isConsistent()).thenReturn(true);
111 Mockito.when(future.isCancelled()).thenReturn(false);
112 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
113 Mockito.when(pool.lease(
114 Mockito.eq(route),
115 Mockito.eq(null),
116 Mockito.<Timeout>any(),
117 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
118 .thenReturn(future);
119
120 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
121 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ofSeconds(1));
122 Assert.assertNotNull(endpoint1);
123 Assert.assertNotSame(conn, endpoint1);
124
125 mgr.release(endpoint1, null, TimeValue.NEG_ONE_MILLISECOND);
126
127 Mockito.verify(pool).release(entry, true);
128 }
129
130 @Test
131 public void testReleaseRouteIncomplete() throws Exception {
132 final HttpHost target = new HttpHost("localhost", 80);
133 final HttpRoute route = new HttpRoute(target);
134
135 final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = new PoolEntry<>(route, TimeValue.NEG_ONE_MILLISECOND);
136
137 Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
138 Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
139 Mockito.when(schemePortResolver.resolve(target)).thenReturn(80);
140 Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
141
142 Mockito.when(conn.isOpen()).thenReturn(true);
143 Mockito.when(future.isCancelled()).thenReturn(false);
144 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
145 Mockito.when(pool.lease(
146 Mockito.eq(route),
147 Mockito.eq(null),
148 Mockito.<Timeout>any(),
149 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
150 .thenReturn(future);
151
152 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
153 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ofSeconds(1));
154 Assert.assertNotNull(endpoint1);
155 Assert.assertNotSame(conn, endpoint1);
156
157 mgr.release(endpoint1, null, TimeValue.NEG_ONE_MILLISECOND);
158
159 Mockito.verify(pool).release(entry, false);
160 }
161
162 @Test(expected= ExecutionException.class)
163 public void testLeaseFutureCancelled() throws Exception {
164 final HttpHost target = new HttpHost("localhost", 80);
165 final HttpRoute route = new HttpRoute(target);
166
167 final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = new PoolEntry<>(route, TimeValue.NEG_ONE_MILLISECOND);
168 entry.assignConnection(conn);
169
170 Mockito.when(future.isCancelled()).thenReturn(Boolean.TRUE);
171 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
172 Mockito.when(pool.lease(
173 Mockito.eq(route),
174 Mockito.eq(null),
175 Mockito.<Timeout>any(),
176 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
177 .thenReturn(future);
178
179 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
180 connRequest1.get(Timeout.ofSeconds(1));
181 }
182
183 @Test(expected=TimeoutException.class)
184 public void testLeaseFutureTimeout() throws Exception {
185 final HttpHost target = new HttpHost("localhost", 80);
186 final HttpRoute route = new HttpRoute(target);
187
188 Mockito.when(future.isCancelled()).thenReturn(Boolean.TRUE);
189 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenThrow(new TimeoutException());
190 Mockito.when(pool.lease(
191 Mockito.eq(route),
192 Mockito.eq(null),
193 Mockito.<Timeout>any(),
194 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
195 .thenReturn(future);
196
197 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
198 connRequest1.get(Timeout.ofSeconds(1));
199 }
200
201 @Test
202 public void testReleaseReusable() throws Exception {
203 final HttpHost target = new HttpHost("localhost", 80);
204 final HttpRoute route = new HttpRoute(target);
205
206 final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = new PoolEntry<>(route, TimeValue.NEG_ONE_MILLISECOND);
207 entry.assignConnection(conn);
208
209 Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
210 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
211 Mockito.when(pool.lease(
212 Mockito.eq(route),
213 Mockito.eq(null),
214 Mockito.<Timeout>any(),
215 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
216 .thenReturn(future);
217 Mockito.when(conn.isOpen()).thenReturn(true);
218 Mockito.when(conn.isConsistent()).thenReturn(true);
219
220 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
221 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ofSeconds(1));
222 Assert.assertNotNull(endpoint1);
223 Assert.assertTrue(endpoint1.isConnected());
224
225 mgr.release(endpoint1, "some state", TimeValue.NEG_ONE_MILLISECOND);
226
227 Mockito.verify(pool).release(entry, true);
228 Assert.assertEquals("some state", entry.getState());
229 }
230
231 @Test
232 public void testReleaseNonReusable() throws Exception {
233 final HttpHost target = new HttpHost("localhost", 80);
234 final HttpRoute route = new HttpRoute(target);
235
236 final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = new PoolEntry<>(route, TimeValue.NEG_ONE_MILLISECOND);
237 entry.assignConnection(conn);
238
239 Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
240 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
241 Mockito.when(pool.lease(
242 Mockito.eq(route),
243 Mockito.eq(null),
244 Mockito.<Timeout>any(),
245 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
246 .thenReturn(future);
247 Mockito.when(conn.isOpen()).thenReturn(Boolean.FALSE);
248
249 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
250 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ofSeconds(1));
251 Assert.assertNotNull(endpoint1);
252 Assert.assertFalse(endpoint1.isConnected());
253
254 mgr.release(endpoint1, "some state", TimeValue.NEG_ONE_MILLISECOND);
255
256 Mockito.verify(pool).release(entry, false);
257 Assert.assertEquals(null, entry.getState());
258 }
259
260 @Test
261 public void testTargetConnect() throws Exception {
262 final HttpHost target = new HttpHost("https", "somehost", 443);
263 final InetAddress remote = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
264 final InetAddress local = InetAddress.getByAddress(new byte[]{127, 0, 0, 1});
265 final HttpRoute route = new HttpRoute(target, local, true);
266
267 final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = new PoolEntry<>(route, TimeValue.NEG_ONE_MILLISECOND);
268 entry.assignConnection(conn);
269
270 Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
271 Mockito.when(conn.isOpen()).thenReturn(false);
272 Mockito.when(future.isCancelled()).thenReturn(false);
273 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
274 Mockito.when(pool.lease(
275 Mockito.eq(route),
276 Mockito.eq(null),
277 Mockito.<Timeout>any(),
278 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
279 .thenReturn(future);
280
281 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
282 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ofSeconds(1));
283 Assert.assertNotNull(endpoint1);
284
285 final HttpClientContext context = HttpClientContext.create();
286 final SocketConfig sconfig = SocketConfig.custom().build();
287
288 mgr.setDefaultSocketConfig(sconfig);
289
290 Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[]{remote});
291 Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
292 Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(plainSocketFactory);
293 Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
294 Mockito.when(plainSocketFactory.connectSocket(
295 Mockito.<TimeValue>any(),
296 Mockito.eq(socket),
297 Mockito.<HttpHost>any(),
298 Mockito.<InetSocketAddress>any(),
299 Mockito.<InetSocketAddress>any(),
300 Mockito.<HttpContext>any())).thenReturn(socket);
301
302 mgr.connect(endpoint1, TimeValue.ofMilliseconds(123), context);
303
304 Mockito.verify(dnsResolver, Mockito.times(1)).resolve("somehost");
305 Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
306 Mockito.verify(plainSocketFactory, Mockito.times(1)).createSocket(context);
307 Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(TimeValue.ofMilliseconds(123), socket, target,
308 new InetSocketAddress(remote, 8443),
309 new InetSocketAddress(local, 0), context);
310 }
311
312 @Test
313 public void testProxyConnectAndUpgrade() throws Exception {
314 final HttpHost target = new HttpHost("https", "somehost", 443);
315 final HttpHost proxy = new HttpHost("someproxy", 8080);
316 final InetAddress remote = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
317 final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
318 final HttpRoute route = new HttpRoute(target, local, proxy, true);
319
320 final PoolEntry<HttpRoute, ManagedHttpClientConnection> entry = new PoolEntry<>(route, TimeValue.NEG_ONE_MILLISECOND);
321 entry.assignConnection(conn);
322
323 Mockito.when(future.isCancelled()).thenReturn(Boolean.FALSE);
324 Mockito.when(conn.isOpen()).thenReturn(false);
325 Mockito.when(future.isCancelled()).thenReturn(false);
326 Mockito.when(future.get(1, TimeUnit.SECONDS)).thenReturn(entry);
327 Mockito.when(pool.lease(
328 Mockito.eq(route),
329 Mockito.eq(null),
330 Mockito.<Timeout>any(),
331 Mockito.<FutureCallback<PoolEntry<HttpRoute, ManagedHttpClientConnection>>>eq(null)))
332 .thenReturn(future);
333
334 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
335 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ofSeconds(1));
336 Assert.assertNotNull(endpoint1);
337
338 final ConnectionSocketFactory plainsf = Mockito.mock(ConnectionSocketFactory.class);
339 final LayeredConnectionSocketFactory sslsf = Mockito.mock(LayeredConnectionSocketFactory.class);
340 final Socket mockSock = Mockito.mock(Socket.class);
341 final HttpClientContext context = HttpClientContext.create();
342 final SocketConfig sconfig = SocketConfig.custom().build();
343
344 mgr.setDefaultSocketConfig(sconfig);
345
346 Mockito.when(dnsResolver.resolve("someproxy")).thenReturn(new InetAddress[] {remote});
347 Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8080);
348 Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
349 Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainsf);
350 Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslsf);
351 Mockito.when(plainsf.createSocket(Mockito.<HttpContext>any())).thenReturn(mockSock);
352 Mockito.when(plainsf.connectSocket(
353 Mockito.<TimeValue>any(),
354 Mockito.eq(mockSock),
355 Mockito.<HttpHost>any(),
356 Mockito.<InetSocketAddress>any(),
357 Mockito.<InetSocketAddress>any(),
358 Mockito.<HttpContext>any())).thenReturn(mockSock);
359
360 mgr.connect(endpoint1, TimeValue.ofMilliseconds(123), context);
361
362 Mockito.verify(dnsResolver, Mockito.times(1)).resolve("someproxy");
363 Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
364 Mockito.verify(plainsf, Mockito.times(1)).createSocket(context);
365 Mockito.verify(plainsf, Mockito.times(1)).connectSocket(TimeValue.ofMilliseconds(123), mockSock, proxy,
366 new InetSocketAddress(remote, 8080),
367 new InetSocketAddress(local, 0), context);
368
369 Mockito.when(conn.isOpen()).thenReturn(true);
370 Mockito.when(conn.getSocket()).thenReturn(mockSock);
371
372 mgr.upgrade(endpoint1, context);
373
374 Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
375 Mockito.verify(sslsf, Mockito.times(1)).createLayeredSocket(
376 mockSock, "somehost", 8443, context);
377 }
378
379 }