Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
539 lines (449 sloc) 14.7 KB
/* Copyright 2008 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.codehaus.groovy.grails.plugins.testing
import grails.artefact.ApiDelegate
import grails.converters.JSON
import grails.converters.XML
import javax.servlet.http.HttpServletRequest
import org.codehaus.groovy.grails.plugins.web.api.RequestMimeTypesApi
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes
import org.codehaus.groovy.grails.web.util.WebUtils
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
import org.springframework.mock.web.MockHttpServletRequest
import org.springframework.util.Assert
import org.springframework.util.LinkedMultiValueMap
import org.springframework.util.MultiValueMap
import org.springframework.web.multipart.MultipartFile
import org.springframework.web.multipart.MultipartHttpServletRequest
import javax.servlet.DispatcherType
import javax.servlet.http.Part
import javax.servlet.AsyncContext
import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest
import javax.servlet.http.HttpServletResponse
import javax.servlet.AsyncEvent
import javax.servlet.AsyncListener
import javax.servlet.ServletRequest
import javax.servlet.ServletResponse
/**
* A custom mock HTTP servlet request that provides the extra properties
* and methods normally injected by the "servlets" plugin.
*/
class GrailsMockHttpServletRequest extends MockHttpServletRequest implements MultipartHttpServletRequest{
@ApiDelegate(HttpServletRequest) RequestMimeTypesApi requestMimeTypesApi = new RequestMimeTypesApi()
boolean invalidToken
MultiValueMap multipartFiles = new LinkedMultiValueMap<String, MultipartFile>();
private Map<String, String> multipartContentTypes = Collections.emptyMap();
private Map<String, HttpHeaders> multipartHeaders = Collections.emptyMap();
private HttpHeaders httpHeaders = new HttpHeaders();
private String requestHeaders = null;
private HttpMethod requestMethod = HttpMethod.GET;
private cachedJson
private cachedXml
javax.servlet.DispatcherType dispatcherType;
AsyncContext asyncContext;
/**
* Sets the request format to use
* @param format The request format
*/
void setFormat(String format) {
setAttribute(GrailsApplicationAttributes.CONTENT_FORMAT, format)
}
/**
* Sets the body of the request to be a json packet
*
* @param sourceJson The source json
*/
void setJson(Object sourceJson) {
setContentType('application/json')
setFormat('json')
if (sourceJson instanceof String) {
setContent(sourceJson.bytes)
}
else if (sourceJson instanceof JSON) {
setContent(sourceJson.toString().bytes)
}
else {
setContent(new JSON(sourceJson).toString().bytes)
}
getAttribute("org.codehaus.groovy.grails.WEB_REQUEST")?.informParameterCreationListeners()
}
/**
* Sets the body of the request to be an XML packet
*
* @param sourceXml
*/
void setXml(Object sourceXml) {
setContentType("text/xml")
setFormat("xml")
if (sourceXml instanceof String) {
setContent(sourceXml.bytes)
}
else {
XML xml = new XML(sourceXml);
setContent(xml.toString().bytes)
}
getAttribute("org.codehaus.groovy.grails.WEB_REQUEST")?.informParameterCreationListeners()
}
void setXML(Object sourceXml) {
setXml(sourceXml)
}
void setJSON(Object sourceJson) {
setJson(sourceJson)
}
/**
* Implementation of the dynamic "forwardURI" property.
*/
String getForwardURI() {
def result = getAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE)
if (!result) result = requestURI
return result
}
/**
* Sets the "forwardURI" property for the request.
*/
void setForwardURI(String uri) {
setAttribute(WebUtils.FORWARD_REQUEST_URI_ATTRIBUTE, uri)
}
/**
* Indicates whether this is an AJAX request or not (as far as
* Grails is concerned). Returns <code>true</code> if it is an
* AJAX request, otherwise <code>false</code>.
*/
boolean isXhr() {
return getHeader("X-Requested-With") == "XMLHttpRequest"
}
/**
* Makes this request an AJAX request as Grails understands it.
* This cannot be undone, so if you need a non-AJAX request you
* will have to create a new instance.
*/
void makeAjaxRequest() {
addHeader("X-Requested-With", "XMLHttpRequest")
}
/**
* Map-like access to request attributes, e.g. request["count"].
*/
def getAt(String key) {
return getAttribute(key)
}
/**
* Map-like setting of request attributes, e.g. request["count"] = 10.
*/
void putAt(String key, Object val) {
setAttribute(key, val)
}
/**
* Property access for request attributes.
*/
def getProperty(String name) {
def mp = getClass().metaClass.getMetaProperty(name)
return mp ? mp.getProperty(this) : getAttribute(name)
}
/**
* Property setting of request attributes.
*/
void setProperty(String name, value) {
def mp = getClass().metaClass.getMetaProperty(name)
if (mp) {
mp.setProperty(this, value)
}
else {
setAttribute(name, value)
}
}
boolean isGet() { method == "GET" }
boolean isPost() { method == "POST" }
/**
* Parses the request content as XML using XmlSlurper and returns
* the GPath result object. Throws an exception if there is no
* content or the content is not valid XML.
*/
def getXML() {
if (!cachedXml) {
cachedXml = GrailsMockHttpServletRequest.classLoader.loadClass("grails.converters.XML").parse(this)
}
return cachedXml
}
/**
* Parses the request content as JSON using the JSON converter.
* Throws an exception if there is no content or the content is
* not valid JSON.
*/
def getJSON() {
if (!cachedJson) {
cachedJson = GrailsMockHttpServletRequest.classLoader.loadClass("grails.converters.JSON").parse(this)
}
return cachedJson
}
/**
* Adds a "find()" method to the request that searches the request's
* attributes. Returns the first attribute for which the closure
* returns <code>true</code>, just like the normal Groovy find() method.
*/
def find(Closure c) {
def result = [:]
for (String name in attributeNames) {
def match = false
switch (c.parameterTypes.length) {
case 0:
match = c.call()
break
case 1:
match = c.call(key:name, value:getAttribute(name))
break
default:
match = c.call(name, getAttribute(name))
}
if (match) {
result[name] = getAttribute(name)
break
}
}
return result
}
/**
* Like the {@link #find(Closure)} method, this searches the request
* attributes. Returns all the attributes that match the closure
* conditions.
*/
def findAll(Closure c) {
def results = [:]
for (String name in attributeNames) {
def match = false
switch (c.parameterTypes.length) {
case 0:
match = c.call()
break
case 1:
match = c.call(key:name, value:getAttribute(name))
break
default:
match = c.call(name, getAttribute(name))
}
if (match) { results[name] = getAttribute(name) }
}
results
}
/**
* Iterates over the request attributes.
*/
def each(Closure c) {
for (String name in attributeNames) {
switch (c.parameterTypes.length) {
case 0:
c.call()
break
case 1:
c.call(key:name, value:getAttribute(name))
break
default:
c.call(name, getAttribute(name))
}
}
}
/**
* {@inheritDoc }
*/
Iterator<String> getFileNames() {
return multipartFiles.keySet().iterator()
}
/**
* {@inheritDoc }
*/
MultipartFile getFile(String name) {
return multipartFiles.getFirst(name)
}
/**
* {@inheritDoc }
*/
List<MultipartFile> getFiles(String name) {
return multipartFiles.get(name)
}
/**
* {@inheritDoc }
*/
Map<String, MultipartFile> getFileMap() {
return multipartFiles
}
/**
* {@inheritDoc }
*/
MultiValueMap<String, MultipartFile> getMultiFileMap() {
return multipartFiles
}
/**
* Add a file to this request. The parameter name from the multipart
* form is taken from the {@link MultipartFile#getName()}.
* @param file multipart file to be added
*/
void addFile(MultipartFile file) {
setMethod("POST");
setContentType("multipart/form-data");
Assert.notNull(file, "MultipartFile must not be null");
multipartFiles.add(file.getName(), file);
}
/**
* Add a file for the given location and bytes
*
* @param location The location
* @param contents The bytes
*/
void addFile(String location, byte[] contents) {
setMethod("POST");
setContentType("multipart/form-data");
multipartFiles.add(location, new GrailsMockMultipartFile(location, contents));
}
@Override
void clearAttributes() {
super.clearAttributes()
multipartFiles.clear();
multipartContentTypes.clear();
httpHeaders.clear();
}
String getMultipartContentType(String paramOrFileName) {
return multipartContentTypes.get(paramOrFileName);
}
String setMultipartContentType(String paramOrFileName, String contentType) {
return multipartContentTypes.put(paramOrFileName, contentType);
}
HttpHeaders getMultipartHeaders(String paramOrFileName) {
return multipartHeaders.get(paramOrFileName);
}
HttpHeaders setMultipartHeaders(String paramOrFileName, HttpHeaders headers) {
return multipartHeaders.put(paramOrFileName, headers);
}
HttpHeaders getRequestHeaders() {
return requestHeaders;
}
void setRequestHeaders(HttpHeaders headers) {
requestHeaders = headers;
}
HttpMethod getRequestMethod() {
return requestMethod;
}
HttpMethod setRequestMethod(HttpMethod method) {
requestMethod = method;
}
Collection<javax.servlet.http.Part> getParts() {
getFileMap().values().collect {new MockPart(it)}
}
javax.servlet.http.Part getPart(String name) {
MultipartFile file = getFile(name)
if(file) {
return new MockPart(file)
}
}
javax.servlet.AsyncContext startAsync() {
def webRequest = GrailsWebRequest.lookup()
def response = webRequest?.currentResponse
if(response == null) {
response = new GrailsMockHttpServletResponse()
}
startAsync(this,response)
}
javax.servlet.AsyncContext startAsync(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) {
return new MockAsyncContext(servletRequest, servletResponse)
}
boolean isAsyncStarted() { asyncContext != null }
boolean isAsyncSupported() { true }
}
class MockPart implements Part {
MultipartFile file
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>()
MockPart(MultipartFile file) {
this.file = file
}
InputStream getInputStream() {
file.inputStream
}
String getContentType() {
file.contentType
}
String getName() {
file.name
}
long getSize() {
file.size
}
void write(String fileName) {
file.transferTo(new File(fileName))
}
void delete() {
// no-op
}
String getHeader(String name) {
return headers.getFirst(name)
}
Collection<String> getHeaders(String name) {
return headers[name]
}
Collection<String> getHeaderNames() {
return headers.keySet()
}
}
class MockAsyncContext implements AsyncContext {
ServletRequest request
ServletResponse response
String dispatchUri
long timeout = -1
List asyncListeners = []
MockAsyncContext(HttpServletRequest request, HttpServletResponse response) {
this.request = request
this.response = response
}
boolean hasOriginalRequestAndResponse() {
return true
}
void dispatch() {
dispatchUri = request.requestURI
}
void dispatch(String path) {
dispatchUri = path
}
void dispatch(javax.servlet.ServletContext context, String path) {
dispatchUri = path
}
void complete() {
// no op
}
void start(Runnable run) {
try {
for(listener in asyncListeners) {
AsyncListener al = listener.listener
al.onStartAsync(listener.event)
}
run.run()
for(listener in asyncListeners) {
AsyncListener al = listener.listener
al.onComplete(listener.event)
}
} catch (e) {
for(listener in asyncListeners) {
AsyncListener al = listener.listener
al.onError(new AsyncEvent(this, e))
}
}
}
void addListener(javax.servlet.AsyncListener listener) {
asyncListeners << [listener:listener, event:new AsyncEvent(this, request, response)]
}
void addListener(javax.servlet.AsyncListener listener, javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) {
asyncListeners << [listener:listener, event:new AsyncEvent(this, servletRequest, servletResponse)]
}
def <T extends javax.servlet.AsyncListener> T createListener(Class<T> clazz) {
return clazz.newInstance()
}
}
Jump to Line
Something went wrong with that request. Please try again.