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
34 import org.apache.hc.client5.http.DnsResolver;
35 import org.apache.hc.client5.http.HttpRoute;
36 import org.apache.hc.client5.http.SchemePortResolver;
37 import org.apache.hc.client5.http.io.ConnectionEndpoint;
38 import org.apache.hc.client5.http.io.LeaseRequest;
39 import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
40 import org.apache.hc.client5.http.protocol.HttpClientContext;
41 import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
42 import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
43 import org.apache.hc.core5.http.HttpHost;
44 import org.apache.hc.core5.http.config.Lookup;
45 import org.apache.hc.core5.http.io.HttpConnectionFactory;
46 import org.apache.hc.core5.http.io.SocketConfig;
47 import org.apache.hc.core5.http.protocol.HttpContext;
48 import org.apache.hc.core5.io.CloseMode;
49 import org.apache.hc.core5.util.TimeValue;
50 import org.apache.hc.core5.util.Timeout;
51 import org.junit.Assert;
52 import org.junit.Before;
53 import org.junit.Test;
54 import org.mockito.Mock;
55 import org.mockito.Mockito;
56 import org.mockito.MockitoAnnotations;
57
58 @SuppressWarnings({"boxing","static-access"})
59 public class TestBasicHttpClientConnectionManager {
60
61 @Mock
62 private ManagedHttpClientConnection conn;
63 @Mock
64 private HttpConnectionFactory<ManagedHttpClientConnection> connFactory;
65 @Mock
66 private Lookup<ConnectionSocketFactory> socketFactoryRegistry;
67 @Mock
68 private ConnectionSocketFactory plainSocketFactory;
69 @Mock
70 private LayeredConnectionSocketFactory sslSocketFactory;
71 @Mock
72 private Socket socket;
73 @Mock
74 private SchemePortResolver schemePortResolver;
75 @Mock
76 private DnsResolver dnsResolver;
77
78 private BasicHttpClientConnectionManager mgr;
79
80 @Before
81 public void setup() throws Exception {
82 MockitoAnnotations.initMocks(this);
83 mgr = new BasicHttpClientConnectionManager(
84 socketFactoryRegistry, connFactory, schemePortResolver, dnsResolver);
85 }
86
87 @Test
88 public void testLeaseReleaseNonReusable() throws Exception {
89 final HttpHost target = new HttpHost("localhost", 80);
90 final HttpRoute route = new HttpRoute(target);
91
92 Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
93
94 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
95 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ZERO_MILLISECONDS);
96 Assert.assertNotNull(endpoint1);
97 Assert.assertFalse(endpoint1.isConnected());
98
99 mgr.release(endpoint1, null, TimeValue.ofMilliseconds(100));
100
101 Assert.assertNull(mgr.getRoute());
102 Assert.assertNull(mgr.getState());
103
104 final LeaseRequest connRequest2 = mgr.lease("some-id", route, null);
105 final ConnectionEndpoint conn2 = connRequest2.get(Timeout.ZERO_MILLISECONDS);
106 Assert.assertNotNull(conn2);
107 Assert.assertFalse(conn2.isConnected());
108
109 Mockito.verify(connFactory, Mockito.times(2)).createConnection(Mockito.<Socket>any());
110 }
111
112 @Test
113 public void testLeaseReleaseReusable() throws Exception {
114 final HttpHost target = new HttpHost("somehost", 80);
115 final HttpRoute route = new HttpRoute(target);
116
117 Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
118
119 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
120 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ZERO_MILLISECONDS);
121 Assert.assertNotNull(endpoint1);
122
123 Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
124
125 Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
126
127 mgr.release(endpoint1, null, TimeValue.ofMilliseconds(100));
128
129 Assert.assertEquals(route, mgr.getRoute());
130 Assert.assertEquals(null, mgr.getState());
131
132 final LeaseRequest connRequest2 = mgr.lease("some-id", route, null);
133 final ConnectionEndpoint conn2 = connRequest2.get(Timeout.ZERO_MILLISECONDS);
134 Assert.assertNotNull(conn2);
135 Assert.assertTrue(conn2.isConnected());
136
137 Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
138 }
139
140 @Test
141 public void testLeaseReleaseReusableWithState() throws Exception {
142 final HttpHost target = new HttpHost("somehost", 80);
143 final HttpRoute route = new HttpRoute(target);
144
145 Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
146
147 final LeaseRequest connRequest1 = mgr.lease("some-id", route, "some state");
148 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ZERO_MILLISECONDS);
149 Assert.assertNotNull(endpoint1);
150
151 Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
152
153 Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
154
155 mgr.release(endpoint1, "some other state", TimeValue.ofMilliseconds(10000));
156
157 Assert.assertEquals(route, mgr.getRoute());
158 Assert.assertEquals("some other state", mgr.getState());
159
160 final LeaseRequest connRequest2 = mgr.lease("some-id", route, "some other state");
161 final ConnectionEndpoint conn2 = connRequest2.get(Timeout.ZERO_MILLISECONDS);
162 Assert.assertNotNull(conn2);
163 Assert.assertTrue(conn2.isConnected());
164
165 Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
166 }
167
168 @Test
169 public void testLeaseDifferentRoute() throws Exception {
170 final HttpHost target1 = new HttpHost("somehost", 80);
171 final HttpRoute route1 = new HttpRoute(target1);
172
173 Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
174
175 final LeaseRequest connRequest1 = mgr.lease("some-id", route1, null);
176 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ZERO_MILLISECONDS);
177 Assert.assertNotNull(endpoint1);
178
179 Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
180
181 Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
182
183 mgr.release(endpoint1, null, TimeValue.NEG_ONE_MILLISECOND);
184
185 Assert.assertEquals(route1, mgr.getRoute());
186 Assert.assertEquals(null, mgr.getState());
187
188 final HttpHost target2 = new HttpHost("otherhost", 80);
189 final HttpRoute route2 = new HttpRoute(target2);
190 final LeaseRequest connRequest2 = mgr.lease("some-id", route2, null);
191 final ConnectionEndpoint conn2 = connRequest2.get(Timeout.ZERO_MILLISECONDS);
192 Assert.assertNotNull(conn2);
193 Assert.assertFalse(conn2.isConnected());
194
195 Mockito.verify(conn).close(CloseMode.GRACEFUL);
196 Mockito.verify(connFactory, Mockito.times(2)).createConnection(Mockito.<Socket>any());
197 }
198
199 @Test
200 public void testLeaseExpired() throws Exception {
201 final HttpHost target = new HttpHost("somehost", 80);
202 final HttpRoute route = new HttpRoute(target);
203
204 Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
205
206 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
207 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ZERO_MILLISECONDS);
208 Assert.assertNotNull(endpoint1);
209
210 Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
211
212 Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
213
214 mgr.release(endpoint1, null, TimeValue.ofMilliseconds(10));
215
216 Assert.assertEquals(route, mgr.getRoute());
217 Assert.assertEquals(null, mgr.getState());
218
219 Thread.sleep(50);
220
221 final LeaseRequest connRequest2 = mgr.lease("some-id", route, null);
222 final ConnectionEndpoint conn2 = connRequest2.get(Timeout.ZERO_MILLISECONDS);
223 Assert.assertNotNull(conn2);
224 Assert.assertFalse(conn2.isConnected());
225
226 Mockito.verify(conn).close(CloseMode.GRACEFUL);
227 Mockito.verify(connFactory, Mockito.times(2)).createConnection(Mockito.<Socket>any());
228 }
229
230 @Test(expected=NullPointerException.class)
231 public void testReleaseInvalidArg() throws Exception {
232 mgr.release(null, null, TimeValue.NEG_ONE_MILLISECOND);
233 }
234
235 @Test(expected=IllegalStateException.class)
236 public void testReleaseAnotherConnection() throws Exception {
237 final ConnectionEndpoint wrongCon = Mockito.mock(ConnectionEndpoint.class);
238 mgr.release(wrongCon, null, TimeValue.NEG_ONE_MILLISECOND);
239 }
240
241 @Test
242 public void testShutdown() throws Exception {
243 final HttpHost target = new HttpHost("somehost", 80);
244 final HttpRoute route = new HttpRoute(target);
245
246 Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
247
248 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
249 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ZERO_MILLISECONDS);
250 Assert.assertNotNull(endpoint1);
251
252 Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
253
254 Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE);
255
256 mgr.release(endpoint1, null, TimeValue.NEG_ONE_MILLISECOND);
257
258 mgr.close();
259
260 Mockito.verify(conn, Mockito.times(1)).close(CloseMode.GRACEFUL);
261
262 try {
263 final LeaseRequest connRequest2 = mgr.lease("some-id", route, null);
264 connRequest2.get(Timeout.ZERO_MILLISECONDS);
265 Assert.fail("IllegalStateException expected");
266 } catch (final IllegalStateException ex) {
267 }
268
269
270 mgr.closeExpired();
271 mgr.closeIdle(TimeValue.ZERO_MILLISECONDS);
272 mgr.close();
273
274 Mockito.verify(conn, Mockito.times(1)).close(CloseMode.GRACEFUL);
275 }
276
277 @Test
278 public void testCloseExpired() throws Exception {
279 final HttpHost target = new HttpHost("somehost", 80);
280 final HttpRoute route = new HttpRoute(target);
281
282 Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
283
284 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
285 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ZERO_MILLISECONDS);
286 Assert.assertNotNull(endpoint1);
287
288 Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
289
290 Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
291
292 mgr.release(endpoint1, null, TimeValue.ofMilliseconds(10));
293
294 Assert.assertEquals(route, mgr.getRoute());
295 Assert.assertEquals(null, mgr.getState());
296
297 Thread.sleep(50);
298
299 mgr.closeExpired();
300
301 Mockito.verify(conn).close(CloseMode.GRACEFUL);
302 }
303
304 @Test
305 public void testCloseIdle() throws Exception {
306 final HttpHost target = new HttpHost("somehost", 80);
307 final HttpRoute route = new HttpRoute(target);
308
309 Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
310
311 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
312 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ZERO_MILLISECONDS);
313 Assert.assertNotNull(endpoint1);
314
315 Mockito.verify(connFactory, Mockito.times(1)).createConnection(Mockito.<Socket>any());
316
317 Mockito.when(conn.isOpen()).thenReturn(Boolean.TRUE, Boolean.FALSE);
318
319 mgr.release(endpoint1, null, TimeValue.NEG_ONE_MILLISECOND);
320
321 Assert.assertEquals(route, mgr.getRoute());
322 Assert.assertEquals(null, mgr.getState());
323
324 Thread.sleep(100);
325
326 mgr.closeIdle(TimeValue.ofMilliseconds(50));
327
328 Mockito.verify(conn).close(CloseMode.GRACEFUL);
329 }
330
331 @Test(expected=IllegalStateException.class)
332 public void testAlreadyLeased() throws Exception {
333 final HttpHost target = new HttpHost("somehost", 80);
334 final HttpRoute route = new HttpRoute(target);
335
336 Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
337
338 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
339 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ZERO_MILLISECONDS);
340 Assert.assertNotNull(endpoint1);
341 mgr.release(endpoint1, null, TimeValue.ofMilliseconds(100));
342
343 mgr.getConnection(route, null);
344 mgr.getConnection(route, null);
345 }
346
347 @Test
348 public void testTargetConnect() throws Exception {
349 final HttpHost target = new HttpHost("https", "somehost", 443);
350 final InetAddress remote = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
351 final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
352 final HttpRoute route = new HttpRoute(target, local, true);
353
354 Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
355
356 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
357 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ZERO_MILLISECONDS);
358 Assert.assertNotNull(endpoint1);
359
360 final HttpClientContext context = HttpClientContext.create();
361 final SocketConfig sconfig = SocketConfig.custom().build();
362
363 mgr.setSocketConfig(sconfig);
364
365 Mockito.when(dnsResolver.resolve("somehost")).thenReturn(new InetAddress[] {remote});
366 Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
367 Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(plainSocketFactory);
368 Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
369 Mockito.when(plainSocketFactory.connectSocket(
370 Mockito.<TimeValue>any(),
371 Mockito.eq(socket),
372 Mockito.<HttpHost>any(),
373 Mockito.<InetSocketAddress>any(),
374 Mockito.<InetSocketAddress>any(),
375 Mockito.<HttpContext>any())).thenReturn(socket);
376
377 mgr.connect(endpoint1, TimeValue.ofMilliseconds(123), context);
378
379 Mockito.verify(dnsResolver, Mockito.times(1)).resolve("somehost");
380 Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
381 Mockito.verify(plainSocketFactory, Mockito.times(1)).createSocket(context);
382 Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(TimeValue.ofMilliseconds(123), socket, target,
383 new InetSocketAddress(remote, 8443),
384 new InetSocketAddress(local, 0), context);
385 }
386
387 @Test
388 public void testProxyConnectAndUpgrade() throws Exception {
389 final HttpHost target = new HttpHost("https", "somehost", 443);
390 final HttpHost proxy = new HttpHost("someproxy", 8080);
391 final InetAddress remote = InetAddress.getByAddress(new byte[] {10, 0, 0, 1});
392 final InetAddress local = InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
393 final HttpRoute route = new HttpRoute(target, local, proxy, true);
394
395 Mockito.when(connFactory.createConnection(Mockito.<Socket>any())).thenReturn(conn);
396
397 final LeaseRequest connRequest1 = mgr.lease("some-id", route, null);
398 final ConnectionEndpoint endpoint1 = connRequest1.get(Timeout.ZERO_MILLISECONDS);
399 Assert.assertNotNull(endpoint1);
400
401 final HttpClientContext context = HttpClientContext.create();
402 final SocketConfig sconfig = SocketConfig.custom().build();
403
404 mgr.setSocketConfig(sconfig);
405
406 Mockito.when(dnsResolver.resolve("someproxy")).thenReturn(new InetAddress[] {remote});
407 Mockito.when(schemePortResolver.resolve(proxy)).thenReturn(8080);
408 Mockito.when(schemePortResolver.resolve(target)).thenReturn(8443);
409 Mockito.when(socketFactoryRegistry.lookup("http")).thenReturn(plainSocketFactory);
410 Mockito.when(socketFactoryRegistry.lookup("https")).thenReturn(sslSocketFactory);
411 Mockito.when(plainSocketFactory.createSocket(Mockito.<HttpContext>any())).thenReturn(socket);
412 Mockito.when(plainSocketFactory.connectSocket(
413 Mockito.<TimeValue>any(),
414 Mockito.eq(socket),
415 Mockito.<HttpHost>any(),
416 Mockito.<InetSocketAddress>any(),
417 Mockito.<InetSocketAddress>any(),
418 Mockito.<HttpContext>any())).thenReturn(socket);
419
420 mgr.connect(endpoint1, TimeValue.ofMilliseconds(123), context);
421
422 Mockito.verify(dnsResolver, Mockito.times(1)).resolve("someproxy");
423 Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(proxy);
424 Mockito.verify(plainSocketFactory, Mockito.times(1)).createSocket(context);
425 Mockito.verify(plainSocketFactory, Mockito.times(1)).connectSocket(TimeValue.ofMilliseconds(123), socket, proxy,
426 new InetSocketAddress(remote, 8080),
427 new InetSocketAddress(local, 0), context);
428
429 Mockito.when(conn.getSocket()).thenReturn(socket);
430
431 mgr.upgrade(endpoint1, context);
432
433 Mockito.verify(schemePortResolver, Mockito.times(1)).resolve(target);
434 Mockito.verify(sslSocketFactory, Mockito.times(1)).createLayeredSocket(
435 socket, "somehost", 8443, context);
436 }
437
438 }