View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.juneau.rest.client;
18  
19  import static org.apache.juneau.TestUtils.*;
20  import static org.apache.juneau.commons.utils.CollectionUtils.*;
21  import static org.apache.juneau.http.HttpEntities.*;
22  import static org.apache.juneau.http.HttpParts.*;
23  import static org.apache.juneau.http.HttpResources.*;
24  import static org.apache.juneau.http.header.ContentType.*;
25  
26  import java.io.*;
27  import java.util.function.*;
28  
29  import org.apache.http.*;
30  import org.apache.http.client.utils.*;
31  import org.apache.juneau.*;
32  import org.apache.juneau.http.annotation.*;
33  import org.apache.juneau.http.header.*;
34  import org.apache.juneau.http.part.*;
35  import org.apache.juneau.marshaller.*;
36  import org.apache.juneau.rest.annotation.*;
37  import org.apache.juneau.rest.httppart.*;
38  import org.apache.juneau.rest.mock.*;
39  import org.apache.juneau.rest.servlet.*;
40  import org.apache.juneau.utest.utils.*;
41  import org.junit.jupiter.api.*;
42  
43  class RestClient_BasicCalls_Test extends TestBase {
44  
45  	public static class ABean {
46  		public int f;
47  		static ABean get() {
48  			var x = new ABean();
49  			x.f = 1;
50  			return x;
51  		}
52  		@Override
53  		public String toString() {
54  			return Json5.of(this);
55  		}
56  	}
57  
58  	private static ABean bean = ABean.get();
59  
60  	@Rest
61  	public static class A extends BasicRestObject {
62  		@RestOp(path="/bean") public ABean getBean() { return bean; }
63  		@RestOp(path="/bean") public ABean postBean(@Content ABean b) { return b; }
64  		@RestOp(path="/bean") public ABean putBean(@Content ABean b) { return b; }
65  		@RestOp(path="/bean") public ABean patchBean(@Content ABean b) { return b; }
66  		@RestOp(path="/bean") public ABean deleteBean() { return bean; }
67  		@RestOp(path="/bean") public ABean optionsBean() { return bean; }
68  		@RestOp(path="/bean") public ABean headBean() { return bean; }
69  		@RestOp(path="/checkHeader") public String[] postHeader(org.apache.juneau.rest.RestRequest req) { return req.getHeaders().getAll(req.getHeaderParam("Check").orElse(null)).stream().map(RequestHeader::getValue).toArray(String[]::new); }
70  		@RestOp(path="/",method="*") public Reader echoMethod(@Method String method) { return reader(method); }
71  	}
72  
73  	@Test void a01_basic() throws Exception {
74  		var x = client().build();
75  		x.get().run().assertContent("GET");
76  		x.get("/").run().assertContent("GET");
77  		x.get("").run().assertContent("GET");
78  		x.put("/",null).run().assertContent("PUT");
79  		x.post("/",null).run().assertContent("POST");
80  		x.delete("/").run().assertContent("DELETE");
81  		x.formPost("/").run().assertContent("POST");
82  	}
83  
84  	@Test void a02_get() throws Exception {
85  		client().build().get("/bean").run().assertContent("{f:1}");
86  
87  		assertThrowsWithMessage(Exception.class, "Method does not support content entity.", ()->client().build().get("/bean").content(bean).run());
88  	}
89  
90  	@Test void a03_get_exhaustiveUrls() throws Exception {
91  		var urls = l(
92  			new URIBuilder("http://localhost/bean"),
93  			java.net.URI.create("http://localhost/bean"),
94  			url("http://localhost/bean"),
95  			"/bean",
96  			new StringBuilder("/bean")
97  		);
98  		var x = client().build();
99  		for (var url : urls) {
100 			x.get(url).run().assertContent("{f:1}");
101 		}
102 	}
103 
104 	@Test void a04_put() throws Exception {
105 		client().build().put("/bean",bean).run().assertContent("{f:1}");
106 		client().build().put("/bean").content(bean).run().assertContent("{f:1}");
107 		client().build().put("/bean",MutableSupplier.of(bean)).run().assertContent("{f:1}");
108 		client().build().put("/bean").content(MutableSupplier.of(bean)).run().assertContent("{f:1}");
109 	}
110 
111 	@Test void a05_put_bodyString() throws Exception {
112 		client().build().put("/bean","{f:1}",APPLICATION_JSON).run().assertContent("{f:1}");
113 		client().build().put("/bean").contentString("{f:1}").json5().run().assertContent("{f:1}");
114 		client().build().put("/bean").contentString("").json5().run().assertContent("{f:0}");
115 		client().build().put("/bean").contentString(null).json5().run().assertContent("null");
116  	}
117 
118 	@Test void a06_put_exhaustiveUrls() throws Exception {
119 		var urls = l(
120 			new URIBuilder("http://localhost/bean"),
121 			java.net.URI.create("http://localhost/bean"),
122 			url("http://localhost/bean"),
123 			"/bean",
124 			new StringBuilder("/bean")
125 		);
126 		var x = client().build();
127 		for (var url : urls) {
128 			x.put(url,bean).run().assertContent("{f:1}");
129 			x.put(url,"{f:1}",APPLICATION_JSON).run().assertContent("{f:1}");
130 			x.put(url).content(bean).run().assertContent("{f:1}");
131 		}
132 	}
133 
134 	@Test void a07_put_exhaustiveBodyTypes() throws Exception {
135 		var bodies = l(
136 			reader("{f:1}"),
137 			inputStream("{f:1}"),
138 			stringResource("{f:1}"),
139 			bean,
140 			stringEntity("{f:1}"),
141 			parts("f","1")
142 		);
143 		for (var body : bodies) {
144 			client().headers(body instanceof PartList ? APPLICATION_FORM_URLENCODED : APPLICATION_JSON).build().put("/bean",body).run().assertContent("{f:1}");
145 		}
146 	}
147 
148 	@Test void a08_post() throws Exception {
149 		client().build().post("/bean",bean).run().assertContent("{f:1}");
150 		client().build().post("/bean").content(bean).run().assertContent("{f:1}");
151 	}
152 
153 	@Test void a09_post_stringBody() throws Exception {
154 		client().build().post("/bean","{f:1}",APPLICATION_JSON).run().assertContent("{f:1}");
155 	}
156 
157 	@Test void a10_post_exhaustiveUrls() throws Exception {
158 		var urls = l(
159 			new URIBuilder("http://localhost/bean"),
160 			java.net.URI.create("http://localhost/bean"),
161 			url("http://localhost/bean"),
162 			"/bean",
163 			new StringBuilder("/bean")
164 		);
165 		var x = client().build();
166 		for (var url : urls) {
167 			x.post(url,bean).run().assertContent("{f:1}");
168 			x.post(url,"{f:1}",APPLICATION_JSON).run().assertContent("{f:1}");
169 			x.post(url).content(bean).run().assertContent("{f:1}");
170 		}
171 	}
172 
173 	@Test void a11_exhaustiveBodyTypes() throws Exception {
174 		var bodies = l(
175 			reader("{f:1}"),
176 			inputStream("{f:1}"),
177 			stringResource("{f:1}"),
178 			bean,
179 			stringEntity("{f:1}"),
180 			parts("f","1")
181 		);
182 		for (var body : bodies) {
183 			client().headers(body instanceof PartList ? APPLICATION_FORM_URLENCODED : APPLICATION_JSON).build().post("/bean",body).run().assertContent("{f:1}");
184 		}
185 	}
186 
187 	@Test void a12_delete() throws Exception {
188 		client().build().delete("/bean").run().assertContent("{f:1}");
189 	}
190 
191 	@Test void a13_delete_exhaustiveUrls() throws Exception {
192 		var urls = l(
193 			new URIBuilder("http://localhost/bean"),
194 			java.net.URI.create("http://localhost/bean"),
195 			url("http://localhost/bean"),
196 			"/bean",
197 			new StringBuilder("/bean")
198 		);
199 		var x = client().build();
200 		for (var url : urls) {
201 			x.delete(url).run().assertContent("{f:1}");
202 		}
203 	}
204 
205 	@Test void a14_options() throws Exception {
206 		client().build().options("/bean").run().assertContent("{f:1}");
207 	}
208 
209 	@Test void a15_options_exhaustiveUrls() throws Exception {
210 		var urls = l(
211 			new URIBuilder("http://localhost/bean"),
212 			java.net.URI.create("http://localhost/bean"),
213 			url("http://localhost/bean"),
214 			"/bean",
215 			new StringBuilder("/bean")
216 		);
217 		var x = client().build();
218 		for (var url : urls) {
219 			x.options(url).run().assertContent("{f:1}");
220 		}
221 	}
222 
223 	@Test void a16_head() throws Exception {
224 		client().build().head("/bean").run().assertContent("");
225 	}
226 
227 	@Test void a17_head_exhaustiveUrls() throws Exception {
228 		var urls = l(
229 			new URIBuilder("http://localhost/bean"),
230 			java.net.URI.create("http://localhost/bean"),
231 			url("http://localhost/bean"),
232 			"/bean",
233 			new StringBuilder("/bean")
234 		);
235 		var x = client().build();
236 		for (var url : urls) {
237 			x.head(url).run().assertContent("");
238 		}
239 	}
240 
241 	@Test void a18_formPost() throws Exception {
242 		client().build().formPost("/bean",bean).accept("application/json5").run().assertContent("{f:1}");
243 
244 		client().build().formPost("/bean",bean).content(bean).accept("application/json5").run().assertContent("{f:1}");
245 		client().build().post("/bean").urlEnc().formDataBean(bean).content(bean).accept("application/json5").run().assertContent("{f:1}");
246 		client().build().post("/bean").urlEnc().content(bean).formDataBean(bean).accept("application/json5").run().assertContent("{f:1}");
247 	}
248 
249 	@Test void a19_formPost_exhaustiveUrls() throws Exception {
250 		var urls = l(
251 			new URIBuilder("http://localhost/bean"),
252 			java.net.URI.create("http://localhost/bean"),
253 			url("http://localhost/bean"),
254 			"/bean",
255 			new StringBuilder("/bean")
256 		);
257 		var x = client().build();
258 		for (var url : urls) {
259 			x.formPost(url,bean).accept("application/json5").run().assertContent("{f:1}");
260 		}
261 	}
262 
263 	@Test void a20_formPost_exhaustiveBodyTypes() throws Exception {
264 		Supplier<Object>
265 			s1 = () -> reader("f=1"),
266 			s2 = () -> inputStream("f=1");
267 		var bodies = l(
268 			/*[ 0]*/ bean,
269 			/*[ 1]*/ parts("f","1"),
270 			/*[ 2]*/ a(part("f","1")),
271 			/*[ 3]*/ stringEntity("f=1", ContentType.APPLICATION_FORM_URLENCODED),
272 			/*[ 4]*/ stringEntity("f=1", null),
273 			/*[ 5]*/ part("f","1"),
274 			/*[ 6]*/ stringResource("f=1"),
275 			/*[ 7]*/ stringResource("f=1"),
276 			/*[ 8]*/ stringResource("f=1").setContentType(APPLICATION_FORM_URLENCODED),
277 			/*[ 9]*/ stringResource("f=1").setContentType(APPLICATION_FORM_URLENCODED),
278 			/*[14]*/ s1,
279 			/*[15]*/ s2
280 		);
281 		for (var i = 0; i < bodies.size(); i++) {
282 			client().header("Check","Content-Type").accept("application/json5").build().formPost("/checkHeader",bodies.get(i)).run().assertContent().setMsg("Body {0} failed",i).asString().isMatches("['application/x-www-form-urlencoded*']");
283 			client().build().formPost("/bean",bodies.get(i)).accept("application/json5").run().assertContent().setMsg("Body {0} failed","#"+i).is("{f:1}");
284 		}
285 	}
286 
287 	@Test void a21_formPostPairs() throws Exception {
288 		client().build().formPostPairs("/bean","f","1").accept("application/json5").run().assertContent("{f:1}");
289 	}
290 
291 	@Test void a22_patch() throws Exception {
292 		client().build().patch("/bean",bean).run().assertContent("{f:1}");
293 		client().build().patch("/bean").content(bean).run().assertContent("{f:1}");
294 	}
295 
296 	@Test void a23_patch_fromString() throws Exception {
297 		client().build().patch("/bean","{f:1}",APPLICATION_JSON).run().assertContent("{f:1}");
298 	}
299 
300 	@Test void a24_patch_exhaustiveBodyTypes() throws Exception {
301 		var bodies = l(
302 			reader("{f:1}"),
303 			inputStream("{f:1}"),
304 			stringResource("{f:1}"),
305 			bean,
306 			stringEntity("{f:1}"),
307 			parts("f","1")
308 		);
309 		var x = client().build();
310 		for (var body : bodies) {
311 			x.patch("/bean",body).header(body instanceof PartList ? APPLICATION_FORM_URLENCODED : APPLICATION_JSON).run().assertContent("{f:1}");
312 		}
313 	}
314 
315 	@Test void a25_patch_exhaustiveUrls() throws Exception {
316 		var urls = l(
317 			new URIBuilder("http://localhost/bean"),
318 			java.net.URI.create("http://localhost/bean"),
319 			url("http://localhost/bean"),
320 			"/bean",
321 			new StringBuilder("/bean")
322 		);
323 		var x = client().build();
324 		for (var url : urls) {
325 			x.patch(url,bean).accept("application/json5").run().assertContent("{f:1}");
326 		}
327 	}
328 
329 	@Test void a26_request_PATCH() throws Exception {
330 		client().build().request("patch","/bean",bean).run().assertContent("{f:1}");
331 		client().build().request("patch","/bean").content(bean).run().assertContent("{f:1}");
332 	}
333 
334 	@Test void a27_request_PATCH_exhaustiveBodyTypes() throws Exception {
335 		var bodies = l(
336 			reader("{f:1}"),
337 			inputStream("{f:1}"),
338 			stringResource("{f:1}"),
339 			bean,
340 			stringEntity("{f:1}"),
341 			parts("f","1")
342 		);
343 		var x = client().build();
344 		for (var body : bodies) {
345 			x.request("patch","/bean",body).header(body instanceof PartList ? APPLICATION_FORM_URLENCODED : APPLICATION_JSON).run().assertContent("{f:1}");
346 		}
347 	}
348 
349 	@Test void a28_request_PATCH_exhaustiveUrls() throws Exception {
350 		var urls = l(
351 			new URIBuilder("http://localhost/bean"),
352 			java.net.URI.create("http://localhost/bean"),
353 			url("http://localhost/bean"),
354 			"/bean",
355 			new StringBuilder("/bean")
356 		);
357 		var x = client().build();
358 		for (var url : urls) {
359 			x.request("patch",url,bean).accept("application/json5").run().assertContent("{f:1}");
360 		}
361 	}
362 
363 	@Test void a29_request_GET() throws Exception {
364 		client().build().request("get","/bean").run().assertContent("{f:1}");
365 	}
366 
367 	@Test void a30_request_GET_exhaustiveUrls() throws Exception {
368 		var urls = l(
369 			new URIBuilder("http://localhost/bean"),
370 			java.net.URI.create("http://localhost/bean"),
371 			url("http://localhost/bean"),
372 			"/bean",
373 			new StringBuilder("/bean")
374 		);
375 		var x = client().build();
376 		for (var url : urls) {
377 			x.request("get",url).accept("application/json5").run().assertContent("{f:1}");
378 		}
379 	}
380 
381 	//-----------------------------------------------------------------------------------------------------------------
382 	// Helper methods.
383 	//-----------------------------------------------------------------------------------------------------------------
384 
385 	private static NameValuePair part(String name, Object val) {
386 		return basicPart(name, val);
387 	}
388 
389 	private static PartList parts(String...pairs) {
390 		return partList(pairs);
391 	}
392 
393 	private static RestClient.Builder client() {
394 		return MockRestClient.create(A.class).json5();
395 	}
396 }