-
Notifications
You must be signed in to change notification settings - Fork 38k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Spring MVC Test framework never stores more than one cookie [SPR-13166] #17757
Comments
Sam Brannen commented Hi Chris, How are you setting the cookies in the response? If one of them is being set by a Servlet Cheers, Sam |
Sam Brannen commented FYI: there is nothing wrong with public void addCookie(Cookie cookie) {
Assert.notNull(cookie, "Cookie must not be null");
this.cookies.add(cookie);
} Thus, the problem must lie within the internals of Spring MVC Test (unless you forgot to add a required |
Sam Brannen commented Regarding the rendering of the cookies in |
Chris Beams commented Thanks Sam. The cookies in question are JSESSIONID (which I've renamed to "session") and the one set by Spring Security's csrf support (which I've renamed to "csrf"). Take a look at this gist: https://gist.github.com/cbeams/f3c3e3002118b44694b4#file-tomcatconfigtests-java-L25-L27 Notice that I'm using Both of these cookies are set by filters that Spring Security manages. What else would there be for me to do? Notice the order of the cookie headers coming back:
Notice that |
Sam Brannen commented Interesting. Out of curiosity, what happens if you execute something like the following in your test (excluding the expectation that currently fails)? ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
MockHttpServletResponse mockResponse = (MockHttpServletResponse) requestAttributes.getResponse();
assertEquals(2, mockResponse.getCookies().length); Or... if you inspect the contents of that |
Chris Beams commented The updated test: @Test
public void shouldSetCustomizedSessionCookie() throws Exception {
http.perform(get("/"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(cookie().exists("csrf"))
.andExpect(cookie().doesNotExist("JSESSIONID"))
//.andExpect(cookie().exists("session"))
;
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
MockHttpServletResponse mockResponse = (MockHttpServletResponse) requestAttributes.getResponse();
assertEquals(2, mockResponse.getCookies().length);
} And the result:
|
Rossen Stoyanchev commented What Spring MVC Test does to access cookies is dead simple see here. I think the issue is not related to access or asserting expectations. There is something else going on where the expected cookie is not added when running with Spring MVC Test. To confirm I just did a simple test with a controller adding two cookies and I had no trouble asserting that both exist with /cc robwinch |
Sam Brannen commented Thanks for updating the test, Chris. I just wanted to rule out the possibility that one of the cookies was being set via the So your test in fact rules that out. |
Rossen Stoyanchev commented Chris, in the original comment "jsessionid" is missing. In fact I don't see what would set that since this is not running in a Servlet container. However in the referenced gist the code is asserting the opposite that "jsessionid" doesn't exist, which makes more sense but then you're checking "session". Can you clarify? Regarding "jsessionid" I presume the gist is the correct version. Also what is the "session" cookie and what's supposed to set that? |
Rob Winch commented Thanks for the report Chris. I created two instances of a CookieFilter (which adds a cookie to the response) and added them to Spring Security's Filters. When running the test with MockMvc it seems to work for me. See rwinch/spring-security-sample/SRP-13116 Like Rossen, I'm curious about the JSESSIONID vs the session cookie differences. I'm also wondering are you using Spring Session? Spring Session is added outside of Spring Security, so you would need to add that to MockMvc separately. |
Chris Beams commented Ok, it looks like I'm confused about the way things work with MVC Test. Rossen, the "session" cookie is Tomcat's usual JSESSIONID cookie, just renamed: @Configuration
static class TomcatConfig {
@Bean
public EmbeddedServletContainerFactory tomcat() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
tomcat.addContextCustomizers(context -> context.setSessionCookieName("session"));
return tomcat;
}
} The source of my confusion is summed up by your quote above: "... this is not running in a Servlet container". I actually thought it was wiring everything up with the same embedded tomcat configuration that is in use at actual runtime. Since that is not the case, this issue is invalid. Feel free to close it. Perhaps these limitations could be mentioned a bit more prominently in the documentation? The current docs do mention that MVC Test makes end-to-end testing "without needing to run a servlet container", but it also says " For the most part everything should work as it does at runtime with the exception of JSP rendering, which is not available outside a Servlet container." Assumptions about session cookies would be another "something that doesn't work", as well as the workarounds necessary to I guess the point is that the way MVC Test "feels" to the user is that they really are working against a fully wired up webapp. It "feels" like the container is there, even though it's not. This means that these assumptions about all the usual filters and cookies, etc being there are natural to make, and a surprise every time they're violated. An early heads-up to check those assumptions at the door might be helpful. In any case, thanks everyone for the quick responses! |
Sam Brannen commented Ok, Chris, we'll close this issue and create follow-up tickets to improve the documentation on the limitations of Spring MVC Test (see #17760) and to improve the debug output for cookies (see #17759).
I think you are possibly confusing Spring MVC Test's out-of-container testing support with Spring Boot's in-container testing support. Using In contrast, with Spring Boot... if you use Make sense? |
Chris Beams commented Thanks Sam—I actually hadn't worked with |
Rossen Stoyanchev commented Okay thanks for the feedback. Improving the documentation on that point, perhaps even mentioning Spring Boot's The question of Spring MVC Test vs Also with Spring MVC Test you're conceptually on the inside on the server-side so we know what handler was used, if an exception was handled with a HandlerExceptionResolver, we have access to the model, etc. It means you can make assertions on the kinds of things you couldn't when using a REST client in which case the server is a black box. Or you might say that one should avoid looking at anything but the response, otherwise the tests are fragile. I think there is room here for multiple styles and schools of thought. |
Sam Brannen commented All very valid points, Rossen, and ...
Yes... I couldn't agree more. ;) |
Sam Brannen commented Chris Beams, I baked you some pretty cookies in #17759. Is that better now? ;) |
Chris Beams commented Very nice! Thanks. |
Chris Beams opened SPR-13166 and commented
Scenario
An HTTP response contains multiple
Set-Cookie
headers, e.g.:Problem
Spring MVC Test only stores the last cookie seen:
The output from the
print()
above tells the tale:Note that the
Cookies
array contains only a single entry, where it should have two. (and it would be nice by the way, if the cookie entries themselves were rendered in a friendlier way).Affects: 4.2 RC1
Issue Links:
The text was updated successfully, but these errors were encountered: