From c14cc7099a184688f9b49368ee35dc7cdfdb3460 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 461123fca24..9b442743e96 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 @@ -74,22 +74,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) @@ -97,7 +102,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 @@ -105,12 +110,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 2677fbd10f4..4720a4835a5 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 + } } diff --git a/grails-plugin-testing/src/test/groovy/grails/test/mixin/FiltersUnitTestMixinTests.groovy b/grails-plugin-testing/src/test/groovy/grails/test/mixin/FiltersUnitTestMixinTests.groovy index 7d9b14a2f96..62aaa8a623b 100644 --- a/grails-plugin-testing/src/test/groovy/grails/test/mixin/FiltersUnitTestMixinTests.groovy +++ b/grails-plugin-testing/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 af843fdd40a..615e2ee1d51 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 @TestFor(UserController) @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"() { @@ -86,9 +99,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 @@ -110,4 +131,12 @@ class AuthenticationFilters { } } } +} + +@Artefact("Service") +class SecurityService { + + boolean isAuthorized() { + return true + } } \ No newline at end of file