| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.struts2.result; |
| |
| import static javax.servlet.http.HttpServletResponse.SC_SEE_OTHER; |
| import static org.easymock.EasyMock.createControl; |
| import static org.easymock.EasyMock.createNiceMock; |
| import static org.easymock.EasyMock.createMock; |
| import static org.easymock.EasyMock.expect; |
| import static org.easymock.EasyMock.expectLastCall; |
| import static org.easymock.EasyMock.replay; |
| |
| import java.io.IOException; |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.servlet.http.HttpServletRequest; |
| import javax.servlet.http.HttpServletResponse; |
| |
| import ognl.Ognl; |
| |
| import org.apache.struts2.ServletActionContext; |
| import org.apache.struts2.StrutsInternalTestCase; |
| import org.apache.struts2.StrutsStatics; |
| import org.apache.struts2.dispatcher.mapper.ActionMapper; |
| import org.apache.struts2.result.ServletRedirectResult; |
| import org.apache.struts2.views.util.DefaultUrlHelper; |
| import org.easymock.IMocksControl; |
| import org.springframework.mock.web.MockHttpServletRequest; |
| import org.springframework.mock.web.MockHttpServletResponse; |
| |
| import com.mockobjects.dynamic.C; |
| import com.mockobjects.dynamic.Mock; |
| import com.opensymphony.xwork2.ActionContext; |
| import com.opensymphony.xwork2.ActionInvocation; |
| import com.opensymphony.xwork2.ActionProxy; |
| import com.opensymphony.xwork2.config.entities.ActionConfig; |
| import com.opensymphony.xwork2.config.entities.PackageConfig; |
| import com.opensymphony.xwork2.config.entities.ResultConfig; |
| import com.opensymphony.xwork2.mock.MockActionInvocation; |
| import com.opensymphony.xwork2.util.ValueStack; |
| |
| |
| /** |
| */ |
| public class ServletRedirectResultTest extends StrutsInternalTestCase implements StrutsStatics { |
| |
| protected ServletRedirectResult view; |
| private Mock requestMock; |
| private Mock responseMock; |
| protected ActionInvocation ai; |
| |
| |
| public void testAbsoluteRedirect() { |
| view.setLocation("/bar/foo.jsp"); |
| responseMock.expectAndReturn("encodeRedirectURL", "/context/bar/foo.jsp", "/context/bar/foo.jsp"); |
| responseMock.expect("sendRedirect", C.args(C.eq("/context/bar/foo.jsp"))); |
| |
| try { |
| view.execute(ai); |
| requestMock.verify(); |
| responseMock.verify(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| fail(); |
| } |
| } |
| |
| public void testFullUrlRedirect() { |
| view.setLocation("http://localhost/bar/foo.jsp"); |
| responseMock.expectAndReturn("encodeRedirectURL", C.args(C.eq("http://localhost/bar/foo.jsp")), "http://localhost/bar/foo.jsp"); |
| responseMock.expect("sendRedirect", C.args(C.eq("http://localhost/bar/foo.jsp"))); |
| |
| try { |
| view.execute(ai); |
| requestMock.verify(); |
| responseMock.verify(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| fail(); |
| } |
| } |
| |
| public void testFullUrlRedirectWithSpaces() { |
| view.setLocation("http://localhost/bar/foo some.pdf"); |
| responseMock.expectAndReturn("encodeRedirectURL", C.args(C.eq("http://localhost/bar/foo some.pdf")), "http://localhost/bar/foo some.pdf"); |
| responseMock.expect("sendRedirect", C.args(C.eq("http://localhost/bar/foo some.pdf"))); |
| |
| try { |
| view.execute(ai); |
| requestMock.verify(); |
| responseMock.verify(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| fail(); |
| } |
| } |
| |
| public void testFullUrlRedirectWithParams() { |
| view.setLocation("http://localhost/bar/foo.action?param=1¶m 2=3"); |
| responseMock.expectAndReturn("encodeRedirectURL", C.args(C.eq("http://localhost/bar/foo.action?param=1¶m 2=3")), "http://localhost/bar/foo.action?param=1¶m 2=3"); |
| responseMock.expect("sendRedirect", C.args(C.eq("http://localhost/bar/foo.action?param=1¶m 2=3"))); |
| |
| try { |
| view.execute(ai); |
| requestMock.verify(); |
| responseMock.verify(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| fail(); |
| } |
| } |
| |
| public void testAbsoluteRedirect303() { |
| view.setLocation("/bar/foo.jsp"); |
| view.setStatusCode(303); |
| responseMock.expectAndReturn("encodeRedirectURL", "/context/bar/foo.jsp", "/context/bar/foo.jsp"); |
| responseMock.expect("setStatus", C.args(C.eq(SC_SEE_OTHER))); |
| responseMock.expect("setHeader", C.args(C.eq("Location"), C.eq("/context/bar/foo.jsp"))); |
| StringWriter writer = new StringWriter(); |
| responseMock.matchAndReturn("getWriter", new PrintWriter(writer)); |
| |
| try { |
| view.execute(ai); |
| requestMock.verify(); |
| responseMock.verify(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| fail(); |
| } |
| assertEquals("/context/bar/foo.jsp", writer.toString()); |
| } |
| |
| public void testAbsoluteRedirectAnchor() { |
| view.setLocation("/bar/foo.jsp"); |
| view.setAnchor("fragment"); |
| responseMock.expectAndReturn("encodeRedirectURL", "/context/bar/foo.jsp#fragment", "/context/bar/foo.jsp#fragment"); |
| responseMock.expect("sendRedirect", C.args(C.eq("/context/bar/foo.jsp#fragment"))); |
| |
| try { |
| view.execute(ai); |
| requestMock.verify(); |
| responseMock.verify(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| fail(); |
| } |
| } |
| public void testPrependServletContextFalse() { |
| view.setLocation("/bar/foo.jsp"); |
| view.setPrependServletContext(false); |
| responseMock.expectAndReturn("encodeRedirectURL", "/bar/foo.jsp", "/bar/foo.jsp"); |
| responseMock.expect("sendRedirect", C.args(C.eq("/bar/foo.jsp"))); |
| |
| try { |
| view.execute(ai); |
| requestMock.verify(); |
| responseMock.verify(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| fail(); |
| } |
| } |
| |
| public void testRelativeRedirect() throws Exception { |
| view.setLocation("foo.jsp"); |
| requestMock.expectAndReturn("getParameterMap", new HashMap()); |
| requestMock.expectAndReturn("getServletPath", "/namespace/some.action"); |
| requestMock.expectAndReturn("getRequestURI", "/namespace/some.action"); |
| requestMock.expectAndReturn("getAttribute", C.ANY_ARGS, null); |
| responseMock.expectAndReturn("encodeRedirectURL", "/context/namespace/foo.jsp", "/context/namespace/foo.jsp"); |
| responseMock.expect("sendRedirect", C.args(C.eq("/context/namespace/foo.jsp"))); |
| |
| view.execute(ai); |
| |
| requestMock.verify(); |
| responseMock.verify(); |
| } |
| |
| public void testMultipleParametersRedirect() throws Exception { |
| view.setLocation("foo.jsp?foo=bar&baz=jim"); |
| requestMock.expectAndReturn("getParameterMap", new HashMap()); |
| requestMock.expectAndReturn("getServletPath", "/namespace/some.action"); |
| requestMock.expectAndReturn("getRequestURI", "/namespace/some.action"); |
| requestMock.expectAndReturn("getAttribute", C.ANY_ARGS, null); |
| responseMock.expectAndReturn("encodeRedirectURL", "/context/namespace/foo.jsp?foo=bar&baz=jim", "/context/namespace/foo.jsp?foo=bar&baz=jim"); |
| responseMock.expect("sendRedirect", C.args(C.eq("/context/namespace/foo.jsp?foo=bar&baz=jim"))); |
| |
| view.execute(ai); |
| |
| requestMock.verify(); |
| responseMock.verify(); |
| } |
| |
| public void testIncludeParameterInResult() throws Exception { |
| |
| ResultConfig resultConfig = new ResultConfig.Builder("", "") |
| .addParam("namespace", "someNamespace") |
| .addParam("encode", "true") |
| .addParam("parse", "true") |
| .addParam("location", "someLocation") |
| .addParam("prependServletContext", "true") |
| .addParam("method", "someMethod") |
| .addParam("statusCode", "333") |
| .addParam("param1", "value 1") |
| .addParam("param2", "value 2") |
| .addParam("param3", "value 3") |
| .build(); |
| |
| ActionContext context = ActionContext.getContext(); |
| MockHttpServletRequest req = new MockHttpServletRequest(); |
| MockHttpServletResponse res = new MockHttpServletResponse(); |
| context.put(ServletActionContext.HTTP_REQUEST, req); |
| context.put(ServletActionContext.HTTP_RESPONSE, res); |
| |
| |
| Map<String, ResultConfig> results= new HashMap<String, ResultConfig>(); |
| results.put("myResult", resultConfig); |
| |
| ActionConfig actionConfig = new ActionConfig.Builder("", "", "") |
| .addResultConfigs(results).build(); |
| |
| ServletRedirectResult result = new ServletRedirectResult(); |
| result.setLocation("/myNamespace/myAction.action"); |
| result.setParse(false); |
| result.setEncode(false); |
| result.setPrependServletContext(false); |
| result.setAnchor("fragment"); |
| result.setUrlHelper(new DefaultUrlHelper()); |
| |
| IMocksControl control = createControl(); |
| ActionProxy mockActionProxy = control.createMock(ActionProxy.class); |
| ActionInvocation mockInvocation = control.createMock(ActionInvocation.class); |
| expect(mockInvocation.getProxy()).andReturn(mockActionProxy); |
| expect(mockInvocation.getResultCode()).andReturn("myResult"); |
| expect(mockActionProxy.getConfig()).andReturn(actionConfig); |
| expect(mockInvocation.getInvocationContext()).andReturn(context); |
| |
| control.replay(); |
| result.setActionMapper(container.getInstance(ActionMapper.class)); |
| result.execute(mockInvocation); |
| assertEquals("/myNamespace/myAction.action?param1=value+1¶m2=value+2¶m3=value+3#fragment", res.getRedirectedUrl()); |
| control.verify(); |
| } |
| |
| public void testIncludeCollectionParameterInResult() throws Exception { |
| List<String> paramValues = new ArrayList<String>(); |
| paramValues.add("value 1"); |
| paramValues.add(""); |
| paramValues.add("value 2"); |
| paramValues.add(null); |
| |
| ResultConfig resultConfig = new ResultConfig.Builder("", "") |
| .addParam("namespace", "someNamespace") |
| .addParam("param", "${list}") |
| .build(); |
| |
| ActionContext context = ActionContext.getContext(); |
| MockHttpServletRequest req = new MockHttpServletRequest(); |
| MockHttpServletResponse res = new MockHttpServletResponse(); |
| context.put(ServletActionContext.HTTP_REQUEST, req); |
| context.put(ServletActionContext.HTTP_RESPONSE, res); |
| |
| Map<String, ResultConfig> results= new HashMap<String, ResultConfig>(); |
| results.put("myResult", resultConfig); |
| |
| ActionConfig actionConfig = new ActionConfig.Builder("", "", "") |
| .addResultConfigs(results).build(); |
| |
| ServletRedirectResult result = new ServletRedirectResult(); |
| result.setLocation("/myNamespace/myAction.action"); |
| result.setParse(true); |
| result.setEncode(false); |
| result.setPrependServletContext(false); |
| result.setUrlHelper(new DefaultUrlHelper()); |
| result.setSuppressEmptyParameters(true); |
| |
| IMocksControl control = createControl(); |
| ActionProxy mockActionProxy = control.createMock(ActionProxy.class); |
| ActionInvocation mockInvocation = control.createMock(ActionInvocation.class); |
| |
| ValueStack mockValueStack = control.createMock(ValueStack.class); |
| Map<String, Object> mockContext = new HashMap<String, Object>(); |
| mockContext.put(ActionContext.CONTAINER, container); |
| |
| expect(mockInvocation.getStack()).andReturn(mockValueStack); |
| expect(mockValueStack.getContext()).andReturn(mockContext); |
| |
| expect(mockInvocation.getStack()).andReturn(mockValueStack); |
| |
| expect(mockValueStack.findValue("list")).andReturn(paramValues); // no asType !!! |
| |
| expect(mockInvocation.getProxy()).andReturn(mockActionProxy); |
| expect(mockInvocation.getResultCode()).andReturn("myResult"); |
| expect(mockActionProxy.getConfig()).andReturn(actionConfig); |
| expect(mockInvocation.getInvocationContext()).andReturn(context); |
| |
| expect(mockValueStack.getContext()).andReturn(mockContext); |
| |
| control.replay(); |
| result.setActionMapper(container.getInstance(ActionMapper.class)); |
| result.execute(mockInvocation); |
| assertEquals("/myNamespace/myAction.action?param=value+1¶m=value+2", res.getRedirectedUrl()); |
| control.verify(); |
| } |
| |
| /** |
| * Test to exercise the code path and prove sendRedirect() will output |
| * the desired log warning when an IOException is thrown for statusCode SC_FOUND. |
| */ |
| public void testSendRedirectSCFoundIOException() { |
| HttpServletResponse httpServletResponseMock = (HttpServletResponse) createMock(HttpServletResponse.class); |
| boolean ioeCaught = false; |
| view.setLocation("/bar/foo.jsp"); |
| view.setStatusCode(HttpServletResponse.SC_FOUND); |
| try { |
| httpServletResponseMock.sendRedirect(view.getLocation()); |
| expectLastCall().andStubThrow(new IOException("Fake IO Exception (SC_FOUND)")); |
| replay(httpServletResponseMock); |
| } catch (IOException ioe) { |
| fail("Mock sendRedirect call setup failed. Ex: " + ioe); |
| } |
| try { |
| view.sendRedirect(httpServletResponseMock, view.getLocation()); |
| } catch (IOException ioe) { |
| ioeCaught = true; // Verify expected exception was thrown |
| } |
| if (!ioeCaught) { |
| fail("sendRedirect (SC_FOUND) with forced IOException did not propagate from setLocation!"); |
| } |
| } |
| |
| /** |
| * Test to exercise the code path and prove sendRedirect() will output |
| * the desired log warning when an IOException is thrown for statusCode SC_MOVED_PERMANENTLY. |
| */ |
| public void testSendRedirectSCMovedPermanentlyIOException() { |
| HttpServletResponse httpServletResponseMock = (HttpServletResponse) createMock(HttpServletResponse.class); |
| boolean ioeCaught = false; |
| view.setLocation("/bar/foo.jsp"); |
| view.setStatusCode(HttpServletResponse.SC_MOVED_PERMANENTLY); // Any non SC_FOUND will suffice |
| try { |
| httpServletResponseMock.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); |
| expectLastCall(); |
| httpServletResponseMock.setHeader("Location", view.getLocation()); |
| expectLastCall(); |
| expect(httpServletResponseMock.getWriter()).andStubThrow(new IOException("Fake IO Exception (SC_MOVED_PERMANENTLY)")); |
| replay(httpServletResponseMock); |
| } catch (IOException ioe) { |
| fail("Mock getWriter call setup failed. Ex: " + ioe); |
| } |
| try { |
| view.sendRedirect(httpServletResponseMock, view.getLocation()); |
| } catch (IOException ioe) { |
| ioeCaught = true; // Verify expected exception was thrown |
| } |
| if (!ioeCaught) { |
| fail("sendRedirect (SC_MOVED_PERMANENTLY) with forced IOException did not propagate from setLocation!"); |
| } |
| } |
| |
| /** |
| * Test to exercise the code path and prove sendRedirect() will output |
| * the desired log warning when an IllegalStateException is thrown for statusCode SC_FOUND. |
| */ |
| public void testSendRedirectSCFoundIllegalStateException() { |
| HttpServletResponse httpServletResponseMock = (HttpServletResponse) createMock(HttpServletResponse.class); |
| boolean iseCaught = false; |
| view.setLocation("/bar/foo.jsp"); |
| view.setStatusCode(HttpServletResponse.SC_FOUND); |
| try { |
| httpServletResponseMock.sendRedirect(view.getLocation()); |
| expectLastCall().andStubThrow(new IllegalStateException("Fake IllegalState Exception (SC_FOUND)")); |
| expect(httpServletResponseMock.isCommitted()).andStubReturn(Boolean.TRUE); |
| replay(httpServletResponseMock); |
| } catch (IOException ioe) { |
| fail("Mock sendRedirect call setup failed. Ex: " + ioe); |
| } |
| try { |
| view.sendRedirect(httpServletResponseMock, view.getLocation()); |
| } catch (IOException ioe) { |
| iseCaught = false; |
| } catch (IllegalStateException ise) { |
| iseCaught = true; // Verify expected exception was thrown |
| } |
| if (!iseCaught) { |
| fail("sendRedirect (SC_FOUND) with forced IllegalStateException did not propagate from setLocation!"); |
| } |
| } |
| |
| /** |
| * Test to exercise the code path and prove sendRedirect() will output |
| * the desired log warning when an IllegalStateException is thrown for statusCode SC_MOVED_PERMANENTLY. |
| */ |
| public void testSendRedirectSCMovedPermanentlyIllegalStateException() { |
| HttpServletResponse httpServletResponseMock = (HttpServletResponse) createMock(HttpServletResponse.class); |
| boolean iseCaught = false; |
| view.setLocation("/bar/foo.jsp"); |
| view.setStatusCode(HttpServletResponse.SC_MOVED_PERMANENTLY); // Any non SC_FOUND will suffice |
| try { |
| httpServletResponseMock.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); |
| expectLastCall(); |
| httpServletResponseMock.setHeader("Location", view.getLocation()); |
| expectLastCall(); |
| expect(httpServletResponseMock.getWriter()).andStubThrow(new IllegalStateException("Fake IllegalState Exception (SC_MOVED_PERMANENTLY)")); |
| expect(httpServletResponseMock.isCommitted()).andStubReturn(Boolean.TRUE); |
| replay(httpServletResponseMock); |
| } catch (IOException ioe) { |
| fail("Mock getWriter call setup failed. Ex: " + ioe); |
| } |
| try { |
| view.sendRedirect(httpServletResponseMock, view.getLocation()); |
| } catch (IOException ioe) { |
| iseCaught = false; |
| } catch (IllegalStateException ise) { |
| iseCaught = true; // Verify expected exception was thrown |
| } |
| if (!iseCaught) { |
| fail("sendRedirect (SC_MOVED_PERMANENTLY) with forced IllegalStateException did not propagate from setLocation!"); |
| } |
| } |
| |
| protected void setUp() throws Exception { |
| super.setUp(); |
| configurationManager.getConfiguration(). |
| addPackageConfig("foo", new PackageConfig.Builder("foo").namespace("/namespace").build()); |
| |
| view = new ServletRedirectResult(); |
| container.inject(view); |
| |
| responseMock = new Mock(HttpServletResponse.class); |
| |
| requestMock = new Mock(HttpServletRequest.class); |
| requestMock.matchAndReturn("getContextPath", "/context"); |
| |
| ResultConfig resultConfig = new ResultConfig.Builder("", "").build(); |
| |
| Map<String, ResultConfig> results= new HashMap<String, ResultConfig>(); |
| results.put("myResult", resultConfig); |
| |
| ActionConfig actionConfig = new ActionConfig.Builder("", "", "") |
| .addResultConfigs(results).build(); |
| |
| ActionContext ac = new ActionContext(Ognl.createDefaultContext(null)); |
| ac.put(ServletActionContext.HTTP_REQUEST, requestMock.proxy()); |
| ac.put(ServletActionContext.HTTP_RESPONSE, responseMock.proxy()); |
| MockActionInvocation ai = new MockActionInvocation(); |
| ai.setInvocationContext(ac); |
| ai.setResultCode("myResult"); |
| ActionProxy mockActionProxy = createNiceMock(ActionProxy.class); |
| ai.setProxy(mockActionProxy); |
| expect(mockActionProxy.getConfig()).andReturn(actionConfig).anyTimes(); |
| replay(mockActionProxy); |
| this.ai = ai; |
| ai.setStack(ActionContext.getContext().getValueStack()); |
| } |
| } |