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.testing.sync;
29
30 import java.io.IOException;
31 import java.util.concurrent.TimeoutException;
32
33 import org.apache.hc.client5.http.HttpRoute;
34 import org.apache.hc.client5.http.config.ConnectionConfig;
35 import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
36 import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
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.protocol.HttpClientContext;
40 import org.apache.hc.client5.testing.classic.RandomHandler;
41 import org.apache.hc.client5.testing.sync.extension.TestClientResources;
42 import org.apache.hc.core5.http.ClassicHttpRequest;
43 import org.apache.hc.core5.http.ClassicHttpResponse;
44 import org.apache.hc.core5.http.HttpException;
45 import org.apache.hc.core5.http.HttpHost;
46 import org.apache.hc.core5.http.HttpStatus;
47 import org.apache.hc.core5.http.URIScheme;
48 import org.apache.hc.core5.http.impl.io.HttpRequestExecutor;
49 import org.apache.hc.core5.http.io.HttpClientConnection;
50 import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
51 import org.apache.hc.core5.http.protocol.DefaultHttpProcessor;
52 import org.apache.hc.core5.http.protocol.HttpContext;
53 import org.apache.hc.core5.http.protocol.HttpProcessor;
54 import org.apache.hc.core5.http.protocol.RequestConnControl;
55 import org.apache.hc.core5.http.protocol.RequestContent;
56 import org.apache.hc.core5.http.protocol.RequestTargetHost;
57 import org.apache.hc.core5.pool.PoolConcurrencyPolicy;
58 import org.apache.hc.core5.pool.PoolReusePolicy;
59 import org.apache.hc.core5.testing.classic.ClassicTestServer;
60 import org.apache.hc.core5.util.TimeValue;
61 import org.apache.hc.core5.util.Timeout;
62 import org.junit.jupiter.api.Assertions;
63 import org.junit.jupiter.api.BeforeEach;
64 import org.junit.jupiter.api.Test;
65 import org.junit.jupiter.api.extension.RegisterExtension;
66
67
68
69
70
71 public class TestConnectionManagement {
72
73 public static final Timeout TIMEOUT = Timeout.ofMinutes(1);
74
75 @RegisterExtension
76 private TestClientResources testResources = new TestClientResources(URIScheme.HTTP, TIMEOUT);
77
78 ConnectionEndpoint.RequestExecutor exec;
79
80 @BeforeEach
81 public void setup() {
82 exec = new ConnectionEndpoint.RequestExecutor() {
83
84 final HttpRequestExecutor requestExecutor = new HttpRequestExecutor();
85 final HttpProcessor httpProcessor = new DefaultHttpProcessor(
86 new RequestTargetHost(), new RequestContent(), new RequestConnControl());
87 @Override
88 public ClassicHttpResponse execute(final ClassicHttpRequest request,
89 final HttpClientConnection conn,
90 final HttpContext context) throws IOException, HttpException {
91 requestExecutor.preProcess(request, httpProcessor, context);
92 final ClassicHttpResponse response = requestExecutor.execute(request, conn, context);
93 requestExecutor.postProcess(response, httpProcessor, context);
94 return response;
95 }
96
97 };
98 }
99
100 public ClassicTestServer startServer() throws IOException {
101 return testResources.startServer(null, null, null);
102 }
103
104 public CloseableHttpClient startClient() throws Exception {
105 return testResources.startClient(b -> {}, b -> {});
106 }
107
108 public HttpHost targetHost() {
109 return testResources.targetHost();
110 }
111
112
113
114
115 @Test
116 public void testReleaseConnection() throws Exception {
117 final ClassicTestServer server = startServer();
118 server.registerHandler("/random/*", new RandomHandler());
119 final HttpHost target = targetHost();
120
121 startClient();
122
123 final PoolingHttpClientConnectionManager connManager = testResources.connManager();
124 connManager.setMaxTotal(1);
125
126 final HttpRoute route = new HttpRoute(target, null, false);
127 final int rsplen = 8;
128 final String uri = "/random/" + rsplen;
129
130 final ClassicHttpRequest request = new BasicClassicHttpRequest("GET", target, uri);
131 final HttpClientContext context = HttpClientContext.create();
132
133 final LeaseRequest leaseRequest1 = connManager.lease("id1", route, null);
134 final ConnectionEndpoint endpoint1 = leaseRequest1.get(Timeout.ZERO_MILLISECONDS);
135
136 connManager.connect(endpoint1, null, context);
137
138 try (final ClassicHttpResponse response1 = endpoint1.execute("id1", request, exec, context)) {
139 Assertions.assertEquals(HttpStatus.SC_OK, response1.getCode());
140 }
141
142
143
144 final LeaseRequest leaseRequest2 = connManager.lease("id2", route, null);
145 Assertions.assertThrows(TimeoutException.class, () -> leaseRequest2.get(Timeout.ofMilliseconds(10)));
146
147 endpoint1.close();
148 connManager.release(endpoint1, null, TimeValue.NEG_ONE_MILLISECOND);
149 final LeaseRequest leaseRequest3 = connManager.lease("id2", route, null);
150 final ConnectionEndpoint endpoint2 = leaseRequest3.get(Timeout.ZERO_MILLISECONDS);
151 Assertions.assertFalse(endpoint2.isConnected());
152
153 connManager.connect(endpoint2, null, context);
154
155 try (final ClassicHttpResponse response2 = endpoint2.execute("id2", request, exec, context)) {
156 Assertions.assertEquals(HttpStatus.SC_OK, response2.getCode());
157 }
158
159
160
161 connManager.release(endpoint2, null, TimeValue.NEG_ONE_MILLISECOND);
162
163 final LeaseRequest leaseRequest4 = connManager.lease("id3", route, null);
164 final ConnectionEndpoint endpoint3 = leaseRequest4.get(Timeout.ZERO_MILLISECONDS);
165 Assertions.assertTrue(endpoint3.isConnected());
166
167
168 try (final ClassicHttpResponse response3 = endpoint3.execute("id3", request, exec, context)) {
169 Assertions.assertEquals(HttpStatus.SC_OK, response3.getCode());
170 }
171
172 connManager.release(endpoint3, null, TimeValue.NEG_ONE_MILLISECOND);
173 connManager.close();
174 }
175
176
177
178
179 @Test
180 public void testReleaseConnectionWithTimeLimits() throws Exception {
181 final ClassicTestServer server = startServer();
182 server.registerHandler("/random/*", new RandomHandler());
183 final HttpHost target = targetHost();
184
185 startClient();
186
187 final PoolingHttpClientConnectionManager connManager = testResources.connManager();
188 connManager.setMaxTotal(1);
189
190 final HttpRoute route = new HttpRoute(target, null, false);
191 final int rsplen = 8;
192 final String uri = "/random/" + rsplen;
193
194 final ClassicHttpRequest request = new BasicClassicHttpRequest("GET", target, uri);
195 final HttpClientContext context = HttpClientContext.create();
196
197 final LeaseRequest leaseRequest1 = connManager.lease("id1", route, null);
198 final ConnectionEndpoint endpoint1 = leaseRequest1.get(Timeout.ZERO_MILLISECONDS);
199 connManager.connect(endpoint1, null, context);
200
201 try (final ClassicHttpResponse response1 = endpoint1.execute("id1", request, exec, context)) {
202 Assertions.assertEquals(HttpStatus.SC_OK, response1.getCode());
203 }
204
205
206 final LeaseRequest leaseRequest2 = connManager.lease("id2", route, null);
207
208 Assertions.assertThrows(TimeoutException.class, () -> leaseRequest2.get(Timeout.ofMilliseconds(10)));
209
210 endpoint1.close();
211 connManager.release(endpoint1, null, TimeValue.ofMilliseconds(100));
212
213 final LeaseRequest leaseRequest3 = connManager.lease("id2", route, null);
214 final ConnectionEndpoint endpoint2 = leaseRequest3.get(Timeout.ZERO_MILLISECONDS);
215 Assertions.assertFalse(endpoint2.isConnected());
216
217 connManager.connect(endpoint2, null, context);
218
219 try (final ClassicHttpResponse response2 = endpoint2.execute("id2", request, exec, context)) {
220 Assertions.assertEquals(HttpStatus.SC_OK, response2.getCode());
221 }
222
223 connManager.release(endpoint2, null, TimeValue.ofMilliseconds(100));
224
225 final LeaseRequest leaseRequest4 = connManager.lease("id3", route, null);
226 final ConnectionEndpoint endpoint3 = leaseRequest4.get(Timeout.ZERO_MILLISECONDS);
227 Assertions.assertTrue(endpoint3.isConnected());
228
229
230 try (final ClassicHttpResponse response3 = endpoint3.execute("id3", request, exec, context)) {
231 Assertions.assertEquals(HttpStatus.SC_OK, response3.getCode());
232 }
233
234 connManager.release(endpoint3, null, TimeValue.ofMilliseconds(100));
235 Thread.sleep(150);
236
237 final LeaseRequest leaseRequest5 = connManager.lease("id4", route, null);
238 final ConnectionEndpoint endpoint4 = leaseRequest5.get(Timeout.ZERO_MILLISECONDS);
239 Assertions.assertFalse(endpoint4.isConnected());
240
241
242 connManager.connect(endpoint4, null, context);
243
244 try (final ClassicHttpResponse response4 = endpoint4.execute("id4", request, exec, context)) {
245 Assertions.assertEquals(HttpStatus.SC_OK, response4.getCode());
246 }
247
248 connManager.close();
249 }
250
251 @Test
252 public void testCloseExpiredIdleConnections() throws Exception {
253 startServer();
254 final HttpHost target = targetHost();
255 startClient();
256
257 final PoolingHttpClientConnectionManager connManager = testResources.connManager();
258 connManager.setMaxTotal(1);
259
260 final HttpRoute route = new HttpRoute(target, null, false);
261 final HttpClientContext context = HttpClientContext.create();
262
263 final LeaseRequest leaseRequest1 = connManager.lease("id1", route, null);
264 final ConnectionEndpoint endpoint1 = leaseRequest1.get(Timeout.ZERO_MILLISECONDS);
265 connManager.connect(endpoint1, null, context);
266
267 Assertions.assertEquals(1, connManager.getTotalStats().getLeased());
268 Assertions.assertEquals(1, connManager.getStats(route).getLeased());
269
270 connManager.release(endpoint1, null, TimeValue.ofMilliseconds(100));
271
272
273 Assertions.assertEquals(1, connManager.getTotalStats().getAvailable());
274 Assertions.assertEquals(1, connManager.getStats(route).getAvailable());
275
276 connManager.closeExpired();
277
278
279 Assertions.assertEquals(1, connManager.getTotalStats().getAvailable());
280 Assertions.assertEquals(1, connManager.getStats(route).getAvailable());
281
282 Thread.sleep(150);
283
284 connManager.closeExpired();
285
286
287 Assertions.assertEquals(0, connManager.getTotalStats().getAvailable());
288 Assertions.assertEquals(0, connManager.getStats(route).getAvailable());
289
290 connManager.close();
291 }
292
293 @Test
294 public void testCloseExpiredTTLConnections() throws Exception {
295 final ClassicTestServer server = startServer();
296 server.registerHandler("/random/*", new RandomHandler());
297 final HttpHost target = targetHost();
298
299 testResources.startClient(
300 builder -> builder
301 .setPoolConcurrencyPolicy(PoolConcurrencyPolicy.STRICT)
302 .setConnPoolPolicy(PoolReusePolicy.LIFO)
303 .setDefaultConnectionConfig(ConnectionConfig.custom()
304 .setTimeToLive(TimeValue.ofMilliseconds(100))
305 .build())
306 .setMaxConnTotal(1),
307 builder -> {}
308 );
309
310 final PoolingHttpClientConnectionManager connManager = testResources.connManager();
311 connManager.setMaxTotal(1);
312
313 final HttpRoute route = new HttpRoute(target, null, false);
314 final HttpClientContext context = HttpClientContext.create();
315
316 final LeaseRequest leaseRequest1 = connManager.lease("id1", route, null);
317 final ConnectionEndpoint endpoint1 = leaseRequest1.get(Timeout.ZERO_MILLISECONDS);
318 connManager.connect(endpoint1, null, context);
319
320 Assertions.assertEquals(1, connManager.getTotalStats().getLeased());
321 Assertions.assertEquals(1, connManager.getStats(route).getLeased());
322
323 connManager.release(endpoint1, null, TimeValue.NEG_ONE_MILLISECOND);
324
325
326 Assertions.assertEquals(1, connManager.getTotalStats().getAvailable());
327 Assertions.assertEquals(1, connManager.getStats(route).getAvailable());
328
329 connManager.closeExpired();
330
331
332 Assertions.assertEquals(1, connManager.getTotalStats().getAvailable());
333 Assertions.assertEquals(1, connManager.getStats(route).getAvailable());
334
335 Thread.sleep(150);
336
337 connManager.closeExpired();
338
339
340 Assertions.assertEquals(0, connManager.getTotalStats().getAvailable());
341 Assertions.assertEquals(0, connManager.getStats(route).getAvailable());
342
343 connManager.close();
344 }
345
346 }