Ensure ServTEL doesn't reset ReqAttrs by accident

Prior to this commit, the ServletTestExecutionListener did not
overwrite RequestAttributes in the RequestContextHolder if the
ApplicationContext associated with the given TestContext was not a
WebApplicationContext; however, the ServletTestExecutionListener would
clear the RequestAttributes after every test method execution,
regardless of whether the context was a WebApplicationContext or not.
This behavior breaks backwards compatibility with integration tests
that managed the RequestAttributes in RequestContextHolder themselves.

This commit addresses this issue by introducing a TestContext attribute
named RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE in
ServletTestExecutionListener. This attribute is used internally within
ServletTestExecutionListener to ensure that the RequestContextHolder is
only cleared (i.e., reset) if the ServletTestExecutionListener actually
populated the RequestContextHolder.

Issue: SPR-11144
This commit is contained in:
Sam Brannen
2013-12-09 15:35:54 +01:00
parent 5f38996cd6
commit a3b022aa48
2 changed files with 152 additions and 3 deletions

View File

@@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Conventions;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.mock.web.MockServletContext;
@@ -59,6 +60,17 @@ import org.springframework.web.context.request.ServletWebRequest;
*/
public class ServletTestExecutionListener extends AbstractTestExecutionListener {
/**
* Attribute name for a {@link TestContext} attribute which indicates
* whether or not the {@code ServletTestExecutionListener} should {@linkplain
* RequestContextHolder#resetRequestAttributes() reset} Spring Web's
* {@code RequestContextHolder} in {@link #afterTestMethod(TestContext)}.
*
* <p>Permissible values include {@link Boolean#TRUE} and {@link Boolean#FALSE}.
*/
public static final String RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE = Conventions.getQualifiedAttributeName(
ServletTestExecutionListener.class, "resetRequestContextHolder");
private static final Log logger = LogFactory.getLog(ServletTestExecutionListener.class);
@@ -95,10 +107,13 @@ public class ServletTestExecutionListener extends AbstractTestExecutionListener
*/
@Override
public void afterTestMethod(TestContext testContext) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Resetting RequestContextHolder for test context %s.", testContext));
if (Boolean.TRUE.equals(testContext.getAttribute(RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE))) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Resetting RequestContextHolder for test context %s.", testContext));
}
RequestContextHolder.resetRequestAttributes();
testContext.removeAttribute(RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE);
}
RequestContextHolder.resetRequestAttributes();
}
private void setUpRequestContextIfNecessary(TestContext testContext) {
@@ -127,6 +142,7 @@ public class ServletTestExecutionListener extends AbstractTestExecutionListener
ServletWebRequest servletWebRequest = new ServletWebRequest(request, response);
RequestContextHolder.setRequestAttributes(servletWebRequest);
testContext.setAttribute(RESET_REQUEST_CONTEXT_HOLDER_ATTRIBUTE, Boolean.TRUE);
if (wac instanceof ConfigurableApplicationContext) {
@SuppressWarnings("resource")