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 package org.apache.hc.client5.http.impl.classic;
28
29 import java.io.ByteArrayInputStream;
30 import java.io.IOException;
31 import java.io.InterruptedIOException;
32
33 import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
34 import org.apache.hc.client5.http.HttpRoute;
35 import org.apache.hc.client5.http.UserTokenHandler;
36 import org.apache.hc.client5.http.classic.ExecChain;
37 import org.apache.hc.client5.http.classic.ExecRuntime;
38 import org.apache.hc.client5.http.classic.methods.HttpGet;
39 import org.apache.hc.client5.http.entity.EntityBuilder;
40 import org.apache.hc.client5.http.impl.ConnectionShutdownException;
41 import org.apache.hc.client5.http.io.HttpClientConnectionManager;
42 import org.apache.hc.client5.http.protocol.HttpClientContext;
43 import org.apache.hc.core5.http.ClassicHttpRequest;
44 import org.apache.hc.core5.http.ClassicHttpResponse;
45 import org.apache.hc.core5.http.ConnectionReuseStrategy;
46 import org.apache.hc.core5.http.HttpEntity;
47 import org.apache.hc.core5.http.HttpException;
48 import org.apache.hc.core5.http.HttpHost;
49 import org.apache.hc.core5.http.message.BasicClassicHttpResponse;
50 import org.apache.hc.core5.http.protocol.HttpProcessor;
51 import org.apache.hc.core5.util.TimeValue;
52 import org.junit.jupiter.api.Assertions;
53 import org.junit.jupiter.api.BeforeEach;
54 import org.junit.jupiter.api.Test;
55 import org.mockito.Mock;
56 import org.mockito.Mockito;
57 import org.mockito.MockitoAnnotations;
58
59 class TestMainClientExec {
60
61 @Mock
62 private HttpClientConnectionManager connectionManager;
63 @Mock
64 private HttpProcessor httpProcessor;
65 @Mock
66 private ConnectionReuseStrategy reuseStrategy;
67 @Mock
68 private ConnectionKeepAliveStrategy keepAliveStrategy;
69 @Mock
70 private UserTokenHandler userTokenHandler;
71 @Mock
72 private ExecRuntime execRuntime;
73
74 private MainClientExec mainClientExec;
75 private HttpHost target;
76
77 @BeforeEach
78 void setup() {
79 MockitoAnnotations.openMocks(this);
80 mainClientExec = new MainClientExec(connectionManager, httpProcessor, reuseStrategy, keepAliveStrategy, userTokenHandler);
81 target = new HttpHost("foo", 80);
82 }
83
84 @Test
85 void testFundamentals() throws Exception {
86 final HttpRoute route = new HttpRoute(target);
87 final ClassicHttpRequest request = new HttpGet("/test");
88 final HttpClientContext context = HttpClientContext.create();
89
90 final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
91 final HttpEntity responseEntity = EntityBuilder.create()
92 .setStream(new ByteArrayInputStream(new byte[]{}))
93 .build();
94 response.setEntity(responseEntity);
95
96 Mockito.when(execRuntime.execute(
97 Mockito.anyString(),
98 Mockito.same(request),
99 Mockito.any(),
100 Mockito.any())).thenReturn(response);
101
102 final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
103 mainClientExec.execute(request, scope, null);
104
105 Mockito.verify(httpProcessor).process(request, null, context);
106 Mockito.verify(execRuntime).execute(Mockito.eq("test"), Mockito.same(request), Mockito.any(), Mockito.any());
107 Mockito.verify(httpProcessor).process(response, responseEntity, context);
108
109 Assertions.assertEquals(route, context.getHttpRoute());
110 Assertions.assertSame(request, context.getRequest());
111 Assertions.assertSame(response, context.getResponse());
112 }
113
114 @Test
115 void testExecRequestNonPersistentConnection() throws Exception {
116 final HttpRoute route = new HttpRoute(target);
117 final HttpClientContext context = HttpClientContext.create();
118 final ClassicHttpRequest request = new HttpGet("http://bar/test");
119 final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
120 response.setEntity(EntityBuilder.create()
121 .setStream(new ByteArrayInputStream(new byte[]{}))
122 .build());
123
124 Mockito.when(execRuntime.execute(
125 Mockito.anyString(),
126 Mockito.same(request),
127 Mockito.any(),
128 Mockito.any())).thenReturn(response);
129 Mockito.when(reuseStrategy.keepAlive(
130 Mockito.same(request),
131 Mockito.same(response),
132 Mockito.<HttpClientContext>any())).thenReturn(false);
133
134 final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
135 final ClassicHttpResponse finalResponse = mainClientExec.execute(request, scope, null);
136 Mockito.verify(execRuntime).execute(Mockito.eq("test"), Mockito.same(request), Mockito.any(), Mockito.any());
137 Mockito.verify(execRuntime, Mockito.times(1)).markConnectionNonReusable();
138 Mockito.verify(execRuntime, Mockito.never()).releaseEndpoint();
139
140 Assertions.assertNull(context.getUserToken());
141 Assertions.assertNotNull(finalResponse);
142 Assertions.assertTrue(finalResponse instanceof CloseableHttpResponse);
143 }
144
145 @Test
146 void testExecRequestNonPersistentConnectionNoResponseEntity() throws Exception {
147 final HttpRoute route = new HttpRoute(target);
148 final HttpClientContext context = HttpClientContext.create();
149 final ClassicHttpRequest request = new HttpGet("http://bar/test");
150 final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
151 response.setEntity(null);
152
153 Mockito.when(execRuntime.execute(
154 Mockito.anyString(),
155 Mockito.same(request),
156 Mockito.any(),
157 Mockito.any())).thenReturn(response);
158 Mockito.when(reuseStrategy.keepAlive(
159 Mockito.same(request),
160 Mockito.same(response),
161 Mockito.<HttpClientContext>any())).thenReturn(false);
162
163 final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
164 final ClassicHttpResponse finalResponse = mainClientExec.execute(request, scope, null);
165
166 Mockito.verify(execRuntime).execute(Mockito.eq("test"), Mockito.same(request), Mockito.any(), Mockito.any());
167 Mockito.verify(execRuntime).markConnectionNonReusable();
168 Mockito.verify(execRuntime).releaseEndpoint();
169
170 Assertions.assertNotNull(finalResponse);
171 Assertions.assertTrue(finalResponse instanceof CloseableHttpResponse);
172 }
173
174 @Test
175 void testExecRequestPersistentConnection() throws Exception {
176 final HttpRoute route = new HttpRoute(target);
177 final HttpClientContext context = HttpClientContext.create();
178 final ClassicHttpRequest request = new HttpGet("http://bar/test");
179 final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
180
181 response.setEntity(EntityBuilder.create()
182 .setStream(new ByteArrayInputStream(new byte[]{}))
183 .build());
184
185
186 Mockito.when(execRuntime.execute(
187 Mockito.anyString(),
188 Mockito.same(request),
189 Mockito.any(),
190 Mockito.any())).thenReturn(response);
191 Mockito.when(reuseStrategy.keepAlive(
192 Mockito.same(request),
193 Mockito.same(response),
194 Mockito.<HttpClientContext>any())).thenReturn(true);
195 Mockito.when(keepAliveStrategy.getKeepAliveDuration(
196 Mockito.same(response),
197 Mockito.<HttpClientContext>any())).thenReturn(TimeValue.ofMilliseconds(678L));
198
199 final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
200 final ClassicHttpResponse finalResponse = mainClientExec.execute(request, scope, null);
201
202 Mockito.verify(execRuntime).execute(Mockito.eq("test"), Mockito.same(request), Mockito.any(), Mockito.any());
203 Mockito.verify(execRuntime).markConnectionReusable(null, TimeValue.ofMilliseconds(678L));
204 Mockito.verify(execRuntime, Mockito.never()).releaseEndpoint();
205
206 Assertions.assertNotNull(finalResponse);
207 Assertions.assertTrue(finalResponse instanceof CloseableHttpResponse);
208 }
209
210 @Test
211 void testExecRequestPersistentConnectionNoResponseEntity() throws Exception {
212 final HttpRoute route = new HttpRoute(target);
213 final HttpClientContext context = HttpClientContext.create();
214 final ClassicHttpRequest request = new HttpGet("http://bar/test");
215 final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
216
217 Mockito.when(execRuntime.execute(
218 Mockito.anyString(),
219 Mockito.same(request),
220 Mockito.any(),
221 Mockito.any())).thenReturn(response);
222 Mockito.when(reuseStrategy.keepAlive(
223 Mockito.same(request),
224 Mockito.same(response),
225 Mockito.<HttpClientContext>any())).thenReturn(true);
226 Mockito.when(keepAliveStrategy.getKeepAliveDuration(
227 Mockito.same(response),
228 Mockito.<HttpClientContext>any())).thenReturn(TimeValue.ofMilliseconds(678L));
229
230 final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
231 final ClassicHttpResponse finalResponse = mainClientExec.execute(request, scope, null);
232
233 Mockito.verify(execRuntime).execute(Mockito.eq("test"), Mockito.same(request), Mockito.any(), Mockito.any());
234 Mockito.verify(execRuntime).releaseEndpoint();
235
236 Assertions.assertNotNull(finalResponse);
237 Assertions.assertTrue(finalResponse instanceof CloseableHttpResponse);
238 }
239
240 @Test
241 void testExecRequestConnectionRelease() throws Exception {
242 final HttpRoute route = new HttpRoute(target);
243 final HttpClientContext context = HttpClientContext.create();
244 final ClassicHttpRequest request = new HttpGet("http://bar/test");
245 final ClassicHttpResponse response = new BasicClassicHttpResponse(200, "OK");
246
247 response.setEntity(EntityBuilder.create()
248 .setStream(new ByteArrayInputStream(new byte[]{}))
249 .build());
250
251 Mockito.when(execRuntime.execute(
252 Mockito.anyString(),
253 Mockito.same(request),
254 Mockito.any(),
255 Mockito.any())).thenReturn(response);
256 Mockito.when(reuseStrategy.keepAlive(
257 Mockito.same(request),
258 Mockito.same(response),
259 Mockito.<HttpClientContext>any())).thenReturn(Boolean.FALSE);
260
261 final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
262 final ClassicHttpResponse finalResponse = mainClientExec.execute(request, scope, null);
263 Mockito.verify(execRuntime, Mockito.times(1)).execute(Mockito.eq("test"), Mockito.same(request), Mockito.any(), Mockito.any());
264 Mockito.verify(execRuntime, Mockito.never()).disconnectEndpoint();
265 Mockito.verify(execRuntime, Mockito.never()).releaseEndpoint();
266
267 Assertions.assertNotNull(finalResponse);
268 Assertions.assertTrue(finalResponse instanceof CloseableHttpResponse);
269 finalResponse.close();
270
271 Mockito.verify(execRuntime).disconnectEndpoint();
272 Mockito.verify(execRuntime).discardEndpoint();
273 }
274
275 @Test
276 void testExecConnectionShutDown() throws Exception {
277 final HttpRoute route = new HttpRoute(target);
278 final HttpClientContext context = HttpClientContext.create();
279 final ClassicHttpRequest request = new HttpGet("http://bar/test");
280
281 Mockito.when(execRuntime.execute(
282 Mockito.anyString(),
283 Mockito.same(request),
284 Mockito.any(),
285 Mockito.any())).thenThrow(new ConnectionShutdownException());
286
287 final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
288 Assertions.assertThrows(InterruptedIOException.class, () ->
289 mainClientExec.execute(request, scope, null));
290 Mockito.verify(execRuntime).discardEndpoint();
291 }
292
293 @Test
294 void testExecRuntimeException() throws Exception {
295 final HttpRoute route = new HttpRoute(target);
296 final HttpClientContext context = HttpClientContext.create();
297 final ClassicHttpRequest request = new HttpGet("http://bar/test");
298
299 Mockito.when(execRuntime.execute(
300 Mockito.anyString(),
301 Mockito.same(request),
302 Mockito.any(),
303 Mockito.any())).thenThrow(new RuntimeException("Ka-boom"));
304
305 final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
306 Assertions.assertThrows(RuntimeException.class, () ->
307 mainClientExec.execute(request, scope, null));
308 Mockito.verify(execRuntime).discardEndpoint();
309 }
310
311 @Test
312 void testExecHttpException() throws Exception {
313 final HttpRoute route = new HttpRoute(target);
314 final HttpClientContext context = HttpClientContext.create();
315 final ClassicHttpRequest request = new HttpGet("http://bar/test");
316
317 Mockito.when(execRuntime.execute(
318 Mockito.anyString(),
319 Mockito.same(request),
320 Mockito.any(),
321 Mockito.any())).thenThrow(new HttpException("Ka-boom"));
322
323 final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
324 Assertions.assertThrows(HttpException.class, () ->
325 mainClientExec.execute(request, scope, null));
326 Mockito.verify(execRuntime).discardEndpoint();
327 }
328
329 @Test
330 void testExecIOException() throws Exception {
331 final HttpRoute route = new HttpRoute(target);
332 final HttpClientContext context = HttpClientContext.create();
333 final ClassicHttpRequest request = new HttpGet("http://bar/test");
334
335 Mockito.when(execRuntime.execute(
336 Mockito.anyString(),
337 Mockito.same(request),
338 Mockito.any(),
339 Mockito.any())).thenThrow(new IOException("Ka-boom"));
340
341 final ExecChain.Scope scope = new ExecChain.Scope("test", route, request, execRuntime, context);
342 Assertions.assertThrows(IOException.class, () ->
343 mainClientExec.execute(request, scope, null));
344 Mockito.verify(execRuntime).discardEndpoint();
345 }
346
347 }