1   /*
2    * Copyright 2004-2009 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.seasar.cubby.action;
17  
18  import static org.easymock.EasyMock.createMock;
19  import static org.easymock.EasyMock.expect;
20  import static org.easymock.EasyMock.getCurrentArguments;
21  import static org.easymock.EasyMock.isA;
22  import static org.easymock.EasyMock.replay;
23  import static org.easymock.EasyMock.verify;
24  import static org.junit.Assert.assertEquals;
25  import static org.junit.Assert.assertFalse;
26  import static org.junit.Assert.fail;
27  
28  import java.io.IOException;
29  import java.lang.reflect.Method;
30  import java.util.ArrayList;
31  import java.util.LinkedHashMap;
32  import java.util.List;
33  import java.util.Map;
34  
35  import javax.servlet.RequestDispatcher;
36  import javax.servlet.http.HttpServletRequest;
37  import javax.servlet.http.HttpServletResponse;
38  import javax.servlet.http.HttpServletResponseWrapper;
39  
40  import org.easymock.IAnswer;
41  import org.junit.After;
42  import org.junit.Before;
43  import org.junit.Test;
44  import org.seasar.cubby.mock.MockActionContext;
45  import org.seasar.cubby.mock.MockPathResolverProvider;
46  import org.seasar.cubby.plugin.PluginRegistry;
47  import org.seasar.cubby.plugins.BinderPlugin;
48  import org.seasar.cubby.routing.PathResolver;
49  import org.seasar.cubby.routing.RoutingException;
50  import org.seasar.cubby.routing.impl.PathResolverImpl;
51  import org.seasar.cubby.routing.impl.PathTemplateParserImpl;
52  import org.seasar.cubby.spi.PathResolverProvider;
53  
54  public class RedirectTest {
55  
56  	private final PluginRegistry pluginRegistry = PluginRegistry.getInstance();
57  
58  	private final MockAction action = new MockAction();
59  
60  	private HttpServletRequest request;
61  
62  	private RequestDispatcher requestDispatcher;
63  
64  	private HttpServletResponse response;
65  
66  	@Before
67  	public void setupContainer() {
68  		final List<Class<?>> actionClasses = new ArrayList<Class<?>>();
69  		actionClasses.add(MockAction.class);
70  		final PathResolver pathResolver = new PathResolverImpl(
71  				new PathTemplateParserImpl());
72  		pathResolver.addAll(actionClasses);
73  		final BinderPlugin binderPlugin = new BinderPlugin();
74  		binderPlugin.bind(PathResolverProvider.class).toInstance(
75  				new MockPathResolverProvider(pathResolver));
76  		pluginRegistry.register(binderPlugin);
77  	}
78  
79  	@After
80  	public void tearDownProvider() {
81  		pluginRegistry.clear();
82  	}
83  
84  	@Before
85  	public void setupRequest() {
86  		request = createMock(HttpServletRequest.class);
87  		expect(request.getCharacterEncoding()).andReturn("UTF-8").anyTimes();
88  		expect(request.getRequestURL()).andReturn(
89  				new StringBuffer("http://localhost/foo")).anyTimes();
90  		requestDispatcher = createMock(RequestDispatcher.class);
91  		response = createMock(HttpServletResponse.class);
92  	}
93  
94  	@Test
95  	public void basicSequence() throws Exception {
96  		final Method method = action.getClass().getMethod("dummy1");
97  		final MockActionContext actionContext = new MockActionContext(action,
98  				MockAction.class, method);
99  
100 		expect(request.getContextPath()).andReturn("/cubby").anyTimes();
101 		expect(response.encodeRedirectURL(isA(String.class))).andStubAnswer(
102 				new IAnswer<String>() {
103 
104 					public String answer() throws Throwable {
105 						return String.class.cast(getCurrentArguments()[0]);
106 					}
107 
108 				});
109 		response.sendRedirect("/cubby/mock/path.jsp");
110 		replay(request, requestDispatcher, response);
111 
112 		final Redirect redirect = new Redirect("path.jsp");
113 		assertFalse(actionContext.isPrerendered());
114 		redirect.execute(actionContext, request, response);
115 		assertFalse(actionContext.isPrerendered());
116 		assertFalse(actionContext.isPostrendered());
117 
118 		verify(request, response, requestDispatcher);
119 	}
120 
121 	@Test
122 	public void basicSequenceWithProtocol() throws Exception {
123 		final Method method = action.getClass().getMethod("dummy1");
124 		final MockActionContext actionContext = new MockActionContext(action,
125 				MockAction.class, method);
126 
127 		expect(request.getContextPath()).andReturn("/cubby").anyTimes();
128 		expect(response.encodeRedirectURL(isA(String.class))).andStubAnswer(
129 				new IAnswer<String>() {
130 
131 					public String answer() throws Throwable {
132 						return String.class.cast(getCurrentArguments()[0]);
133 					}
134 
135 				});
136 		response.sendRedirect("https://localhost/cubby/mock/path.jsp");
137 		replay(request, requestDispatcher, response);
138 
139 		final Redirect redirect = new Redirect("path.jsp", "https");
140 		assertFalse(actionContext.isPrerendered());
141 		redirect.execute(actionContext, request, response);
142 		assertFalse(actionContext.isPrerendered());
143 		assertFalse(actionContext.isPostrendered());
144 
145 		verify(request, response, requestDispatcher);
146 	}
147 
148 	@Test
149 	public void basicSequenceWithProtocolAndPort() throws Exception {
150 		final Method method = action.getClass().getMethod("dummy1");
151 		final MockActionContext actionContext = new MockActionContext(action,
152 				MockAction.class, method);
153 
154 		expect(request.getContextPath()).andReturn("/cubby").anyTimes();
155 		expect(response.encodeRedirectURL(isA(String.class))).andStubAnswer(
156 				new IAnswer<String>() {
157 
158 					public String answer() throws Throwable {
159 						return String.class.cast(getCurrentArguments()[0]);
160 					}
161 
162 				});
163 		response.sendRedirect("https://localhost:8080/cubby/mock/path.jsp");
164 		replay(request, requestDispatcher, response);
165 
166 		final Redirect redirect = new Redirect("path.jsp", "https", 8080);
167 		assertFalse(actionContext.isPrerendered());
168 		redirect.execute(actionContext, request, response);
169 		assertFalse(actionContext.isPrerendered());
170 		assertFalse(actionContext.isPostrendered());
171 
172 		verify(request, response, requestDispatcher);
173 	}
174 
175 	@Test
176 	public void relativePath() throws Exception {
177 		final Method method = action.getClass().getMethod("dummy1");
178 		final ActionContext actionContext = new MockActionContext(action,
179 				MockAction.class, method);
180 
181 		expect(request.getContextPath()).andReturn("/cubby").anyTimes();
182 		expect(response.encodeRedirectURL(isA(String.class))).andStubAnswer(
183 				new IAnswer<String>() {
184 
185 					public String answer() throws Throwable {
186 						return String.class.cast(getCurrentArguments()[0]);
187 					}
188 
189 				});
190 		response.sendRedirect("/cubby/mock/page.jsp");
191 		replay(request, requestDispatcher, response);
192 
193 		final Redirect redirect = new Redirect("page.jsp");
194 		redirect.execute(actionContext, request, response);
195 
196 		verify(request, response, requestDispatcher);
197 	}
198 
199 	@Test
200 	public void relativePathWithProtocol() throws Exception {
201 		final Method method = action.getClass().getMethod("dummy1");
202 		final ActionContext actionContext = new MockActionContext(action,
203 				MockAction.class, method);
204 
205 		expect(request.getContextPath()).andReturn("/cubby").anyTimes();
206 		expect(response.encodeRedirectURL(isA(String.class))).andStubAnswer(
207 				new IAnswer<String>() {
208 
209 					public String answer() throws Throwable {
210 						return String.class.cast(getCurrentArguments()[0]);
211 					}
212 
213 				});
214 		response.sendRedirect("https://localhost/cubby/mock/page.jsp");
215 		replay(request, requestDispatcher, response);
216 
217 		final Redirect redirect = new Redirect("page.jsp", "https");
218 		redirect.execute(actionContext, request, response);
219 
220 		verify(request, response, requestDispatcher);
221 	}
222 
223 	@Test
224 	public void absolutePath() throws Exception {
225 		final Method method = action.getClass().getMethod("dummy1");
226 		final ActionContext actionContext = new MockActionContext(action,
227 				MockAction.class, method);
228 
229 		expect(request.getContextPath()).andReturn("/cubby").anyTimes();
230 		expect(response.encodeRedirectURL(isA(String.class))).andStubAnswer(
231 				new IAnswer<String>() {
232 
233 					public String answer() throws Throwable {
234 						return String.class.cast(getCurrentArguments()[0]);
235 					}
236 
237 				});
238 		response.sendRedirect("/cubby/absolute/path.jsp");
239 		replay(request, requestDispatcher, response);
240 
241 		final Redirect redirect = new Redirect("/absolute/path.jsp");
242 		redirect.execute(actionContext, request, response);
243 
244 		verify(request, response, requestDispatcher);
245 	}
246 
247 	@Test
248 	public void absolutePathWithProtocol() throws Exception {
249 		final Method method = action.getClass().getMethod("dummy1");
250 		final ActionContext actionContext = new MockActionContext(action,
251 				MockAction.class, method);
252 
253 		expect(request.getContextPath()).andReturn("/cubby").anyTimes();
254 		expect(response.encodeRedirectURL(isA(String.class))).andStubAnswer(
255 				new IAnswer<String>() {
256 
257 					public String answer() throws Throwable {
258 						return String.class.cast(getCurrentArguments()[0]);
259 					}
260 
261 				});
262 		response.sendRedirect("https://localhost/cubby/absolute/path.jsp");
263 		replay(request, requestDispatcher, response);
264 
265 		final Redirect redirect = new Redirect("/absolute/path.jsp", "https");
266 		redirect.execute(actionContext, request, response);
267 
268 		verify(request, response, requestDispatcher);
269 	}
270 
271 	@Test
272 	public void absoluteURL() throws Exception {
273 		final Method method = action.getClass().getMethod("dummy1");
274 		final ActionContext actionContext = new MockActionContext(action,
275 				MockAction.class, method);
276 
277 		expect(request.getContextPath()).andReturn("/cubby").anyTimes();
278 		expect(response.encodeRedirectURL(isA(String.class))).andStubAnswer(
279 				new IAnswer<String>() {
280 
281 					public String answer() throws Throwable {
282 						return String.class.cast(getCurrentArguments()[0]);
283 					}
284 
285 				});
286 		response.sendRedirect("http://example.com/");
287 		replay(request, requestDispatcher, response);
288 
289 		final Redirect redirect = new Redirect("http://example.com/");
290 		redirect.execute(actionContext, request, response);
291 
292 		verify(request, response, requestDispatcher);
293 	}
294 
295 	@Test
296 	public void rootContextPath() throws Exception {
297 		final Method method = action.getClass().getMethod("dummy1");
298 		final ActionContext actionContext = new MockActionContext(action,
299 				MockAction.class, method);
300 
301 		expect(request.getContextPath()).andReturn("/").anyTimes();
302 		expect(response.encodeRedirectURL(isA(String.class))).andStubAnswer(
303 				new IAnswer<String>() {
304 
305 					public String answer() throws Throwable {
306 						return String.class.cast(getCurrentArguments()[0]);
307 					}
308 
309 				});
310 		response.sendRedirect("/mock/path.jsp");
311 		replay(request, requestDispatcher, response);
312 
313 		final Redirect redirect = new Redirect("path.jsp");
314 		redirect.execute(actionContext, request, response);
315 
316 		verify(request, response, requestDispatcher);
317 	}
318 
319 	@Test
320 	public void redirectByClassAndMethod1() throws Exception {
321 		final Redirect redirect = new Redirect(MockAction.class, "dummy1");
322 		PluginRegistry.getInstance().clear();
323 
324 		assertEquals("/mock/dummy1", redirect.getPath("UTF-8"));
325 	}
326 
327 	@Test
328 	public void redirectByClassAndMethod2() throws Exception {
329 		final Map<String, String[]> values = new LinkedHashMap<String, String[]>();
330 		values.put("value1", new String[] { "123" });
331 		values.put("value2", new String[] { "456" });
332 
333 		final Redirect redirect = new Redirect(MockAction.class, "dummy1",
334 				values);
335 		PluginRegistry.getInstance().clear();
336 
337 		assertEquals("/mock/dummy1?value1=123&value2=456", redirect
338 				.getPath("UTF-8"));
339 	}
340 
341 	@Test
342 	public void redirectByClassAndMethod3() throws Exception {
343 		final Map<String, String[]> values = new LinkedHashMap<String, String[]>();
344 		values.put("value1", new String[] { "123" });
345 		values.put("value2", new String[] { "456" });
346 		final Redirect redirect = new Redirect(MockAction.class, "dummy2",
347 				values);
348 		PluginRegistry.getInstance().clear();
349 
350 		assertEquals("/mock/dummy2/123/456", redirect.getPath("UTF-8"));
351 	}
352 
353 	@Test
354 	public void redirectByClassAndMethod4() throws Exception {
355 		final Map<String, String[]> values = new LinkedHashMap<String, String[]>();
356 		values.put("value1", new String[] { "123" });
357 		values.put("value2", new String[] { "456" });
358 		values.put("value3", new String[] { "789" });
359 		final Redirect redirect = new Redirect(MockAction.class, "dummy2",
360 				values);
361 		PluginRegistry.getInstance().clear();
362 
363 		assertEquals("/mock/dummy2/123/456?value3=789", redirect
364 				.getPath("UTF-8"));
365 	}
366 
367 	@Test
368 	public void redirectByClassAndMethod5() throws Exception {
369 		final Redirect redirect1 = new Redirect(MockAction.class, "index");
370 		final Redirect redirect2 = new Redirect(MockAction.class);
371 
372 		PluginRegistry.getInstance().clear();
373 
374 		assertEquals("/mock/", redirect1.getPath("UTF-8"));
375 		assertEquals("/mock/", redirect2.getPath("UTF-8"));
376 	}
377 
378 	@Test
379 	public void redirectByClassAndMethodFailureNoRouting() throws Exception {
380 		try {
381 			new Redirect(MockAction.class, "none").getPath("UTF-8");
382 			fail();
383 		} catch (final RoutingException e) {
384 			// ok
385 		}
386 	}
387 
388 	@Test
389 	public void redirectByClassAndMethodFailureLessParameter() throws Exception {
390 		try {
391 			new Redirect(MockAction.class, "dummy2").getPath("UTF-8");
392 			fail();
393 		} catch (final RoutingException e) {
394 			// ok
395 		}
396 	}
397 
398 	@Test
399 	public void redirectByClassAndMethodFailureUnmatchParameter()
400 			throws Exception {
401 		final Map<String, String[]> values = new LinkedHashMap<String, String[]>();
402 		values.put("value1", new String[] { "abc" });
403 		values.put("value2", new String[] { "456" });
404 		try {
405 			new Redirect(MockAction.class, "dummy2", values).getPath("UTF-8");
406 			fail();
407 		} catch (final RoutingException e) {
408 			// ok
409 		}
410 	}
411 
412 	@Test
413 	public void getPath() throws Exception {
414 		final Redirect redirect = new Redirect("/absolute/redirect");
415 		PluginRegistry.getInstance().clear();
416 		assertEquals("/absolute/redirect", redirect.getPath("UTF-8"));
417 	}
418 
419 	@Test
420 	public void param1() throws Exception {
421 		final Redirect redirect = new Redirect(MockAction.class, "dummy1")
422 				.param("value1", "123").param("value2", "456");
423 		PluginRegistry.getInstance().clear();
424 		assertEquals("/mock/dummy1?value1=123&value2=456", redirect
425 				.getPath("UTF-8"));
426 	}
427 
428 	@Test
429 	public void pParam2() throws Exception {
430 		final Map<String, String[]> params = new LinkedHashMap<String, String[]>();
431 		params.put("value1", new String[] { "123" });
432 		final Redirect redirect = new Redirect(MockAction.class, "dummy1",
433 				params).param("value2", "456");
434 		PluginRegistry.getInstance().clear();
435 		assertEquals("/mock/dummy1?value1=123&value2=456", redirect
436 				.getPath("UTF-8"));
437 	}
438 
439 	@Test
440 	public void param3() throws Exception {
441 		final Redirect redirect = new Redirect("hoge").param("value1", "123")
442 				.param("value2", "456");
443 		PluginRegistry.getInstance().clear();
444 		assertEquals("hoge?value1=123&value2=456", redirect.getPath("UTF-8"));
445 	}
446 
447 	interface Asserter {
448 		void assertDispatchPath(String path);
449 	}
450 
451 	static class RequestDispatcherAssertionWrapper extends
452 			HttpServletResponseWrapper {
453 
454 		private final Asserter asserter;
455 
456 		public RequestDispatcherAssertionWrapper(
457 				final HttpServletResponse response, final Asserter asserter) {
458 			super(response);
459 			this.asserter = asserter;
460 		}
461 
462 		@Override
463 		public void sendRedirect(final String location) throws IOException {
464 			asserter.assertDispatchPath(location);
465 			super.sendRedirect(location);
466 		}
467 
468 	}
469 
470 }