Print only printable request/response body in MVC Test
Prior to this commit, PrintingResultHandler always printed the request or response body regardless of its content type. For binary content, however, the output was unreadable and therefore useless. This commit addresses this issue by only printing the request or response body if it is "printable" (i.e., if its content type is known to be text-based such as plain text, HTML, XHTML, XML, JSON, etc.). If the content type is unknown (e.g., unspecified for the HTTP request in the test), it is assumed that the body is printable. Issue: SPR-14776
This commit is contained in:
parent
7ae729480e
commit
e65a1a4372
|
|
@ -16,7 +16,9 @@
|
||||||
|
|
||||||
package org.springframework.test.web.servlet.result;
|
package org.springframework.test.web.servlet.result;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.http.Cookie;
|
import javax.servlet.http.Cookie;
|
||||||
|
|
@ -29,6 +31,8 @@ import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
import org.springframework.test.web.servlet.MvcResult;
|
import org.springframework.test.web.servlet.MvcResult;
|
||||||
import org.springframework.test.web.servlet.ResultHandler;
|
import org.springframework.test.web.servlet.ResultHandler;
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MimeType;
|
||||||
|
import org.springframework.util.MimeTypeUtils;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
|
|
@ -54,6 +58,14 @@ import org.springframework.web.servlet.support.RequestContextUtils;
|
||||||
*/
|
*/
|
||||||
public class PrintingResultHandler implements ResultHandler {
|
public class PrintingResultHandler implements ResultHandler {
|
||||||
|
|
||||||
|
private static final String NOT_PRINTABLE = "<content type is not printable text>";
|
||||||
|
|
||||||
|
private static final List<MimeType> printableMimeTypes = Arrays.asList(
|
||||||
|
MimeTypeUtils.APPLICATION_JSON, MimeTypeUtils.APPLICATION_XML,
|
||||||
|
new MimeType("text", "*"), new MimeType("application", "*+json"),
|
||||||
|
new MimeType("application", "*+xml"));
|
||||||
|
|
||||||
|
|
||||||
private final ResultValuePrinter printer;
|
private final ResultValuePrinter printer;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -103,11 +115,14 @@ public class PrintingResultHandler implements ResultHandler {
|
||||||
* Print the request.
|
* Print the request.
|
||||||
*/
|
*/
|
||||||
protected void printRequest(MockHttpServletRequest request) throws Exception {
|
protected void printRequest(MockHttpServletRequest request) throws Exception {
|
||||||
|
String body = (isPrintableContentType(request.getContentType()) ?
|
||||||
|
request.getContentAsString() : NOT_PRINTABLE);
|
||||||
|
|
||||||
this.printer.printValue("HTTP Method", request.getMethod());
|
this.printer.printValue("HTTP Method", request.getMethod());
|
||||||
this.printer.printValue("Request URI", request.getRequestURI());
|
this.printer.printValue("Request URI", request.getRequestURI());
|
||||||
this.printer.printValue("Parameters", getParamsMultiValueMap(request));
|
this.printer.printValue("Parameters", getParamsMultiValueMap(request));
|
||||||
this.printer.printValue("Headers", getRequestHeaders(request));
|
this.printer.printValue("Headers", getRequestHeaders(request));
|
||||||
this.printer.printValue("Body", request.getContentAsString());
|
this.printer.printValue("Body", body);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final HttpHeaders getRequestHeaders(MockHttpServletRequest request) {
|
protected final HttpHeaders getRequestHeaders(MockHttpServletRequest request) {
|
||||||
|
|
@ -223,11 +238,14 @@ public class PrintingResultHandler implements ResultHandler {
|
||||||
* Print the response.
|
* Print the response.
|
||||||
*/
|
*/
|
||||||
protected void printResponse(MockHttpServletResponse response) throws Exception {
|
protected void printResponse(MockHttpServletResponse response) throws Exception {
|
||||||
|
String body = (isPrintableContentType(response.getContentType()) ?
|
||||||
|
response.getContentAsString() : NOT_PRINTABLE);
|
||||||
|
|
||||||
this.printer.printValue("Status", response.getStatus());
|
this.printer.printValue("Status", response.getStatus());
|
||||||
this.printer.printValue("Error message", response.getErrorMessage());
|
this.printer.printValue("Error message", response.getErrorMessage());
|
||||||
this.printer.printValue("Headers", getResponseHeaders(response));
|
this.printer.printValue("Headers", getResponseHeaders(response));
|
||||||
this.printer.printValue("Content type", response.getContentType());
|
this.printer.printValue("Content type", response.getContentType());
|
||||||
this.printer.printValue("Body", response.getContentAsString());
|
this.printer.printValue("Body", body);
|
||||||
this.printer.printValue("Forwarded URL", response.getForwardedUrl());
|
this.printer.printValue("Forwarded URL", response.getForwardedUrl());
|
||||||
this.printer.printValue("Redirected URL", response.getRedirectedUrl());
|
this.printer.printValue("Redirected URL", response.getRedirectedUrl());
|
||||||
printCookies(response.getCookies());
|
printCookies(response.getCookies());
|
||||||
|
|
@ -266,6 +284,23 @@ public class PrintingResultHandler implements ResultHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the supplied content type is <em>printable</em> (i.e., text-based).
|
||||||
|
* <p>If the supplied content type is {@code null} (i.e., unknown), this method
|
||||||
|
* assumes that the content is printable by default and returns {@code true}.
|
||||||
|
* @param contentType the content type to check; {@code null} if unknown
|
||||||
|
* @return {@code true} if the content type is known to be or assumed to be printable
|
||||||
|
* @since 5.0
|
||||||
|
*/
|
||||||
|
private static boolean isPrintableContentType(String contentType) {
|
||||||
|
if (contentType == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
MimeType mimeType = MimeType.valueOf(contentType);
|
||||||
|
return printableMimeTypes.stream().anyMatch(printable -> printable.includes(mimeType));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A contract for how to actually write result information.
|
* A contract for how to actually write result information.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,9 @@
|
||||||
package org.springframework.test.web.servlet.result;
|
package org.springframework.test.web.servlet.result;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.http.Cookie;
|
import javax.servlet.http.Cookie;
|
||||||
|
|
@ -31,6 +33,7 @@ import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
import org.springframework.test.web.servlet.StubMvcResult;
|
import org.springframework.test.web.servlet.StubMvcResult;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MimeTypeUtils;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.validation.BindException;
|
import org.springframework.validation.BindException;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
|
|
@ -50,6 +53,11 @@ import static org.junit.Assert.*;
|
||||||
*/
|
*/
|
||||||
public class PrintingResultHandlerTests {
|
public class PrintingResultHandlerTests {
|
||||||
|
|
||||||
|
private static final List<String> textContentTypes = Arrays.asList(MimeTypeUtils.APPLICATION_JSON_VALUE,
|
||||||
|
MimeTypeUtils.APPLICATION_XML_VALUE, MimeTypeUtils.APPLICATION_XHTML_XML_VALUE,
|
||||||
|
MimeTypeUtils.TEXT_HTML_VALUE, MimeTypeUtils.TEXT_PLAIN_VALUE);
|
||||||
|
|
||||||
|
|
||||||
private final TestPrintingResultHandler handler = new TestPrintingResultHandler();
|
private final TestPrintingResultHandler handler = new TestPrintingResultHandler();
|
||||||
|
|
||||||
private final MockHttpServletRequest request = new MockHttpServletRequest("GET", "/") {
|
private final MockHttpServletRequest request = new MockHttpServletRequest("GET", "/") {
|
||||||
|
|
@ -82,7 +90,6 @@ public class PrintingResultHandlerTests {
|
||||||
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
|
||||||
params.add("param", "paramValue");
|
params.add("param", "paramValue");
|
||||||
|
|
||||||
|
|
||||||
assertValue("MockHttpServletRequest", "HTTP Method", this.request.getMethod());
|
assertValue("MockHttpServletRequest", "HTTP Method", this.request.getMethod());
|
||||||
assertValue("MockHttpServletRequest", "Request URI", this.request.getRequestURI());
|
assertValue("MockHttpServletRequest", "Request URI", this.request.getRequestURI());
|
||||||
assertValue("MockHttpServletRequest", "Parameters", params);
|
assertValue("MockHttpServletRequest", "Parameters", params);
|
||||||
|
|
@ -139,6 +146,46 @@ public class PrintingResultHandlerTests {
|
||||||
assertTrue(cookie2.endsWith("]"));
|
assertTrue(cookie2.endsWith("]"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void printRequestWithTextContentTypes() throws Exception {
|
||||||
|
this.request.setContent("text".getBytes());
|
||||||
|
|
||||||
|
for (String contentType: textContentTypes) {
|
||||||
|
this.request.setContentType(contentType);
|
||||||
|
this.handler.handle(this.mvcResult);
|
||||||
|
assertValue("MockHttpServletRequest", "Body", "text");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void printResponseWithTextContentTypes() throws Exception {
|
||||||
|
this.response.getWriter().print("text");
|
||||||
|
|
||||||
|
for (String contentType: textContentTypes) {
|
||||||
|
this.response.setContentType(contentType);
|
||||||
|
this.handler.handle(this.mvcResult);
|
||||||
|
assertValue("MockHttpServletResponse", "Body", "text");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void printRequestWithBinaryContentType() throws Exception {
|
||||||
|
this.request.setContentType(MimeTypeUtils.IMAGE_JPEG_VALUE);
|
||||||
|
|
||||||
|
this.handler.handle(this.mvcResult);
|
||||||
|
|
||||||
|
assertValue("MockHttpServletRequest", "Body", "<content type is not printable text>");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void printResponseWithBinaryContentType() throws Exception {
|
||||||
|
this.response.setContentType(MimeTypeUtils.IMAGE_JPEG_VALUE);
|
||||||
|
|
||||||
|
this.handler.handle(this.mvcResult);
|
||||||
|
|
||||||
|
assertValue("MockHttpServletResponse", "Body", "<content type is not printable text>");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void printHandlerNull() throws Exception {
|
public void printHandlerNull() throws Exception {
|
||||||
StubMvcResult mvcResult = new StubMvcResult(this.request, null, null, null, null, null, this.response);
|
StubMvcResult mvcResult = new StubMvcResult(this.request, null, null, null, null, null, this.response);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue