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