    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 }