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
MockMvc ignores HTTP status code overridden by filter [SPR-11760] #16382
Comments
Sam Brannen commented It looks like you simply forgot to register your To do that, invoke the For example:
Please give that a try and let us know if it addresses your issue. Thanks, Sam |
Gena Makhomed commented
No, I register it:
Also, in unit-test log you can see debug output from filter:
Fragment of controller source-code:
And in unit test log I can see filter in stack trace of logged exception:
|
Rossen Stoyanchev commented I see no (obvious) reason why this shouldn't work. Please provide a sample project here and I'll debug it. |
Gena Makhomed commented Ok, I create pull request. Filter HttpStatusOverrideFilter works fine in MockMvc and Servlet Conatiner only if present several filters, no matter first or last filter HttpStatusOverrideFilter will be. In case if only one filter HttpStatusOverrideFilter present - bug observed in MockMvc and in Servlet Conatiner too. I provide three tests - one failed and two works fine with HttpStatusOverrideFilter and HttpDumperFilter in any order. Looks like this bug is not in P.S. For convenience full debug log of unit test will be written in target/test.log file. |
Rossen Stoyanchev commented I had a look at the repro project. The HttpStatusOverrideFilter tries to change the status at the end but it is too late when the response is committed. Writing content to the response and flushing for example causes the response to be committed. Or it can happen if you write more content than the servlet response buffer can fit. Essentially it means the server has already told the client what the response status is, so you can no longer change it. The reason having HttpDumperFilter makes a difference is because it wraps the response and overrides flushing. However that's more of a side effect. If you really want to set the status at the end, you have to wrap the response and buffer the response body. See for example how our At any rate this is expected behavior. |
Gena Makhomed commented You are right, it was bug in my code, sorry for inconvenience. Feature request: add to MockMvc ability to detect such bugs in user code during unit-testing with unambiguous diagnostics. It will be very useful for finding and detecting such bugs in user code. Finding bugs in user code is the main purpose of JUnit and MockMvc, as I understand. Extend ResponseEntity not help, because can work only with fixed list of HTTP Status Codes. This limitation of ResponseEntity is one and only one reason, why I need create own filter for setting non-standard HTTP Status Codes with Spring MVC Controllers. Simplest solution is to have ResponseEntity constructors not only with enum HttpStatus argument, but also with int argument. But in current version of Spring this is impossible even by extending (only one) ResponseEntity class, internally enum HttpStatus used in Spring Framework almost on all levels, the lowest level is @Override
public void setStatusCode(HttpStatus status) {
this.servletResponse.setStatus(status.value());
} |
Gena Makhomed commented |
Rossen Stoyanchev commented Regarding diagnostics in MockMvc, have you tried adding an Regarding ResponseEntity, there is actually now (in master and therefore 4.1) a proper solution for this. Take a look at #15486. |
Gena Makhomed commented
#15486 ResponseBodyInterceptor does not help, because Servlet API does not contain methods for removing response headers, so if I add header X-HTTP-Status-Override to response - this header also will be send to client. HttpStatusOverrideFilter do all what I need without garbage in server reply and without necessity to parse/modify response body, so HttpStatusOverrideFilter still is the best possible solution. |
Rossen Stoyanchev commented I think ResponseBodyInterceptor would help actually. Your input their is not the HttpServletResponse but a wrapper called ServletServerHttpRequest which contains HttpHeaders. Those headers are not written to the underlying HttpServletResponse until you start writing to the body or call flush. So you can still remove headers and change the response status. As for the ISE on attempts to write to the response. It's something we may be able to enable as an option. I.e. you would have to explicitly choose to enter in this mode. |
Rossen Stoyanchev commented
I just confirmed that works as expected. |
Gena Makhomed opened SPR-11760 and commented
The full source code for
HttpStatusOverrideFilter
is available in the attachment.In production env., all works fine, but when I use JUnit +
MockMvc
, the HTTP Status Code overridden by my filter gets ignored.Test code fragment:
Controller code fragment:
In the production env., the filter works fine, and the HTTP status code is 230. With JUnit +
MockMvc
, the HTTP status code is 500, and the assertion fails.Looks like this is bug in
MockMvc
.Unit-test log fragment:
Affects: 4.0.4
Attachments:
Issue Links:
@ResponseBody
The text was updated successfully, but these errors were encountered: