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