Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

fix for GRAILS-8258 "Unit test with Async in Grails 2.0.0.RC1"

  • Loading branch information...
commit 99bc89db7a48604643a8cc6c3469c8c1087dc74d 1 parent 342b7de
@graemerocher graemerocher authored
View
6 ...nc/src/main/groovy/org/codehaus/groovy/grails/plugins/web/async/GrailsAsyncContext.groovy
@@ -42,7 +42,11 @@ class GrailsAsyncContext implements AsyncContext {
GrailsAsyncContext(AsyncContext delegate, GrailsWebRequest webRequest) {
this.delegate = delegate
originalWebRequest = webRequest
- groovyPageLayoutFinder = webRequest.getApplicationContext()?.getBean("groovyPageLayoutFinder", GroovyPageLayoutFinder)
+ def applicationContext = webRequest.getApplicationContext()
+ if(applicationContext && applicationContext.containsBean("groovyPageLayoutFinder")) {
+
+ groovyPageLayoutFinder = applicationContext.getBean("groovyPageLayoutFinder", GroovyPageLayoutFinder)
+ }
}
def <T extends AsyncListener> T createListener(Class<T> tClass) {
View
1  grails-test-suite-web/build.gradle
@@ -12,6 +12,7 @@ dependencies {
project(':grails-plugin-datasource'),
project(':grails-plugin-i18n'),
project(':grails-plugin-servlets'),
+ project(':grails-plugin-async'),
project(':grails-plugin-log4j'),
project(':grails-plugin-url-mappings'),
project(':grails-plugin-services'),
View
28 grails-test-suite-web/src/test/groovy/grails/test/web/AsyncControllerTestSpec.groovy
@@ -0,0 +1,28 @@
+package grails.test.web
+
+import spock.lang.Specification
+import grails.artefact.Artefact
+import grails.test.mixin.TestFor
+
+/**
+ */
+@TestFor(FooController)
+class AsyncControllerTestSpec extends Specification{
+ void "Test that it is possible to test interaction with the Servlet 3.0 async API"() {
+ when:"A controller that uses the async API is called"
+ controller.index()
+ then:"The async response is testable"
+ response.text == 'Hello World'
+ }
+}
+@Artefact("Controller")
+class FooController {
+
+ def index() {
+ def ctx = startAsync()
+ ctx.start {
+ render "Hello World"
+ ctx.complete()
+ }
+ }
+}
View
5 ...e-web/src/test/groovy/org/codehaus/groovy/grails/web/taglib/ApplicationTagLibTests.groovy
@@ -406,8 +406,3 @@ class ApplicationTagLibTests extends AbstractGrailsTagTests {
}
-class JsessionIdMockHttpServletResponse extends MockHttpServletResponse {
- String encodeURL(String url) {
- super.encodeURL("$url;jsessionid=test")
- }
-}
View
9 .../test/groovy/org/codehaus/groovy/grails/web/taglib/JsessionIdMockHttpServletResponse.java
@@ -0,0 +1,9 @@
+package org.codehaus.groovy.grails.web.taglib;
+
+import org.springframework.mock.web.MockHttpServletResponse;
+
+public class JsessionIdMockHttpServletResponse extends MockHttpServletResponse {
+ public String encodeURL(String url) {
+ return super.encodeURL(url + ";jsessionid=test");
+ }
+}
View
4 ...ting/GrailsMockHttpServletResponse.groovy → ...tractGrailsMockHttpServletResponse.groovy
@@ -30,7 +30,7 @@ import org.springframework.util.ReflectionUtils
* Simple sub-class of Spring's MockHttpServletResponse that adds the
* left-shift operator, "<<".
*/
-class GrailsMockHttpServletResponse extends MockHttpServletResponse {
+abstract class AbstractGrailsMockHttpServletResponse extends MockHttpServletResponse {
@ApiDelegate(HttpServletResponse) ResponseMimeTypesApi responseMimeTypesApi = new ResponseMimeTypesApi()
@@ -109,4 +109,6 @@ class GrailsMockHttpServletResponse extends MockHttpServletResponse {
return super.getRedirectedUrl()
}
+
+
}
View
158 ...ain/groovy/org/codehaus/groovy/grails/plugins/testing/GrailsMockHttpServletRequest.groovy
@@ -31,6 +31,15 @@ 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
@@ -41,7 +50,7 @@ class GrailsMockHttpServletRequest extends MockHttpServletRequest implements Mul
@ApiDelegate(HttpServletRequest) RequestMimeTypesApi requestMimeTypesApi = new RequestMimeTypesApi()
boolean invalidToken
- MultiValueMap<String, MultipartFile> multipartFiles = new LinkedMultiValueMap<String, MultipartFile>();
+ MultiValueMap multipartFiles = new LinkedMultiValueMap<String, MultipartFile>();
private Map<String, String> multipartContentTypes = Collections.emptyMap();
private Map<String, HttpHeaders> multipartHeaders = Collections.emptyMap();
@@ -51,6 +60,8 @@ class GrailsMockHttpServletRequest extends MockHttpServletRequest implements Mul
private cachedJson
private cachedXml
+ javax.servlet.DispatcherType dispatcherType;
+ AsyncContext asyncContext;
/**
* Sets the request format to use
@@ -380,4 +391,149 @@ class GrailsMockHttpServletRequest extends MockHttpServletRequest implements Mul
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()
+ }
+
+
+}
View
27 ...main/groovy/org/codehaus/groovy/grails/plugins/testing/GrailsMockHttpServletResponse.java
@@ -0,0 +1,27 @@
+/* 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 java.util.Collection;
+import java.util.Set;
+
+/**
+ * Refer to the groovydoc of {@link GrailsMockHttpServletResponse} for further information
+ *
+ * @author Graeme Rocher
+ * @since 2.1
+ */
+ public class GrailsMockHttpServletResponse extends AbstractGrailsMockHttpServletResponse{
+ }
View
75 grails-web/src/main/groovy/grails/gsp/PageRenderer.groovy
@@ -214,6 +214,31 @@ class PageRenderer implements ApplicationContextAware, ServletContextAware{
boolean isRequestedSessionIdFromUrl() { false }
+ @Override
+ boolean authenticate(HttpServletResponse response) {
+ return false
+ }
+
+ @Override
+ void login(String username, String password) {
+ // no op
+ }
+
+ @Override
+ void logout() {
+ // no op
+ }
+
+ @Override
+ Collection<javax.servlet.http.Part> getParts() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ javax.servlet.http.Part getPart(String name) {
+ return null
+ }
+
Object getAttribute(String name) {
return attributes[name]
}
@@ -313,6 +338,40 @@ class PageRenderer implements ApplicationContextAware, ServletContextAware{
int getLocalPort() {
return 80
}
+
+ ServletContext getServletContext() {
+ return null //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ javax.servlet.AsyncContext startAsync() {
+ return null //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ javax.servlet.AsyncContext startAsync(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) {
+ return null //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ boolean isAsyncStarted() {
+ return false //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ boolean isAsyncSupported() {
+ return false //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ javax.servlet.AsyncContext getAsyncContext() {
+ return null //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+ @Override
+ javax.servlet.DispatcherType getDispatcherType() {
+ return null //To change body of implemented methods use File | Settings | File Templates.
+ }
}
class PageRenderResponse implements HttpServletResponse {
@@ -385,6 +444,22 @@ class PageRenderer implements ApplicationContextAware, ServletContextAware{
// no-op
}
+ int getStatus() {
+ return 0
+ }
+
+ String getHeader(String name) {
+ return null
+ }
+
+ Collection<String> getHeaders(String name) {
+ return null
+ }
+
+ Collection<String> getHeaderNames() {
+ return Collections.emptyList();
+ }
+
ServletOutputStream getOutputStream() {
throw new UnsupportedOperationException("You cannot use the OutputStream in non-request rendering operations. Use getWriter() instead")
}
Please sign in to comment.
Something went wrong with that request. Please try again.