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