From 0e597db04deb4dfbf82a589bd32f2ffd70972989 Mon Sep 17 00:00:00 2001 From: John Engelman Date: Wed, 10 Apr 2013 10:31:28 -0500 Subject: [PATCH] GRAILS-8976 enable autowiring of Filters during unit test --- .../plugins/web/filters/FilterConfig.groovy | 19 +++--- .../mixin/web/FiltersUnitTestMixin.groovy | 5 +- .../mixin/FiltersUnitTestMixinTests.groovy | 61 +++++++++++++++++++ .../web/filters/FiltersUnitTestSpec.groovy | 29 +++++++++ 4 files changed, 106 insertions(+), 8 deletions(-) diff --git a/grails-plugin-filters/src/main/groovy/org/codehaus/groovy/grails/plugins/web/filters/FilterConfig.groovy b/grails-plugin-filters/src/main/groovy/org/codehaus/groovy/grails/plugins/web/filters/FilterConfig.groovy index 32b65cd1d38..0ce68800cac 100644 --- a/grails-plugin-filters/src/main/groovy/org/codehaus/groovy/grails/plugins/web/filters/FilterConfig.groovy +++ b/grails-plugin-filters/src/main/groovy/org/codehaus/groovy/grails/plugins/web/filters/FilterConfig.groovy @@ -75,22 +75,27 @@ class FilterConfig extends ControllersApi { */ def propertyMissing(String propertyName) { // Delegate to the parent definition if it has this property. - if (filtersDefinition.metaClass.hasProperty(filtersDefinition, propertyName)) { + if (wiredFiltersDefinition.metaClass.hasProperty(wiredFiltersDefinition, propertyName)) { def getterName = GrailsClassUtils.getGetterName(propertyName) - metaClass."$getterName" = {-> delegate.filtersDefinition.getProperty(propertyName) } - return filtersDefinition."$propertyName" + metaClass."$getterName" = {-> delegate.wiredFiltersDefinition.getProperty(propertyName) } + return wiredFiltersDefinition."$propertyName" } throw new MissingPropertyException(propertyName, filtersDefinition.getClass()) } + def getWiredFiltersDefinition() { + final grailsFilter = grailsApplication.getArtefact(FiltersConfigArtefactHandler.TYPE, filtersDefinition.class.name) + applicationContext."${grailsFilter.fullName}" + } + /** * When the filter does not have a particular method, it passes * the call on to the filter definition class. */ def methodMissing(String methodName, args) { // Delegate to the parent definition if it has this method. - List respondsTo = filtersDefinition.metaClass.respondsTo(filtersDefinition, methodName, args) + List respondsTo = wiredFiltersDefinition.metaClass.respondsTo(wiredFiltersDefinition, methodName, args) if (respondsTo) { // Use DelegateMetaMethod to proxy calls to actual MetaMethod for subsequent calls to this method DelegateMetaMethod dmm=new DelegateMetaMethod(respondsTo[0], FilterConfigDelegateMetaMethodTargetStrategy.instance) @@ -98,7 +103,7 @@ class FilterConfig extends ControllersApi { metaClass.registerInstanceMethod(dmm) // for this invocation we still have to make the call - return respondsTo[0].invoke(filtersDefinition, args) + return respondsTo[0].invoke(wiredFiltersDefinition, args) } // Ideally, we would throw a MissingMethodException here @@ -106,12 +111,12 @@ class FilterConfig extends ControllersApi { // if it's in the initialisation phase, the MME gets swallowed somewhere. if (!initialised) { throw new IllegalStateException( - "Invalid filter definition in ${filtersDefinition.getClass().name} - trying " + "Invalid filter definition in ${wiredFiltersDefinition.getClass().name} - trying " + "to call method '${methodName}' outside of an interceptor.") } // The required method was not found on the parent filter definition either. - throw new MissingMethodException(methodName, filtersDefinition.getClass(), args) + throw new MissingMethodException(methodName, wiredFiltersDefinition.getClass(), args) } String toString() {"FilterConfig[$name, scope=$scope]"} diff --git a/grails-plugin-testing/src/main/groovy/grails/test/mixin/web/FiltersUnitTestMixin.groovy b/grails-plugin-testing/src/main/groovy/grails/test/mixin/web/FiltersUnitTestMixin.groovy index 35cacdcc39d..161d4673e4a 100644 --- a/grails-plugin-testing/src/main/groovy/grails/test/mixin/web/FiltersUnitTestMixin.groovy +++ b/grails-plugin-testing/src/main/groovy/grails/test/mixin/web/FiltersUnitTestMixin.groovy @@ -86,7 +86,10 @@ class FiltersUnitTestMixin extends ControllerUnitTestMixin { arguments = [FiltersConfigArtefactHandler.TYPE, grailsFilter.fullName] } - "$grailsFilter.fullName"(grailsFilter.clazz) + "$grailsFilter.fullName"(grailsFilter.clazz) { bean -> + bean.scope = 'prototype' + bean.autowire = true + } } FiltersGrailsPlugin.reloadFilters(grailsApplication, applicationContext) diff --git a/grails-test-suite-uber/src/test/groovy/grails/test/mixin/FiltersUnitTestMixinTests.groovy b/grails-test-suite-uber/src/test/groovy/grails/test/mixin/FiltersUnitTestMixinTests.groovy index 7d9b14a2f96..62aaa8a623b 100644 --- a/grails-test-suite-uber/src/test/groovy/grails/test/mixin/FiltersUnitTestMixinTests.groovy +++ b/grails-test-suite-uber/src/test/groovy/grails/test/mixin/FiltersUnitTestMixinTests.groovy @@ -1,13 +1,16 @@ package grails.test.mixin +import grails.test.GrailsMock import grails.test.mixin.web.FiltersUnitTestMixin import org.junit.Before import org.junit.Test +import org.springframework.beans.factory.config.MethodInvokingFactoryBean @TestMixin(FiltersUnitTestMixin) class FiltersUnitTestMixinTests { AuthorController controller + GrailsMock autowiredServiceMock @Before void setUp() { @@ -72,6 +75,46 @@ class FiltersUnitTestMixinTests { assert request.filterView == null assert request.exception != null } + + @Test + void testFilterIsAutoWired() { + defineBeans { + autowiredService(MethodInvokingFactoryBean) { + targetObject = this + targetMethod = 'mockAutowiredService' + } + } + mockFilters(AutowiredFilters) + + withFilters(action:"list") { + controller.list() + } + + autowiredServiceMock.verify() + } + + @Test + void testFilterIsAutoWiredWithBeansDefinedAfterMocking() { + mockFilters(AutowiredFilters) + defineBeans { + autowiredService(MethodInvokingFactoryBean) { + targetObject = this + targetMethod = 'mockAutowiredService' + } + } + + withFilters(action:"list") { + controller.list() + } + + autowiredServiceMock.verify() + } + + AutowiredService mockAutowiredService() { + this.autowiredServiceMock = mockFor(AutowiredService) + this.autowiredServiceMock.demand.setupSession(1) {} + return this.autowiredServiceMock.createMock() + } } class AuthorController { @@ -124,4 +167,22 @@ class ExceptionThrowingFilters { } } } +} + +class AutowiredFilters { + + def autowiredService + + def filters = { + all(controller:"author", action:"list") { + before = { + autowiredService.setupSession() + } + } + } +} + +class AutowiredService { + + void setupSession() {} } \ No newline at end of file diff --git a/grails-test-suite-web/src/test/groovy/org/codehaus/groovy/grails/web/filters/FiltersUnitTestSpec.groovy b/grails-test-suite-web/src/test/groovy/org/codehaus/groovy/grails/web/filters/FiltersUnitTestSpec.groovy index 9dcd7d6333d..d18c31e2161 100644 --- a/grails-test-suite-web/src/test/groovy/org/codehaus/groovy/grails/web/filters/FiltersUnitTestSpec.groovy +++ b/grails-test-suite-web/src/test/groovy/org/codehaus/groovy/grails/web/filters/FiltersUnitTestSpec.groovy @@ -1,5 +1,7 @@ package org.codehaus.groovy.grails.web.filters +import org.springframework.beans.factory.config.MethodInvokingFactoryBean + import javax.servlet.http.HttpServletResponse import grails.artefact.Artefact import grails.test.mixin.TestFor @@ -10,7 +12,17 @@ import spock.lang.Specification @Mock(AuthenticationFilters) class FiltersUnitTestSpec extends Specification { + SecurityService securityServiceMock + void "test filters are applied for a unit test"() { + given:"A mock for the injected security service" + securityServiceMock = Mock(SecurityService) + defineBeans { + securityService(MethodInvokingFactoryBean) { + targetObject = this + targetMethod = 'getSecurityServiceMock' + } + } when:"A filter is used around a controller" params.username = '' withFilters(action: "create") { @@ -19,6 +31,7 @@ class FiltersUnitTestSpec extends Specification { } then:"Check that the filter logic is applied" 400 == response.status + 1 * securityServiceMock.isAuthorized() >> true } void "test filters relay exceptions"() { @@ -84,9 +97,17 @@ class UserController { @Artefact("Filters") class AuthenticationFilters { + + def securityService + def filters = { create(controller: 'user', action: 'create') { before = { + if (!securityService.isAuthorized()) { + render(status: HttpServletResponse.SC_UNAUTHORIZED) + return false + } + if (params.username == '') { render(status: HttpServletResponse.SC_BAD_REQUEST) return false @@ -109,3 +130,11 @@ class AuthenticationFilters { } } } + +@Artefact("Service") +class SecurityService { + + boolean isAuthorized() { + return true + } +}