blob: 007b508528eb9f600eff635b37666c4ef7bb429a [file] [log] [blame]
/*
* 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&param 2=3");
responseMock.expectAndReturn("encodeRedirectURL", C.args(C.eq("http://localhost/bar/foo.action?param=1&param 2=3")), "http://localhost/bar/foo.action?param=1&param 2=3");
responseMock.expect("sendRedirect", C.args(C.eq("http://localhost/bar/foo.action?param=1&param 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&param2=value+2&param3=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&param=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());
}
}