1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.juneau.rest.client;
18
19 import static org.apache.juneau.TestUtils.*;
20 import static org.apache.juneau.http.HttpHeaders.*;
21 import static org.apache.juneau.http.HttpResponses.*;
22 import static org.junit.jupiter.api.Assertions.*;
23
24 import java.io.*;
25 import java.util.concurrent.*;
26 import java.util.concurrent.atomic.*;
27
28 import org.apache.http.*;
29 import org.apache.http.auth.*;
30 import org.apache.http.client.config.*;
31 import org.apache.http.client.methods.*;
32 import org.apache.http.concurrent.*;
33 import org.apache.http.impl.client.*;
34 import org.apache.http.message.*;
35 import org.apache.http.params.*;
36 import org.apache.http.protocol.*;
37 import org.apache.juneau.*;
38 import org.apache.juneau.common.utils.*;
39 import org.apache.juneau.parser.*;
40 import org.apache.juneau.reflect.*;
41 import org.apache.juneau.rest.annotation.*;
42 import org.apache.juneau.rest.mock.*;
43 import org.apache.juneau.rest.servlet.*;
44 import org.junit.jupiter.api.*;
45
46 class RestClient_Test extends TestBase {
47
48 public static class ABean {
49 public int f;
50 static ABean get() {
51 var x = new ABean();
52 x.f = 1;
53 return x;
54 }
55 }
56
57 private static ABean bean = ABean.get();
58
59 @Rest
60 public static class A extends BasicRestObject {
61 @RestGet
62 public ABean bean() {
63 return bean;
64 }
65 @RestGet(path="/echo/*")
66 public String echo(org.apache.juneau.rest.RestRequest req) {
67 return req.toString();
68 }
69 }
70
71
72
73
74
75 public static class A2 extends RestClient.Builder {
76 public A2() {}
77 }
78
79 @Test void a02_basic_useNoArgConstructor() {
80 assertDoesNotThrow(()->new A2().build());
81 }
82
83 @Test void a03_basic_close() throws IOException {
84 RestClient.create().build().close();
85 RestClient.create().build().closeQuietly();
86 RestClient.create().keepHttpClientOpen().build().close();
87 RestClient.create().keepHttpClientOpen().build().closeQuietly();
88 RestClient.create().httpClient(null).keepHttpClientOpen().build().close();
89
90 var es = new ThreadPoolExecutor(1,1,30,TimeUnit.SECONDS,new ArrayBlockingQueue<>(10));
91 RestClient.create().executorService(es,true).build().close();
92 RestClient.create().executorService(es,true).build().closeQuietly();
93 RestClient.create().executorService(es,false).build().close();
94 RestClient.create().executorService(es,false).build().closeQuietly();
95
96 RestClient.create().debug().build().close();
97 assertDoesNotThrow(()->RestClient.create().debug().build().closeQuietly());
98 }
99
100
101 @Test void a04_request_whenClosed() {
102 var rc = client().build();
103 rc.closeQuietly();
104 assertThrowsWithMessage(Exception.class, "RestClient.close() has already been called", ()->rc.request("get","/bean",null));
105 }
106
107 @Test void a05_request_whenClosed_withStackCreation() {
108 var rc = client().debug().build();
109 rc.closeQuietly();
110 assertThrowsWithMessage(Exception.class, "RestClient.close() has already been called", ()->rc.request("get","/bean",null));
111 }
112
113 @Test void a06_request_runCalledTwice() {
114 assertThrowsWithMessage(RestCallException.class, "run() already called.", ()->{RestRequest r = client().build().get("/echo"); r.run(); r.run();});
115 }
116
117
118
119
120
121 public static class B4 extends RestClient {
122 private static boolean CREATE_REQUEST_CALLED, CREATE_RESPONSE_CALLED;
123 public B4(RestClient.Builder b) {
124 super(b);
125 }
126 @Override
127 protected RestRequest createRequest(java.net.URI uri, String method, boolean hasBody) throws RestCallException {
128 CREATE_REQUEST_CALLED = true;
129 return super.createRequest(uri, method, hasBody);
130 }
131 @Override
132 protected RestResponse createResponse(RestRequest req, HttpResponse httpResponse, Parser parser) throws RestCallException {
133 CREATE_RESPONSE_CALLED = true;
134 return super.createResponse(req, httpResponse, parser);
135 }
136 @Override
137 public HttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException {
138 return new BasicHttpResponse(new ProtocolVersion("http",1,1),200,null);
139 }
140 }
141
142 @Test void b04_restClient_overrideCreateRequest() throws Exception {
143 RestClient.create().json5().build(B4.class).get("foo").run();
144 assertTrue(B4.CREATE_REQUEST_CALLED);
145 assertTrue(B4.CREATE_RESPONSE_CALLED);
146 }
147
148
149
150
151
152 public static class C01 implements HttpRequestInterceptor, HttpResponseInterceptor {
153 @Override
154 public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
155 request.setHeader("A1","1");
156 }
157 @Override
158 public void process(HttpResponse response, HttpContext context) throws HttpException,IOException {
159 response.setHeader("B1","1");
160 }
161 }
162
163 @Test void c01_httpClient_interceptors() throws Exception {
164 HttpRequestInterceptor x1 = (request, context) -> request.setHeader("A1","1");
165 HttpResponseInterceptor x2 = (response, context) -> response.setHeader("B1","1");
166 HttpRequestInterceptor x3 = (request, context) -> request.setHeader("A2","2");
167 HttpResponseInterceptor x4 = (response, context) -> response.setHeader("B2","2");
168
169 client().addInterceptorFirst(x1).addInterceptorLast(x2).addInterceptorFirst(x3).addInterceptorLast(x4)
170 .build().get("/echo").run().assertContent().isContains("A1: 1","A2: 2").assertHeader("B1").is("1").assertHeader("B2").is("2");
171 client().interceptors(C01.class).build().get("/echo").run().assertContent().isContains("A1: 1").assertHeader("B1").is("1");
172 client().interceptors(new C01()).build().get("/echo").run().assertContent().isContains("A1: 1").assertHeader("B1").is("1");
173 }
174
175 @Test void c02_httpClient_httpProcessor() throws RestCallException {
176 var x = new HttpProcessor() {
177 @Override
178 public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
179 request.setHeader("A1","1");
180 }
181 @Override
182 public void process(HttpResponse response, HttpContext context) throws HttpException, IOException {
183 response.setHeader("B1","1");
184 }
185 };
186 client().httpProcessor(x).build().get("/echo").run().assertContent().isContains("A1: 1").assertHeader("B1").is("1");
187 }
188
189 @Test void c03_httpClient_requestExecutor() throws RestCallException {
190 var b1 = new AtomicBoolean();
191 var x = new HttpRequestExecutor() {
192 @Override
193 public HttpResponse execute(HttpRequest request, HttpClientConnection conn, HttpContext context) throws HttpException, IOException {
194 b1.set(true);
195 return super.execute(request, conn, context);
196 }
197 };
198 client().requestExecutor(x).build().get("/echo").run().assertContent().isContains("GET /echo HTTP/1.1");
199 assertTrue(b1.get());
200 }
201
202 @Test void c04_httpClient_defaultHeaders() throws RestCallException {
203 client().headersDefault(stringHeader("Foo","bar")).build().get("/echo").run().assertContent().isContains("GET /echo HTTP/1.1","Foo: bar");
204 }
205
206 @Test void c05_httpClient_httpClientBuilderMethods() {
207 assertDoesNotThrow(()->RestClient.create().disableRedirectHandling().redirectStrategy(DefaultRedirectStrategy.INSTANCE).defaultCookieSpecRegistry(null).sslHostnameVerifier(null).publicSuffixMatcher(null).sslContext(null).sslSocketFactory(null).maxConnTotal(10).maxConnPerRoute(10).defaultSocketConfig(null).defaultConnectionConfig(null).connectionTimeToLive(100,TimeUnit.DAYS).connectionManager(null).connectionManagerShared(true).connectionReuseStrategy(null).keepAliveStrategy(null).targetAuthenticationStrategy(null).proxyAuthenticationStrategy(null).userTokenHandler(null).disableConnectionState().schemePortResolver(null).disableCookieManagement().disableContentCompression().disableAuthCaching().retryHandler(null).disableAutomaticRetries().proxy(null).routePlanner(null).connectionBackoffStrategy(null).backoffManager(null).serviceUnavailableRetryStrategy(null).defaultCookieStore(null).defaultCredentialsProvider(null).defaultAuthSchemeRegistry(null).contentDecoderRegistry(null).defaultRequestConfig(null).useSystemProperties().evictExpiredConnections().evictIdleConnections(1,TimeUnit.DAYS));
208 }
209
210 @SuppressWarnings("deprecation")
211 @Test void c06_httpClient_unusedHttpClientMethods() {
212 var x = RestClient.create().build();
213 assertThrows(UnsupportedOperationException.class, x::getParams);
214 assertNotNull(x.getConnectionManager());
215 }
216
217 @Test void c07_httpClient_executeHttpUriRequest() throws Exception {
218 var x = new HttpGet("http://localhost/bean");
219 x.addHeader("Accept","text/json5");
220 var res = MockRestClient.create(A.class).build().execute(x);
221 assertEquals("{f:1}",IOUtils.read(res.getEntity().getContent()));
222 }
223
224 @Test void c08_httpClient_executeHttpHostHttpRequest() throws Exception {
225 var x = new HttpGet("http://localhost/bean");
226 var target = new HttpHost("localhost");
227 x.addHeader("Accept","text/json5");
228 var res = MockRestClient.create(A.class).build().execute(target,x);
229 assertEquals("{f:1}",IOUtils.read(res.getEntity().getContent()));
230 }
231
232 @Test void c09_httpClient_executeHttpHostHttpRequestHttpContext() throws Exception {
233 var x = new HttpGet("http://localhost/bean");
234 var target = new HttpHost("localhost");
235 var context = new BasicHttpContext();
236 x.addHeader("Accept","text/json5");
237 var res = MockRestClient.create(A.class).build().execute(target,x,context);
238 assertEquals("{f:1}",IOUtils.read(res.getEntity().getContent()));
239 }
240
241 @Test void c10_httpClient_executeResponseHandler() throws Exception {
242 var x = new HttpGet("http://localhost/bean");
243 x.addHeader("Accept","text/json5");
244 var res = MockRestClient.create(A.class).build().execute(x,new BasicResponseHandler());
245 assertEquals("{f:1}",res);
246 }
247
248 @Test void c11_httpClient_executeHttpUriRequestResponseHandlerHttpContext() throws Exception {
249 var x = new HttpGet("http://localhost/bean");
250 x.addHeader("Accept","text/json5");
251 var res = MockRestClient.create(A.class).build().execute(x,new BasicResponseHandler(),new BasicHttpContext());
252 assertEquals("{f:1}",res);
253 }
254
255 @Test void c12_httpClient_executeHttpHostHttpRequestResponseHandlerHttpContext() throws Exception {
256 var x = new HttpGet("http://localhost/bean");
257 x.addHeader("Accept","text/json5");
258 var res = MockRestClient.create(A.class).build().execute(new HttpHost("localhost"),x,new BasicResponseHandler(),new BasicHttpContext());
259 assertEquals("{f:1}",res);
260 }
261
262 @Test void c13_httpClient_executeHttpHostHttpRequestResponseHandler() throws Exception {
263 var x = new HttpGet("http://localhost/bean");
264 x.addHeader("Accept","text/json5");
265 var res = MockRestClient.create(A.class).build().execute(new HttpHost("localhost"),x,new BasicResponseHandler());
266 assertEquals("{f:1}",res);
267 }
268
269 @Test void c14_httpClient_requestConfig() throws Exception {
270 var req = client().build().get("/bean").config(RequestConfig.custom().setMaxRedirects(1).build());
271 req.run().assertContent("{f:1}");
272 assertEquals(1, req.getConfig().getMaxRedirects());
273 }
274
275 @Test void c15_httpClient_pooled() throws Exception {
276 var x1 = RestClient.create().json5().pooled().build();
277 var x2 = RestClient.create().json5().build();
278 var x3 = client().pooled().build();
279 assertEquals("PoolingHttpClientConnectionManager",ClassInfo.of(x1.httpClient).getDeclaredField(x -> x.hasName("connManager")).accessible().get(x1.httpClient).getClass().getSimpleName());
280 assertEquals("BasicHttpClientConnectionManager",ClassInfo.of(x2.httpClient).getDeclaredField(x -> x.hasName("connManager")).accessible().get(x2.httpClient).getClass().getSimpleName());
281 assertEquals("MockHttpClientConnectionManager",ClassInfo.of(x3.httpClient).getDeclaredField(x -> x.hasName("connManager")).accessible().get(x3.httpClient).getClass().getSimpleName());
282 }
283
284
285
286
287
288 @Rest
289 public static class D extends BasicRestObject {
290 @RestGet
291 public String echo(@org.apache.juneau.http.annotation.Header("Authorization") String auth, org.apache.juneau.rest.RestResponse res) {
292 if (auth == null) {
293 throw unauthorized().setHeader2("WWW-Authenticate","BASIC realm=\"foo\"");
294 }
295 assertEquals("Basic dXNlcjpwdw==",auth);
296 return "OK";
297 }
298 }
299
300 @Test void d01_basicAuth() throws RestCallException {
301 client(D.class).basicAuth(AuthScope.ANY_HOST,AuthScope.ANY_PORT,"user","pw").build().get("/echo").run().assertContent().isContains("OK");
302 }
303
304
305
306
307
308 @Test void e01_other_completeFuture() throws Exception {
309 client().build().get("/bean").completeFuture().get().assertStatus(200);
310 }
311
312 public static class E2 implements Cancellable {
313 @Override
314 public boolean cancel() {
315 return false;
316 }
317 }
318
319 @Test void e02_httpRequestBase_setCancellable() throws Exception {
320 client().build().get("/bean").cancellable(new E2()).run().assertStatus(200);
321 }
322
323 @Test void e03_httpRequestBase_protocolVersion() throws Exception {
324 client().build().get("/bean").protocolVersion(new ProtocolVersion("http", 2, 0)).run().assertStatus(200);
325 var x = client().build().get("/bean").protocolVersion(new ProtocolVersion("http", 2, 0)).getProtocolVersion();
326 assertEquals(2,x.getMajor());
327 }
328
329 @SuppressWarnings("deprecation")
330 @Test void e04_httpRequestBase_completed() throws Exception {
331 client().build().get("/bean").completed().run().assertStatus(200);
332 }
333
334 @Test void e05_httpUriRequest_abort() throws Exception {
335 var x = client().build().get("/bean");
336 x.abort();
337 assertTrue(x.isAborted());
338 }
339
340 @Test void e06_httpMessage_getRequestLine() throws Exception {
341 var x = client().build().get("/bean");
342 assertEquals("GET",x.getRequestLine().getMethod());
343 }
344
345 @Test void e07_httpMessage_containsHeader() throws Exception {
346 var x = client().build().get("/bean").header("Foo", "bar");
347 assertTrue(x.containsHeader("Foo"));
348 }
349
350 @Test void e08_httpMessage_getFirstHeader_getLastHeader() throws Exception {
351 var x = client().build().get("/bean").header("Foo","bar").header("Foo","baz");
352 assertEquals("bar",x.getFirstHeader("Foo").getValue());
353 assertEquals("baz",x.getLastHeader("Foo").getValue());
354 }
355
356 @Test void e09_httpMessage_addHeader() throws Exception {
357 var x = client().build().get("/bean");
358 x.addHeader(header("Foo","bar"));
359 x.addHeader("Foo","baz");
360 assertEquals("bar",x.getFirstHeader("Foo").getValue());
361 assertEquals("baz",x.getLastHeader("Foo").getValue());
362 }
363
364 @Test void e10_httpMessage_setHeader() throws Exception {
365 var x = client().build().get("/bean");
366 x.setHeader(header("Foo","bar"));
367 x.setHeader(header("Foo","baz"));
368 assertEquals("baz",x.getFirstHeader("Foo").getValue());
369 assertEquals("baz",x.getLastHeader("Foo").getValue());
370 x.setHeader("Foo","qux");
371 assertEquals("qux",x.getFirstHeader("Foo").getValue());
372 assertEquals("qux",x.getLastHeader("Foo").getValue());
373 }
374
375 @Test void e11_httpMessage_setHeaders() throws Exception {
376 var x = client().build().get("/bean");
377 x.setHeaders(new Header[]{header("Foo","bar")});
378 assertEquals("bar",x.getFirstHeader("Foo").getValue());
379 }
380
381 @Test void e12_httpMessage_removeHeaders() throws Exception {
382 var x = client().build().get("/bean");
383 x.setHeaders(new Header[]{header("Foo","bar")});
384 x.removeHeaders("Foo");
385 assertNull(x.getFirstHeader("Foo"));
386 }
387
388 @Test void e13_httpMessage_removeHeader() throws Exception {
389 var x = client().build().get("/bean");
390 x.setHeaders(new Header[]{header("Foo","bar")});
391 x.removeHeader(header("Foo","bar"));
392
393 }
394
395 @Test void e14_httpMessage_headerIterator() throws Exception {
396 var x = client().build().get("/bean");
397 x.setHeaders(new Header[]{header("Foo","bar")});
398 assertEquals("Foo: bar", x.headerIterator().next().toString());
399 assertEquals("Foo: bar", x.headerIterator("Foo").next().toString());
400 }
401
402 @SuppressWarnings("deprecation")
403 @Test void e15_httpMessage_getParams() throws Exception {
404 var p = new BasicHttpParams();
405 var x = client().build().get("/bean");
406 x.setParams(p);
407 assertEquals(p, x.getParams());
408 }
409
410 @Test void e16_toMap() throws Exception {
411 assertNotNull(client().build().toString());
412 assertNotNull(client().build().get("/bean").toString());
413 }
414
415
416
417
418
419 private static RestClient.Builder client() {
420 return MockRestClient.create(A.class).json5();
421 }
422
423 private static RestClient.Builder client(Class<?> c) {
424 return MockRestClient.create(c).noTrace().json5();
425 }
426
427 private static Header header(String name, Object val) {
428 return basicHeader(name, val);
429 }
430 }