Upgraded all Servlet API mocks to Servlet 3.0 (with a little bit of Servlet 3.1 support in MockHttpServletResponse)

This commit is contained in:
Juergen Hoeller
2013-03-20 17:19:34 +01:00
parent d03de21d62
commit deba32cad9
16 changed files with 847 additions and 322 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ package org.springframework.mock.web.test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
@@ -56,6 +55,7 @@ public class MockAsyncContext implements AsyncContext {
this.response = (HttpServletResponse) response;
}
@Override
public ServletRequest getRequest() {
return this.request;
@@ -71,11 +71,6 @@ public class MockAsyncContext implements AsyncContext {
return (this.request instanceof MockHttpServletRequest) && (this.response instanceof MockHttpServletResponse);
}
public String getDispatchedPath() {
return this.dispatchedPath;
}
@Override
public void dispatch() {
dispatch(this.request.getRequestURI());
}
@@ -90,7 +85,10 @@ public class MockAsyncContext implements AsyncContext {
this.dispatchedPath = path;
}
@Override
public String getDispatchedPath() {
return this.dispatchedPath;
}
public void complete() {
MockHttpServletRequest mockRequest = WebUtils.getNativeRequest(request, MockHttpServletRequest.class);
if (mockRequest != null) {
@@ -111,11 +109,6 @@ public class MockAsyncContext implements AsyncContext {
runnable.run();
}
public List<AsyncListener> getListeners() {
return this.listeners;
}
@Override
public void addListener(AsyncListener listener) {
this.listeners.add(listener);
}
@@ -125,19 +118,20 @@ public class MockAsyncContext implements AsyncContext {
this.listeners.add(listener);
}
@Override
public List<AsyncListener> getListeners() {
return this.listeners;
}
public <T extends AsyncListener> T createListener(Class<T> clazz) throws ServletException {
return BeanUtils.instantiateClass(clazz);
}
@Override
public long getTimeout() {
return this.timeout;
}
@Override
public void setTimeout(long timeout) {
this.timeout = timeout;
}
public long getTimeout() {
return this.timeout;
}
}

View File

@@ -28,9 +28,9 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@@ -54,12 +54,9 @@ import org.springframework.util.Assert;
import org.springframework.util.LinkedCaseInsensitiveMap;
/**
* Mock implementation of the {@link javax.servlet.http.HttpServletRequest}
* interface. Supports the Servlet 2.5 API level; throws
* {@link UnsupportedOperationException} for some methods introduced in Servlet 3.0.
* Mock implementation of the {@link javax.servlet.http.HttpServletRequest} interface.
*
* <p>Used for testing the web framework; also useful for testing
* application controllers.
* <p>As of Spring 4.0, this set of mocks is entirely based on Servlet 3.0.
*
* @author Juergen Hoeller
* @author Rod Johnson
@@ -150,7 +147,13 @@ public class MockHttpServletRequest implements HttpServletRequest {
private int localPort = DEFAULT_SERVER_PORT;
private final Map<String, Part> parts = new HashMap<String, Part>();
private boolean asyncStarted = false;
private boolean asyncSupported = false;
private MockAsyncContext asyncContext;
private DispatcherType dispatcherType = DispatcherType.REQUEST;
// ---------------------------------------------------------------------
@@ -191,13 +194,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
private boolean requestedSessionIdFromURL = false;
private boolean asyncSupported = false;
private boolean asyncStarted = false;
private MockAsyncContext asyncContext;
private DispatcherType dispatcherType = DispatcherType.REQUEST;
private final Map<String, Part> parts = new LinkedHashMap<String, Part>();
// ---------------------------------------------------------------------
@@ -228,8 +225,8 @@ public class MockHttpServletRequest implements HttpServletRequest {
/**
* Create a new {@code MockHttpServletRequest} with the supplied {@link ServletContext}.
* @param servletContext the ServletContext that the request runs in (may be
* {@code null} to use a default {@link MockServletContext})
* @param servletContext the ServletContext that the request runs in
* (may be {@code null} to use a default {@link MockServletContext})
* @see #MockHttpServletRequest(ServletContext, String, String)
*/
public MockHttpServletRequest(ServletContext servletContext) {
@@ -688,10 +685,61 @@ public class MockHttpServletRequest implements HttpServletRequest {
return this.localPort;
}
@Override
public AsyncContext startAsync() {
return startAsync(this, null);
}
//---------------------------------------------------------------------
@Override
public AsyncContext startAsync(ServletRequest request, ServletResponse response) {
if (!this.asyncSupported) {
throw new IllegalStateException("Async not supported");
}
this.asyncStarted = true;
this.asyncContext = new MockAsyncContext(request, response);
return this.asyncContext;
}
public void setAsyncStarted(boolean asyncStarted) {
this.asyncStarted = asyncStarted;
}
@Override
public boolean isAsyncStarted() {
return this.asyncStarted;
}
public void setAsyncSupported(boolean asyncSupported) {
this.asyncSupported = asyncSupported;
}
@Override
public boolean isAsyncSupported() {
return this.asyncSupported;
}
public void setAsyncContext(MockAsyncContext asyncContext) {
this.asyncContext = asyncContext;
}
@Override
public AsyncContext getAsyncContext() {
return this.asyncContext;
}
public void setDispatcherType(DispatcherType dispatcherType) {
this.dispatcherType = dispatcherType;
}
@Override
public DispatcherType getDispatcherType() {
return this.dispatcherType;
}
// ---------------------------------------------------------------------
// HttpServletRequest interface
//---------------------------------------------------------------------
// ---------------------------------------------------------------------
public void setAuthType(String authType) {
this.authType = authType;
@@ -713,15 +761,15 @@ public class MockHttpServletRequest implements HttpServletRequest {
/**
* Add a header entry for the given name.
* <p>If there was no entry for that header name before,
* the value will be used as-is. In case of an existing entry,
* a String array will be created, adding the given value (more
* specifically, its toString representation) as further element.
* <p>Multiple values can only be stored as list of Strings,
* following the Servlet spec (see {@code getHeaders} accessor).
* As alternative to repeated {@code addHeader} calls for
* individual elements, you can use a single call with an entire
* array or Collection of values as parameter.
* <p>If there was no entry for that header name before, the value will be used
* as-is. In case of an existing entry, a String array will be created,
* adding the given value (more specifically, its toString representation)
* as further element.
* <p>Multiple values can only be stored as list of Strings, following the
* Servlet spec (see {@code getHeaders} accessor). As alternative to
* repeated {@code addHeader} calls for individual elements, you can
* use a single call with an entire array or Collection of values as
* parameter.
* @see #getHeaderNames
* @see #getHeader
* @see #getHeaders
@@ -972,89 +1020,35 @@ public class MockHttpServletRequest implements HttpServletRequest {
return isRequestedSessionIdFromURL();
}
//---------------------------------------------------------------------
// Methods introduced in Servlet 3.0
//---------------------------------------------------------------------
@Override
public AsyncContext getAsyncContext() {
return this.asyncContext;
}
public void setAsyncContext(MockAsyncContext asyncContext) {
this.asyncContext = asyncContext;
}
@Override
public DispatcherType getDispatcherType() {
return this.dispatcherType;
}
public void setDispatcherType(DispatcherType dispatcherType) {
this.dispatcherType = dispatcherType;
}
public void setAsyncSupported(boolean asyncSupported) {
this.asyncSupported = asyncSupported;
}
@Override
public boolean isAsyncSupported() {
return this.asyncSupported;
}
@Override
public AsyncContext startAsync() {
return startAsync(this, null);
}
@Override
public AsyncContext startAsync(ServletRequest request, ServletResponse response) {
if (!this.asyncSupported) {
throw new IllegalStateException("Async not supported");
}
this.asyncStarted = true;
this.asyncContext = new MockAsyncContext(request, response);
return this.asyncContext;
}
public void setAsyncStarted(boolean asyncStarted) {
this.asyncStarted = asyncStarted;
}
@Override
public boolean isAsyncStarted() {
return this.asyncStarted;
}
@Override
public boolean authenticate(HttpServletResponse arg0) throws IOException, ServletException {
public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
throw new UnsupportedOperationException();
}
public void addPart(Part part) {
parts.put(part.getName(), part);
}
@Override
public Part getPart(String key) throws IOException, IllegalStateException, ServletException {
return parts.get(key);
}
@Override
public Collection<Part> getParts() throws IOException, IllegalStateException, ServletException {
return parts.values();
}
@Override
public void login(String arg0, String arg1) throws ServletException {
public void login(String username, String password) throws ServletException {
throw new UnsupportedOperationException();
}
@Override
public void logout() throws ServletException {
throw new UnsupportedOperationException();
this.userPrincipal = null;
this.remoteUser = null;
this.authType = null;
}
public void addPart(Part part) {
this.parts.put(part.getName(), part);
}
@Override
public Part getPart(String name) throws IOException, IllegalStateException, ServletException {
return this.parts.get(name);
}
@Override
public Collection<Part> getParts() throws IOException, IllegalStateException, ServletException {
return this.parts.values();
}
}

View File

@@ -40,7 +40,8 @@ import org.springframework.web.util.WebUtils;
/**
* Mock implementation of the {@link javax.servlet.http.HttpServletResponse} interface.
*
* <p>Compatible with Servlet 2.5 as well as Servlet 3.0.
* <p>As of Spring 4.0, this set of mocks is designed on a Servlet 3.0 baseline. Beyond that,
* this MockHttpServletResponse is also compatible with Servlet 3.1's setContentLengthLong.
*
* @author Juergen Hoeller
* @author Rod Johnson
@@ -75,7 +76,7 @@ public class MockHttpServletResponse implements HttpServletResponse {
private PrintWriter writer;
private int contentLength = 0;
private long contentLength = 0;
private String contentType;
@@ -198,6 +199,15 @@ public class MockHttpServletResponse implements HttpServletResponse {
}
public int getContentLength() {
return (int) this.contentLength;
}
public void setContentLengthLong(long contentLength) {
this.contentLength = contentLength;
doAddHeaderValue(CONTENT_LENGTH_HEADER, contentLength, true);
}
public long getContentLengthLong() {
return this.contentLength;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@ import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
@@ -50,7 +51,22 @@ public class MockMultipartHttpServletRequest extends MockHttpServletRequest impl
new LinkedMultiValueMap<String, MultipartFile>();
/**
* Create a new {@code MockMultipartHttpServletRequest} with a default
* {@link MockServletContext}.
* @see #MockMultipartHttpServletRequest(ServletContext)
*/
public MockMultipartHttpServletRequest() {
this(null);
}
/**
* Create a new {@code MockMultipartHttpServletRequest} with the supplied {@link ServletContext}.
* @param servletContext the ServletContext that the request runs in
* (may be {@code null} to use a default {@link MockServletContext})
*/
public MockMultipartHttpServletRequest(ServletContext servletContext) {
super(servletContext);
setMethod("POST");
setContentType("multipart/form-data");
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,7 +30,6 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.activation.FileTypeMap;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
@@ -45,6 +44,7 @@ import javax.servlet.descriptor.JspConfigDescriptor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
@@ -56,13 +56,11 @@ import org.springframework.web.util.WebUtils;
/**
* Mock implementation of the {@link javax.servlet.ServletContext} interface.
*
* <p>Compatible with Servlet 2.5 and partially with Servlet 3.0 but throws
* {@link UnsupportedOperationException} for most methods introduced in Servlet
* 3.0. Can be configured to expose a specific version through
* {@link #setMajorVersion}/{@link #setMinorVersion}; default is 2.5. Note that
* Servlet 3.0 support is limited: servlet, filter and listener registration
* methods are not supported; neither is cookie or JSP configuration. We generally
* do not recommend to unit-test your ServletContainerInitializers and
* <p>Compatible with Servlet 3.0. Can be configured to expose a specific version
* through {@link #setMajorVersion}/{@link #setMinorVersion}; default is 3.0.
* Note that Servlet 3.0 support is limited: servlet, filter and listener
* registration methods are not supported; neither is JSP configuration.
* We generally do not recommend to unit-test your ServletContainerInitializers and
* WebApplicationInitializers which is where those registration methods would be used.
*
* <p>Used for testing the Spring web framework; only rarely necessary for testing
@@ -106,35 +104,49 @@ public class MockServletContext implements ServletContext {
private static final String TEMP_DIR_SYSTEM_PROPERTY = "java.io.tmpdir";
private static final Set<SessionTrackingMode> DEFAULT_SESSION_TRACKING_MODES =
new LinkedHashSet<SessionTrackingMode>(3);
static {
DEFAULT_SESSION_TRACKING_MODES.add(SessionTrackingMode.COOKIE);
DEFAULT_SESSION_TRACKING_MODES.add(SessionTrackingMode.URL);
DEFAULT_SESSION_TRACKING_MODES.add(SessionTrackingMode.SSL);
}
private final Log logger = LogFactory.getLog(getClass());
private final Map<String, ServletContext> contexts = new HashMap<String, ServletContext>();
private final Map<String, String> initParameters = new LinkedHashMap<String, String>();
private final Map<String, Object> attributes = new LinkedHashMap<String, Object>();
private final Set<String> declaredRoles = new HashSet<String>();
private final Map<String, RequestDispatcher> namedRequestDispatchers = new HashMap<String, RequestDispatcher>();
private final ResourceLoader resourceLoader;
private final String resourceBasePath;
private String contextPath = "";
private int majorVersion = 2;
private final Map<String, ServletContext> contexts = new HashMap<String, ServletContext>();
private int minorVersion = 5;
private int majorVersion = 3;
private int effectiveMajorVersion = 2;
private int minorVersion = 0;
private int effectiveMinorVersion = 5;
private int effectiveMajorVersion = 3;
private int effectiveMinorVersion = 0;
private final Map<String, RequestDispatcher> namedRequestDispatchers = new HashMap<String, RequestDispatcher>();
private String defaultServletName = COMMON_DEFAULT_SERVLET_NAME;
private final Map<String, String> initParameters = new LinkedHashMap<String, String>();
private final Map<String, Object> attributes = new LinkedHashMap<String, Object>();
private String servletContextName = "MockServletContext";
private String defaultServletName = COMMON_DEFAULT_SERVLET_NAME;
private final Set<String> declaredRoles = new HashSet<String>();
private Set<SessionTrackingMode> sessionTrackingModes;
private final SessionCookieConfig sessionCookieConfig = new MockSessionCookieConfig();
/**
@@ -203,7 +215,6 @@ public class MockServletContext implements ServletContext {
this.contextPath = (contextPath != null ? contextPath : "");
}
/* This is a Servlet API 2.5 method. */
@Override
public String getContextPath() {
return this.contextPath;
@@ -476,7 +487,7 @@ public class MockServletContext implements ServletContext {
@Override
public Enumeration<String> getAttributeNames() {
return Collections.enumeration(this.attributes.keySet());
return Collections.enumeration(new LinkedHashSet<String>(this.attributes.keySet()));
}
@Override
@@ -523,23 +534,68 @@ public class MockServletContext implements ServletContext {
return Collections.unmodifiableSet(this.declaredRoles);
}
@Override
public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
throws IllegalStateException, IllegalArgumentException {
this.sessionTrackingModes = sessionTrackingModes;
}
/**
* Inner factory class used to introduce a Java Activation Framework
* dependency when actually asked to resolve a MIME type.
*/
private static class MimeTypeResolver {
@Override
public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
return DEFAULT_SESSION_TRACKING_MODES;
}
public static String getMimeType(String filePath) {
return FileTypeMap.getDefaultFileTypeMap().getContentType(filePath);
}
@Override
public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
return (this.sessionTrackingModes != null ?
Collections.unmodifiableSet(this.sessionTrackingModes) : DEFAULT_SESSION_TRACKING_MODES);
}
@Override
public SessionCookieConfig getSessionCookieConfig() {
return this.sessionCookieConfig;
}
//---------------------------------------------------------------------
// Methods introduced in Servlet 3.0
// Unsupported Servlet 3.0 registration methods
//---------------------------------------------------------------------
@Override
public JspConfigDescriptor getJspConfigDescriptor() {
throw new UnsupportedOperationException();
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, String className) {
throw new UnsupportedOperationException();
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
throw new UnsupportedOperationException();
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass) {
throw new UnsupportedOperationException();
}
@Override
public <T extends Servlet> T createServlet(Class<T> c) throws ServletException {
throw new UnsupportedOperationException();
}
@Override
public ServletRegistration getServletRegistration(String servletName) {
throw new UnsupportedOperationException();
}
@Override
public Map<String, ? extends ServletRegistration> getServletRegistrations() {
throw new UnsupportedOperationException();
}
@Override
public FilterRegistration.Dynamic addFilter(String filterName, String className) {
throw new UnsupportedOperationException();
@@ -555,6 +611,21 @@ public class MockServletContext implements ServletContext {
throw new UnsupportedOperationException();
}
@Override
public <T extends Filter> T createFilter(Class<T> c) throws ServletException {
throw new UnsupportedOperationException();
}
@Override
public FilterRegistration getFilterRegistration(String filterName) {
throw new UnsupportedOperationException();
}
@Override
public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
throw new UnsupportedOperationException();
}
@Override
public void addListener(Class<? extends EventListener> listenerClass) {
throw new UnsupportedOperationException();
@@ -571,83 +642,20 @@ public class MockServletContext implements ServletContext {
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, String className) {
public <T extends EventListener> T createListener(Class<T> c) throws ServletException {
throw new UnsupportedOperationException();
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
throw new UnsupportedOperationException();
}
@Override
public ServletRegistration.Dynamic addServlet(String servletName,
Class<? extends Servlet> servletClass) {
throw new UnsupportedOperationException();
}
/**
* Inner factory class used to introduce a Java Activation Framework
* dependency when actually asked to resolve a MIME type.
*/
private static class MimeTypeResolver {
@Override
public <T extends Filter> T createFilter(Class<T> c)
throws ServletException {
throw new UnsupportedOperationException();
}
@Override
public <T extends EventListener> T createListener(Class<T> c)
throws ServletException {
throw new UnsupportedOperationException();
}
@Override
public <T extends Servlet> T createServlet(Class<T> c)
throws ServletException {
throw new UnsupportedOperationException();
}
@Override
public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
throw new UnsupportedOperationException();
}
@Override
public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
throw new UnsupportedOperationException();
}
@Override
public FilterRegistration getFilterRegistration(String filterName) {
throw new UnsupportedOperationException();
}
@Override
public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
throw new UnsupportedOperationException();
}
@Override
public JspConfigDescriptor getJspConfigDescriptor() {
throw new UnsupportedOperationException();
}
@Override
public ServletRegistration getServletRegistration(String servletName) {
throw new UnsupportedOperationException();
}
@Override
public Map<String, ? extends ServletRegistration> getServletRegistrations() {
throw new UnsupportedOperationException();
}
@Override
public SessionCookieConfig getSessionCookieConfig() {
throw new UnsupportedOperationException();
}
@Override
public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
throws IllegalStateException, IllegalArgumentException {
throw new UnsupportedOperationException();
public static String getMimeType(String filePath) {
return FileTypeMap.getDefaultFileTypeMap().getContentType(filePath);
}
}
}

View File

@@ -0,0 +1,101 @@
/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed 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.springframework.mock.web.test;
import javax.servlet.SessionCookieConfig;
/**
* Mock implementation of the {@link javax.servlet.SessionCookieConfig} interface.
*
* @author Juergen Hoeller
* @since 4.0
* @see javax.servlet.ServletContext#getSessionCookieConfig()
*/
public class MockSessionCookieConfig implements SessionCookieConfig {
private String name;
private String domain;
private String path;
private String comment;
private boolean httpOnly;
private boolean secure;
private int maxAge;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setDomain(String domain) {
this.domain = domain;
}
public String getDomain() {
return this.domain;
}
public void setPath(String path) {
this.path = path;
}
public String getPath() {
return this.path;
}
public void setComment(String comment) {
this.comment = comment;
}
public String getComment() {
return this.comment;
}
public void setHttpOnly(boolean httpOnly) {
this.httpOnly = httpOnly;
}
public boolean isHttpOnly() {
return this.httpOnly;
}
public void setSecure(boolean secure) {
this.secure = secure;
}
public boolean isSecure() {
return this.secure;
}
public void setMaxAge(int maxAge) {
this.maxAge = maxAge;
}
public int getMaxAge() {
return this.maxAge;
}
}