Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,43 +74,48 @@ 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<MetaMethod> respondsTo = filtersDefinition.metaClass.respondsTo(filtersDefinition, methodName, args)
List<MetaMethod> 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)
// register the metamethod to EMC
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
// whether the filter config is intialised or not. However,
// 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]"}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}


Expand Down
Original file line number Diff line number Diff line change
@@ -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() {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -124,4 +167,22 @@ class ExceptionThrowingFilters {
}
}
}
}

class AutowiredFilters {

def autowiredService

def filters = {
all(controller:"author", action:"list") {
before = {
autowiredService.setupSession()
}
}
}
}

class AutowiredService {

void setupSession() {}
}
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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") {
Expand All @@ -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"() {
Expand Down Expand Up @@ -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
Expand All @@ -110,4 +131,12 @@ class AuthenticationFilters {
}
}
}
}

@Artefact("Service")
class SecurityService {

boolean isAuthorized() {
return true
}
}