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;
18  
19  import org.apache.juneau.*;
20  import org.apache.juneau.http.annotation.*;
21  import org.apache.juneau.rest.annotation.*;
22  import org.apache.juneau.rest.mock.*;
23  import org.apache.juneau.serializer.*;
24  import org.apache.juneau.utest.utils.*;
25  import org.junit.jupiter.api.*;
26  
27  class Header_Accept_Test extends TestBase {
28  
29  	//------------------------------------------------------------------------------------------------------------------
30  	// Setup classes
31  	//------------------------------------------------------------------------------------------------------------------
32  
33  	public static class S1 extends FakeWriterSerializer {
34  		public S1(FakeWriterSerializer.Builder b) {
35  			super(b.produces("text/s1").function((s,o) -> "s1"));
36  		}
37  	}
38  	public static class S2 extends FakeWriterSerializer {
39  		public S2(FakeWriterSerializer.Builder b) {
40  			super(b.produces("text/s2").function((s,o) -> "s2"));
41  		}
42  	}
43  	public static class S3 extends FakeWriterSerializer {
44  		public S3(FakeWriterSerializer.Builder b) {
45  			super(b.produces("text/s3").function((s,o) -> "s3"));
46  		}
47  	}
48  
49  	//------------------------------------------------------------------------------------------------------------------
50  	// Test that default Accept headers on servlet annotation are picked up.
51  	//------------------------------------------------------------------------------------------------------------------
52  
53  	@Rest(
54  		defaultRequestHeaders={" Accept : text/s2 "},
55  		serializers={S1.class,S2.class}
56  	)
57  	public static class A {
58  		@RestOp
59  		public String put(@Content String in) {
60  			return in;
61  		}
62  	}
63  
64  	@Test void a01_defaultHeadersOnServletAnnotation() throws Exception {
65  		var a = MockRestClient.buildLax(A.class);
66  		a.put("/", null)
67  			.run()
68  			.assertContent("s2");
69  		a.put("/", null)
70  			.accept("text/s1")
71  			.run()
72  			.assertContent("s1");
73  		a.put("/", null)
74  			.accept("text/s2")
75  			.run()
76  			.assertContent("s2");
77  		a.put("?noTrace=true", null)
78  			.accept("text/s3")
79  			.run()
80  			.assertStatus(406)
81  			.assertContent().isContains("Unsupported media-type in request header 'Accept': 'text/s3'");
82  	}
83  
84  	//------------------------------------------------------------------------------------------------------------------
85  	// Test that default Accept headers on servlet annotation are picked up
86  	// when @RestOp.parsers/serializers annotations are used.
87  	//------------------------------------------------------------------------------------------------------------------
88  
89  	@Rest(
90  		defaultRequestHeaders={" Accept : text/s2 "},
91  		serializers={S1.class,S2.class}
92  	)
93  	public static class B {
94  		@RestOp(serializers=S3.class)
95  		public String put(@Content String in) {
96  			return in;
97  		}
98  	}
99  
100 	@Test void b01_restMethodWithParsersSerializers() throws Exception {
101 		var b = MockRestClient.buildLax(B.class);
102 		b.put("/", null).accept("text/s3").run().assertContent("s3");
103 		b.put("?noTrace=true", null)
104 			.accept("text/s4")
105 			.run()
106 			.assertStatus(406)
107 			.assertContent().isContains(
108 				"Unsupported media-type in request header 'Accept': 'text/s4'",
109 				"Supported media-types: ['text/s3']"
110 			);
111 	}
112 
113 	//------------------------------------------------------------------------------------------------------------------
114 	// Test that default Accept headers on servlet annotation are picked up
115 	// when @RestOp.addParsers/addSerializers annotations are used.
116 	//------------------------------------------------------------------------------------------------------------------
117 
118 	@Rest(
119 		defaultRequestHeaders={" Accept : text/s2 "},
120 		serializers={S1.class,S2.class}
121 	)
122 	public static class C {
123 		@RestOp(serializers={S3.class,SerializerSet.Inherit.class})
124 		public String put(@Content String in) {
125 			return in;
126 		}
127 	}
128 
129 	@Test void c01_restMethodAddParsersSerializersInherit() throws Exception {
130 		var c = MockRestClient.buildLax(C.class);
131 		c.put("/", null)
132 			.run()
133 			.assertContent("s2");
134 		c.put("/", null)
135 			.accept("text/s1")
136 			.run()
137 			.assertContent("s1");
138 		c.put("/", null)
139 			.accept("text/s2")
140 			.run()
141 			.assertContent("s2");
142 		c.put("/", null)
143 			.accept("text/s3")
144 			.run()
145 			.assertContent("s3");
146 		c.put("?noTrace=true", null)
147 			.accept("text/s4")
148 			.run()
149 			.assertStatus(406)
150 			.assertContent().isContains(
151 				"Unsupported media-type in request header 'Accept': 'text/s4'",
152 				"Supported media-types: ['text/s3','text/s1','text/s2']"
153 			);
154 	}
155 
156 	//------------------------------------------------------------------------------------------------------------------
157 	// Various Accept incantations.
158 	//------------------------------------------------------------------------------------------------------------------
159 
160 	@Rest(
161 		defaultRequestHeaders={" Accept : text/s2 "},
162 		serializers={S1.class,S2.class}
163 	)
164 	public static class D {
165 		@RestOp
166 		public String put(@Content String in) {
167 			return in;
168 		}
169 	}
170 
171 	@Test void d01_accept_valid() throws Exception {
172 		var d = MockRestClient.buildLax(D.class);
173 		// "*/*" should match the first serializer, not the default serializer.
174 		d.put("/", null).accept("*/*").run().assertContent("s1");
175 		// "text/*" should match the first serializer, not the default serializer.
176 		d.put("/", null).accept("text/*").run().assertContent("s1");
177 		d.put("/", null).accept("bad/*,text/*").run().assertContent("s1");
178 		d.put("/", null).accept("text/*,bad/*").run().assertContent("s1");
179 		d.put("/", null).accept("text/s1;q=0.5,text/s2").run().assertContent("s2");
180 		d.put("/", null).accept("text/s1,text/s2;q=0.5").run().assertContent("s1");
181 		d.put("?noTrace=true", null)
182 			.accept("bad/*")
183 			.run()
184 			.assertStatus(406)
185 			.assertContent().isContains(
186 				"Unsupported media-type in request header 'Accept': 'bad/*'",
187 				"Supported media-types: ['text/s1','text/s2']"
188 			);
189 	}
190 
191 	//------------------------------------------------------------------------------------------------------------------
192 	// Test that default Accept headers on method annotation are picked up
193 	// when @RestOp.parsers/serializers annotations are used.
194 	//------------------------------------------------------------------------------------------------------------------
195 
196 	@Rest(
197 		defaultRequestHeaders={" Accept : text/s3 "},
198 		serializers={S1.class,S2.class}
199 	)
200 	public static class E {
201 		@RestOp(defaultRequestHeaders={"Accept: text/s2"}, serializers=S3.class)
202 		public String put(@Content String in) {
203 			return in;
204 		}
205 	}
206 
207 	@Test void e01_restMethodParserSerializerAnnotations() throws Exception {
208 		var e = MockRestClient.buildLax(E.class);
209 		e.put("/", null).run().assertContent("s3");
210 		e.put("/", null).accept("text/s3").run().assertContent("s3");
211 		e.put("?noTrace=true", null)
212 			.accept("text/s1")
213 			.run()
214 			.assertStatus(406)
215 			.assertContent().isContains(
216 				"Unsupported media-type in request header 'Accept': 'text/s1'",
217 				"Supported media-types: ['text/s3']"
218 			);
219 		e.put("?noTrace=true", null).accept("text/s2").run()
220 			.assertStatus(406)
221 			.assertContent().isContains(
222 				"Unsupported media-type in request header 'Accept': 'text/s2'",
223 				"Supported media-types: ['text/s3']"
224 			);
225 	}
226 
227 	//------------------------------------------------------------------------------------------------------------------
228 	// Test that default Accept headers on method annotation are picked up
229 	// 	when @RestOp.addParsers/addSerializers annotations are used.
230 	//------------------------------------------------------------------------------------------------------------------
231 
232 	@Rest(
233 		defaultRequestHeaders={" Accept : text/s3 "},
234 		serializers={S1.class,S2.class}
235 	)
236 	public static class F {
237 		@RestOp(defaultRequestHeaders={"Accept: text/s2"}, serializers={SerializerSet.Inherit.class, S3.class})
238 		public String put(@Content String in) {
239 			return in;
240 		}
241 	}
242 
243 	@Test void f01_restMethodAddParsersSerializersAnnotations() throws Exception {
244 		var f = MockRestClient.build(F.class);
245 		f.put("/", null).run().assertContent("s3");
246 		f.put("/", null).accept("text/s1").run().assertContent("s1");
247 		f.put("/", null).accept("text/s2").run().assertContent("s2");
248 		f.put("/", null).accept("text/s3").run().assertContent("s3");
249 	}
250 }