Использование FiltersUnitTestCase для модульного тестирования фильтров безопасности Shiro, IllegalStateException
Update : я изменил этот вопрос, чтобы он касался конкретной проблемы, с которой я сталкиваюсь. Это связано с тем, что модульное тестирование фильтров будет поддерживаться в Grails 2.0, так что, надеюсь, документация будет лучше.
Я пытаюсь написать модульные тесты для фильтров, которые я настроил для реализации безопасности Shiro в моем приложении grails. Я использую Grails 1.3.7 и некоторое время не смогу использовать 2.0 (если вообще смогу) для этого конкретного проекта.
Идея моего фильтра заключается в том, что мне нужно дайте анонимный доступ к номеру или комбинации контроллер/действие, но защитите доступ к другим. Я также хочу, чтобы он был безопасным, т. е. если вы забыли явно разрешить доступ, то доступ запрещен.
Класс фильтров
class SecurityFilters {
def filters = {
homeAccess(controller: "home", action: "*") {
before = {
// Allow all access
request.accessAllowed = true
}
}
serverAccess(controller: "server", action: "list") {
before = {
// Allow all access
request.accessAllowed = true
}
}
layerAccess(controller: "layer", action: "list|listBaseLayersAsJson|listNonBaseLayerAsJson|showLayerByItsId") {
before = {
// Allow all access
request.accessAllowed = true
}
}
all(uri: "/**") {
before = {
// Check if request has been allowed by another filter
if (request.accessAllowed) return true
// Ignore direct views (e.g. the default main index page).
if (!controllerName) return true
// Access control by convention.
accessControl(auth: false)
}
}
}
}
Модульные тесты
import org.codehaus.groovy.grails.plugins.web.filters.FilterConfig
class SecurityFiltersTests extends FiltersUnitTestCase {
protected void setUp() {
super.setUp()
}
protected void tearDown() {
super.tearDown()
}
void testHomeControllerFilter() {
checkFilter('homeAccess')
}
void testServerControllerFilter() {
checkFilter('serverAccess')
}
void testLayerControllerFilter() {
checkFilter('layerAccess')
}
void testAllFilter() {
assertTrue "Write tests", false
}
void checkFilter(String filterName) {
FilterConfig filter = initFilter(filterName)
assertNotNull filterName + " filter should exist", filter
assertExistsBefore(filterName)
assertEquals "accessAllowed should be null to start with", null, filter.request.accessAllowed
// Run filter
filter.before()
assertEquals "accessAllowed should be true now", true, filter.request.accessAllowed
}
}
Исключение
Проблема заключается в том, что при выполнении этих тестов я получаю следующее исключение:
No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at grails.test.MockUtils$_addCommonWebProperties_closure32.doCall(MockUtils.groovy:316)
at shiro.SecurityFilters$_closure1_closure5_closure12.doCall(SecurityFilters.groovy:40)
at shiro.SecurityFilters$_closure1_closure5_closure12.doCall(SecurityFilters.groovy)
at shiro.SecurityFiltersTests.checkFilter(SecurityFiltersTests.groovy:92)
at shiro.SecurityFiltersTests$checkFilter.callCurrent(Unknown Source)
at shiro.SecurityFiltersTests.testLayerControllerFilter(SecurityFiltersTests.groovy:65)
Дополнительно я поместил в блок следующую строку тест:
println "filter.request: " + filter.request
Который выводит следующее:
filter.request: org.codehaus.groovy.grails.plugins.testing.GrailsMockHttpServletRequest@2914cca4
Таким образом, он, безусловно, использует объект mock request.
Итак, вопросы.
Правильно ли я использую FiltersUnitTestCase для выполнения моих фильтров?
И, если это так:
Почему я испытываю это исключение?
1 ответ:
Напоминание о правилах отладки для всех: продолжайте удалять код, пока не найдете точную строку, на которой находится проблема. Даже если очевидно, что линия не является причиной проблемы. потому что: иногда это действительно .
В рамках моей отладочной работы у меня была следующая строка кода в моем фильтре:
println "controllerName = '${controllerName}', actionName = '${actionName}'"
Это было непосредственно перед строкой:
request.accessAllowed = true
Я взял его из кода, вставленного в этот вопрос, чтобы попытаться сохранить его аккуратно, но, очевидно, я не пытался комментировать это, когда проводил тесты. Извините всех, кто заглянул в этот код и не смог найти проблему. Вы были правы, проблема не была ни в одном из кодов, которые я предоставил.
Таким образом, ответ вы можете увидеть исключение, сообщенное здесь, если попытаетесь получить доступ к переменным
controllerName
илиactionName
.Решение заключается в использовании методов
setControllerName()
иsetActionName()
в FiltersUnitTestCase перед выполнением любого фильтра, который может ссылаться наcontrollerName
илиactionName
.