diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvc.java b/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvc.java index 1eb6536690d..91ee692adab 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvc.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/MockMvc.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2015 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. @@ -26,6 +26,8 @@ import org.springframework.mock.web.MockFilterChain; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.util.Assert; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; /** * Main entry point for server-side Spring MVC test support. @@ -48,6 +50,7 @@ import org.springframework.util.Assert; * * @author Rossen Stoyanchev * @author Rob Winch + * @author Sam Brannen * @since 3.2 */ public final class MockMvc { @@ -140,6 +143,10 @@ public final class MockMvc { final MvcResult mvcResult = new DefaultMvcResult(request, response); request.setAttribute(MVC_RESULT_ATTRIBUTE, mvcResult); + // [SPR-13217] Simulate RequestContextFilter to ensure that RequestAttributes are + // populated before filters are invoked. + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request, response)); + MockFilterChain filterChain = new MockFilterChain(this.servlet, this.filters); filterChain.doFilter(request, response); diff --git a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/spr/RequestContextHolderTests.java b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/spr/RequestContextHolderTests.java index 3d7af1a4709..c0f8210e419 100644 --- a/spring-test/src/test/java/org/springframework/test/web/servlet/samples/spr/RequestContextHolderTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/servlet/samples/spr/RequestContextHolderTests.java @@ -22,7 +22,6 @@ import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; import org.junit.Before; import org.junit.Test; @@ -57,7 +56,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*; /** - * Tests for SPR-10025 (access to request attributes via RequestContextHolder) + * Tests for SPR-10025 (access to request attributes via RequestContextHolder), + * SPR-13217 (Populate RequestAttributes before invoking Filters in MockMvc), * and SPR-13211 (re-use of mock request from the TestContext framework). * * @author Rossen Stoyanchev @@ -72,9 +72,8 @@ public class RequestContextHolderTests { private static final String FROM_TCF_MOCK = "fromTestContextFrameworkMock"; private static final String FROM_MVC_TEST_DEFAULT = "fromSpringMvcTestDefault"; private static final String FROM_MVC_TEST_MOCK = "fromSpringMvcTestMock"; - private static final String FROM_FILTER = "fromFilter"; - - private static final String ENIGMA = "puzzle"; + private static final String FROM_REQUEST_FILTER = "fromRequestFilter"; + private static final String FROM_REQUEST_ATTRIBUTES_FILTER = "fromRequestAttributesFilter"; @Autowired private WebApplicationContext wac; @@ -91,41 +90,44 @@ public class RequestContextHolderTests { @Autowired private SessionScopedService sessionScopedService; + @Autowired + private FilterWithSessionScopedService filterWithSessionScopedService; + private MockMvc mockMvc; @Before public void setup() { - this.mockRequest.setAttribute(FROM_TCF_MOCK, ENIGMA); + this.mockRequest.setAttribute(FROM_TCF_MOCK, FROM_TCF_MOCK); this.mockMvc = webAppContextSetup(this.wac) - .addFilter(new AbcFilter()) - .defaultRequest(get("/").requestAttr(FROM_MVC_TEST_DEFAULT, ENIGMA)) + .addFilters(new RequestFilter(), new RequestAttributesFilter(), this.filterWithSessionScopedService) + .defaultRequest(get("/").requestAttr(FROM_MVC_TEST_DEFAULT, FROM_MVC_TEST_DEFAULT)) .alwaysExpect(status().isOk()) .build(); } @Test public void singletonController() throws Exception { - this.mockMvc.perform(get("/singletonController").requestAttr(FROM_MVC_TEST_MOCK, ENIGMA)); + this.mockMvc.perform(get("/singletonController").requestAttr(FROM_MVC_TEST_MOCK, FROM_MVC_TEST_MOCK)); } @Test public void requestScopedController() throws Exception { assertTrue("request-scoped controller must be a CGLIB proxy", AopUtils.isCglibProxy(this.requestScopedController)); - this.mockMvc.perform(get("/requestScopedController").requestAttr(FROM_MVC_TEST_MOCK, ENIGMA)); + this.mockMvc.perform(get("/requestScopedController").requestAttr(FROM_MVC_TEST_MOCK, FROM_MVC_TEST_MOCK)); } @Test public void requestScopedService() throws Exception { assertTrue("request-scoped service must be a CGLIB proxy", AopUtils.isCglibProxy(this.requestScopedService)); - this.mockMvc.perform(get("/requestScopedService").requestAttr(FROM_MVC_TEST_MOCK, ENIGMA)); + this.mockMvc.perform(get("/requestScopedService").requestAttr(FROM_MVC_TEST_MOCK, FROM_MVC_TEST_MOCK)); } @Test public void sessionScopedService() throws Exception { assertTrue("session-scoped service must be a CGLIB proxy", AopUtils.isCglibProxy(this.sessionScopedService)); - this.mockMvc.perform(get("/sessionScopedService").requestAttr(FROM_MVC_TEST_MOCK, ENIGMA)); + this.mockMvc.perform(get("/sessionScopedService").requestAttr(FROM_MVC_TEST_MOCK, FROM_MVC_TEST_MOCK)); } @@ -167,6 +169,11 @@ public class RequestContextHolderTests { public ControllerWithSessionScopedService controllerWithSessionScopedService() { return new ControllerWithSessionScopedService(); } + + @Bean + public FilterWithSessionScopedService filterWithSessionScopedService() { + return new FilterWithSessionScopedService(); + } } @RestController @@ -182,7 +189,7 @@ public class RequestContextHolderTests { private static class RequestScopedController { @Autowired - private HttpServletRequest request; + private ServletRequest request; @RequestMapping("/requestScopedController") @@ -195,7 +202,7 @@ public class RequestContextHolderTests { private static class RequestScopedService { @Autowired - private HttpServletRequest request; + private ServletRequest request; void process() { @@ -206,7 +213,7 @@ public class RequestContextHolderTests { private static class SessionScopedService { @Autowired - private HttpServletRequest request; + private ServletRequest request; void process() { @@ -242,11 +249,35 @@ public class RequestContextHolderTests { } } - private static class AbcFilter extends GenericFilterBean { + private static class FilterWithSessionScopedService extends GenericFilterBean { + + @Autowired + private SessionScopedService service; + @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - request.setAttribute(FROM_FILTER, ENIGMA); + this.service.process(); + assertRequestAttributes(request); + assertRequestAttributes(); + chain.doFilter(request, response); + } + } + + private static class RequestFilter extends GenericFilterBean { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + request.setAttribute(FROM_REQUEST_FILTER, FROM_REQUEST_FILTER); + chain.doFilter(request, response); + } + } + + private static class RequestAttributesFilter extends GenericFilterBean { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + RequestContextHolder.getRequestAttributes().setAttribute(FROM_REQUEST_ATTRIBUTES_FILTER, FROM_REQUEST_ATTRIBUTES_FILTER, RequestAttributes.SCOPE_REQUEST); chain.doFilter(request, response); } } @@ -258,13 +289,13 @@ public class RequestContextHolderTests { assertRequestAttributes(((ServletRequestAttributes) requestAttributes).getRequest()); } - private static void assertRequestAttributes(HttpServletRequest request) { - // TODO [SPR-13211] Assert that FOO is ENIGMA, instead of NULL. - // assertThat(this.request.getAttribute(FOO), is(ENIGMA)); + private static void assertRequestAttributes(ServletRequest request) { + // TODO [SPR-13211] Assert that FROM_TCF_MOCK is FROM_TCF_MOCK, instead of NULL. assertThat(request.getAttribute(FROM_TCF_MOCK), is(nullValue())); - assertThat(request.getAttribute(FROM_MVC_TEST_DEFAULT), is(ENIGMA)); - assertThat(request.getAttribute(FROM_MVC_TEST_MOCK), is(ENIGMA)); - assertThat(request.getAttribute(FROM_FILTER), is(ENIGMA)); + assertThat(request.getAttribute(FROM_MVC_TEST_DEFAULT), is(FROM_MVC_TEST_DEFAULT)); + assertThat(request.getAttribute(FROM_MVC_TEST_MOCK), is(FROM_MVC_TEST_MOCK)); + assertThat(request.getAttribute(FROM_REQUEST_FILTER), is(FROM_REQUEST_FILTER)); + assertThat(request.getAttribute(FROM_REQUEST_ATTRIBUTES_FILTER), is(FROM_REQUEST_ATTRIBUTES_FILTER)); } }