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