|
|
@ -19,9 +19,12 @@ package org.springframework.web; |
|
|
|
import java.util.Arrays; |
|
|
|
import java.util.Arrays; |
|
|
|
import java.util.Collections; |
|
|
|
import java.util.Collections; |
|
|
|
import java.util.List; |
|
|
|
import java.util.List; |
|
|
|
|
|
|
|
import java.util.Locale; |
|
|
|
|
|
|
|
|
|
|
|
import org.junit.jupiter.api.Test; |
|
|
|
import org.junit.jupiter.api.Test; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import org.springframework.beans.testfixture.beans.TestBean; |
|
|
|
|
|
|
|
import org.springframework.context.support.StaticMessageSource; |
|
|
|
import org.springframework.core.MethodParameter; |
|
|
|
import org.springframework.core.MethodParameter; |
|
|
|
import org.springframework.http.HttpHeaders; |
|
|
|
import org.springframework.http.HttpHeaders; |
|
|
|
import org.springframework.http.HttpMethod; |
|
|
|
import org.springframework.http.HttpMethod; |
|
|
@ -32,7 +35,6 @@ import org.springframework.lang.Nullable; |
|
|
|
import org.springframework.util.LinkedMultiValueMap; |
|
|
|
import org.springframework.util.LinkedMultiValueMap; |
|
|
|
import org.springframework.validation.BindException; |
|
|
|
import org.springframework.validation.BindException; |
|
|
|
import org.springframework.validation.BindingResult; |
|
|
|
import org.springframework.validation.BindingResult; |
|
|
|
import org.springframework.validation.FieldError; |
|
|
|
|
|
|
|
import org.springframework.web.bind.MethodArgumentNotValidException; |
|
|
|
import org.springframework.web.bind.MethodArgumentNotValidException; |
|
|
|
import org.springframework.web.bind.MissingMatrixVariableException; |
|
|
|
import org.springframework.web.bind.MissingMatrixVariableException; |
|
|
|
import org.springframework.web.bind.MissingPathVariableException; |
|
|
|
import org.springframework.web.bind.MissingPathVariableException; |
|
|
@ -46,13 +48,13 @@ import org.springframework.web.multipart.support.MissingServletRequestPartExcept |
|
|
|
import org.springframework.web.server.MethodNotAllowedException; |
|
|
|
import org.springframework.web.server.MethodNotAllowedException; |
|
|
|
import org.springframework.web.server.MissingRequestValueException; |
|
|
|
import org.springframework.web.server.MissingRequestValueException; |
|
|
|
import org.springframework.web.server.NotAcceptableStatusException; |
|
|
|
import org.springframework.web.server.NotAcceptableStatusException; |
|
|
|
|
|
|
|
import org.springframework.web.server.ServerErrorException; |
|
|
|
import org.springframework.web.server.UnsatisfiedRequestParameterException; |
|
|
|
import org.springframework.web.server.UnsatisfiedRequestParameterException; |
|
|
|
import org.springframework.web.server.UnsupportedMediaTypeStatusException; |
|
|
|
import org.springframework.web.server.UnsupportedMediaTypeStatusException; |
|
|
|
import org.springframework.web.testfixture.method.ResolvableMethod; |
|
|
|
import org.springframework.web.testfixture.method.ResolvableMethod; |
|
|
|
|
|
|
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Unit tests that verify the HTTP response details exposed by exceptions in the |
|
|
|
* Unit tests that verify the HTTP response details exposed by exceptions in the |
|
|
|
* {@link ErrorResponse} hierarchy. |
|
|
|
* {@link ErrorResponse} hierarchy. |
|
|
@ -71,12 +73,12 @@ public class ErrorResponseExceptionTests { |
|
|
|
List<MediaType> mediaTypes = |
|
|
|
List<MediaType> mediaTypes = |
|
|
|
Arrays.asList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_CBOR); |
|
|
|
Arrays.asList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_CBOR); |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new HttpMediaTypeNotSupportedException( |
|
|
|
HttpMediaTypeNotSupportedException ex = new HttpMediaTypeNotSupportedException( |
|
|
|
MediaType.APPLICATION_XML, mediaTypes, HttpMethod.PATCH, "Custom message"); |
|
|
|
MediaType.APPLICATION_XML, mediaTypes, HttpMethod.PATCH, "Custom message"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.UNSUPPORTED_MEDIA_TYPE); |
|
|
|
assertStatus(ex, HttpStatus.UNSUPPORTED_MEDIA_TYPE); |
|
|
|
assertDetail(ex, "Content-Type 'application/xml' is not supported."); |
|
|
|
assertDetail(ex, "Content-Type 'application/xml' is not supported."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getContentType(), ex.getSupportedMediaTypes()}); |
|
|
|
|
|
|
|
|
|
|
|
HttpHeaders headers = ex.getHeaders(); |
|
|
|
HttpHeaders headers = ex.getHeaders(); |
|
|
|
assertThat(headers.getAccept()).isEqualTo(mediaTypes); |
|
|
|
assertThat(headers.getAccept()).isEqualTo(mediaTypes); |
|
|
@ -89,9 +91,10 @@ public class ErrorResponseExceptionTests { |
|
|
|
ErrorResponse ex = new HttpMediaTypeNotSupportedException( |
|
|
|
ErrorResponse ex = new HttpMediaTypeNotSupportedException( |
|
|
|
"Could not parse Accept header: Invalid mime type \"foo\": does not contain '/'"); |
|
|
|
"Could not parse Accept header: Invalid mime type \"foo\": does not contain '/'"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.UNSUPPORTED_MEDIA_TYPE); |
|
|
|
assertStatus(ex, HttpStatus.UNSUPPORTED_MEDIA_TYPE); |
|
|
|
assertDetail(ex, "Could not parse Content-Type."); |
|
|
|
assertDetail(ex, "Could not parse Content-Type."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, "parseError", null); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -99,11 +102,11 @@ public class ErrorResponseExceptionTests { |
|
|
|
void httpMediaTypeNotAcceptableException() { |
|
|
|
void httpMediaTypeNotAcceptableException() { |
|
|
|
|
|
|
|
|
|
|
|
List<MediaType> mediaTypes = Arrays.asList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_CBOR); |
|
|
|
List<MediaType> mediaTypes = Arrays.asList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_CBOR); |
|
|
|
ErrorResponse ex = new HttpMediaTypeNotAcceptableException(mediaTypes); |
|
|
|
HttpMediaTypeNotAcceptableException ex = new HttpMediaTypeNotAcceptableException(mediaTypes); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.NOT_ACCEPTABLE); |
|
|
|
assertStatus(ex, HttpStatus.NOT_ACCEPTABLE); |
|
|
|
assertDetail(ex, "Acceptable representations: 'application/json, application/cbor'."); |
|
|
|
assertDetail(ex, "Acceptable representations: [application/json, application/cbor]."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getSupportedMediaTypes()}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).hasSize(1); |
|
|
|
assertThat(ex.getHeaders()).hasSize(1); |
|
|
|
assertThat(ex.getHeaders().getAccept()).isEqualTo(mediaTypes); |
|
|
|
assertThat(ex.getHeaders().getAccept()).isEqualTo(mediaTypes); |
|
|
@ -115,9 +118,10 @@ public class ErrorResponseExceptionTests { |
|
|
|
ErrorResponse ex = new HttpMediaTypeNotAcceptableException( |
|
|
|
ErrorResponse ex = new HttpMediaTypeNotAcceptableException( |
|
|
|
"Could not parse Accept header: Invalid mime type \"foo\": does not contain '/'"); |
|
|
|
"Could not parse Accept header: Invalid mime type \"foo\": does not contain '/'"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.NOT_ACCEPTABLE); |
|
|
|
assertStatus(ex, HttpStatus.NOT_ACCEPTABLE); |
|
|
|
assertDetail(ex, "Could not parse Accept header."); |
|
|
|
assertDetail(ex, "Could not parse Accept header."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, "parseError", null); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -125,22 +129,23 @@ public class ErrorResponseExceptionTests { |
|
|
|
void asyncRequestTimeoutException() { |
|
|
|
void asyncRequestTimeoutException() { |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new AsyncRequestTimeoutException(); |
|
|
|
ErrorResponse ex = new AsyncRequestTimeoutException(); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, null); |
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.SERVICE_UNAVAILABLE); |
|
|
|
assertStatus(ex, HttpStatus.SERVICE_UNAVAILABLE); |
|
|
|
assertDetail(ex, null); |
|
|
|
assertDetail(ex, null); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void httpRequestMethodNotSupportedException() { |
|
|
|
void httpRequestMethodNotSupportedException() { |
|
|
|
|
|
|
|
|
|
|
|
String[] supportedMethods = new String[] { "GET", "POST" }; |
|
|
|
HttpRequestMethodNotSupportedException ex = |
|
|
|
ErrorResponse ex = new HttpRequestMethodNotSupportedException("PUT", supportedMethods, "Custom message"); |
|
|
|
new HttpRequestMethodNotSupportedException("PUT", Arrays.asList("GET", "POST")); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.METHOD_NOT_ALLOWED); |
|
|
|
assertStatus(ex, HttpStatus.METHOD_NOT_ALLOWED); |
|
|
|
assertDetail(ex, "Method 'PUT' is not supported."); |
|
|
|
assertDetail(ex, "Method 'PUT' is not supported."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getMethod(), ex.getSupportedHttpMethods()}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).hasSize(1); |
|
|
|
assertThat(ex.getHeaders()).hasSize(1); |
|
|
|
assertThat(ex.getHeaders().getAllow()).containsExactly(HttpMethod.GET, HttpMethod.POST); |
|
|
|
assertThat(ex.getHeaders().getAllow()).containsExactly(HttpMethod.GET, HttpMethod.POST); |
|
|
@ -149,90 +154,101 @@ public class ErrorResponseExceptionTests { |
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void missingRequestHeaderException() { |
|
|
|
void missingRequestHeaderException() { |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new MissingRequestHeaderException("Authorization", this.methodParameter); |
|
|
|
MissingRequestHeaderException ex = new MissingRequestHeaderException("Authorization", this.methodParameter); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertDetail(ex, "Required header 'Authorization' is not present."); |
|
|
|
assertDetail(ex, "Required header 'Authorization' is not present."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getHeaderName()}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void missingServletRequestParameterException() { |
|
|
|
void missingServletRequestParameterException() { |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new MissingServletRequestParameterException("query", "String"); |
|
|
|
MissingServletRequestParameterException ex = new MissingServletRequestParameterException("query", "String"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertDetail(ex, "Required parameter 'query' is not present."); |
|
|
|
assertDetail(ex, "Required parameter 'query' is not present."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getParameterName()}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void missingMatrixVariableException() { |
|
|
|
void missingMatrixVariableException() { |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new MissingMatrixVariableException("region", this.methodParameter); |
|
|
|
MissingMatrixVariableException ex = new MissingMatrixVariableException("region", this.methodParameter); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertDetail(ex, "Required path parameter 'region' is not present."); |
|
|
|
assertDetail(ex, "Required path parameter 'region' is not present."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getVariableName()}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void missingPathVariableException() { |
|
|
|
void missingPathVariableException() { |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new MissingPathVariableException("id", this.methodParameter); |
|
|
|
MissingPathVariableException ex = new MissingPathVariableException("id", this.methodParameter); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.INTERNAL_SERVER_ERROR); |
|
|
|
assertStatus(ex, HttpStatus.INTERNAL_SERVER_ERROR); |
|
|
|
assertDetail(ex, "Required path variable 'id' is not present."); |
|
|
|
assertDetail(ex, "Required path variable 'id' is not present."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getVariableName()}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void missingRequestCookieException() { |
|
|
|
void missingRequestCookieException() { |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new MissingRequestCookieException("oreo", this.methodParameter); |
|
|
|
MissingRequestCookieException ex = new MissingRequestCookieException("oreo", this.methodParameter); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertDetail(ex, "Required cookie 'oreo' is not present."); |
|
|
|
assertDetail(ex, "Required cookie 'oreo' is not present."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getCookieName()}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void unsatisfiedServletRequestParameterException() { |
|
|
|
void unsatisfiedServletRequestParameterException() { |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new UnsatisfiedServletRequestParameterException( |
|
|
|
UnsatisfiedServletRequestParameterException ex = new UnsatisfiedServletRequestParameterException( |
|
|
|
new String[] { "foo=bar", "bar=baz" }, Collections.singletonMap("q", new String[] {"1"})); |
|
|
|
new String[] { "foo=bar", "bar=baz" }, Collections.singletonMap("q", new String[] {"1"})); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertDetail(ex, "Invalid request parameters."); |
|
|
|
assertDetail(ex, "Invalid request parameters."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {List.of("\"foo=bar, bar=baz\"")}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void missingServletRequestPartException() { |
|
|
|
void missingServletRequestPartException() { |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new MissingServletRequestPartException("file"); |
|
|
|
MissingServletRequestPartException ex = new MissingServletRequestPartException("file"); |
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertDetail(ex, "Required part 'file' is not present."); |
|
|
|
assertDetail(ex, "Required part 'file' is not present."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getRequestPartName()}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void methodArgumentNotValidException() { |
|
|
|
void methodArgumentNotValidException() { |
|
|
|
|
|
|
|
|
|
|
|
BindingResult bindingResult = new BindException(new Object(), "object"); |
|
|
|
MessageSourceTestHelper messageSourceHelper = new MessageSourceTestHelper(MethodArgumentNotValidException.class); |
|
|
|
bindingResult.addError(new FieldError("object", "field", "message")); |
|
|
|
BindingResult bindingResult = messageSourceHelper.initBindingResult(); |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new MethodArgumentNotValidException(this.methodParameter, bindingResult); |
|
|
|
ErrorResponse ex = new MethodArgumentNotValidException(this.methodParameter, bindingResult); |
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertDetail(ex, "Invalid request content."); |
|
|
|
assertDetail(ex, "Invalid request content."); |
|
|
|
|
|
|
|
messageSourceHelper.assertDetailMessage(ex); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -242,11 +258,12 @@ public class ErrorResponseExceptionTests { |
|
|
|
List<MediaType> mediaTypes = |
|
|
|
List<MediaType> mediaTypes = |
|
|
|
Arrays.asList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_CBOR); |
|
|
|
Arrays.asList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_CBOR); |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new UnsupportedMediaTypeStatusException( |
|
|
|
UnsupportedMediaTypeStatusException ex = new UnsupportedMediaTypeStatusException( |
|
|
|
MediaType.APPLICATION_XML, mediaTypes, HttpMethod.PATCH); |
|
|
|
MediaType.APPLICATION_XML, mediaTypes, HttpMethod.PATCH); |
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.UNSUPPORTED_MEDIA_TYPE); |
|
|
|
assertStatus(ex, HttpStatus.UNSUPPORTED_MEDIA_TYPE); |
|
|
|
assertDetail(ex, "Content-Type 'application/xml' is not supported."); |
|
|
|
assertDetail(ex, "Content-Type 'application/xml' is not supported."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getContentType(), ex.getSupportedMediaTypes()}); |
|
|
|
|
|
|
|
|
|
|
|
HttpHeaders headers = ex.getHeaders(); |
|
|
|
HttpHeaders headers = ex.getHeaders(); |
|
|
|
assertThat(headers.getAccept()).isEqualTo(mediaTypes); |
|
|
|
assertThat(headers.getAccept()).isEqualTo(mediaTypes); |
|
|
@ -261,19 +278,20 @@ public class ErrorResponseExceptionTests { |
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.UNSUPPORTED_MEDIA_TYPE); |
|
|
|
assertStatus(ex, HttpStatus.UNSUPPORTED_MEDIA_TYPE); |
|
|
|
assertDetail(ex, "Could not parse Content-Type."); |
|
|
|
assertDetail(ex, "Could not parse Content-Type."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, "parseError", null); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void notAcceptableStatusException() { |
|
|
|
void notAcceptableStatusException() { |
|
|
|
|
|
|
|
|
|
|
|
List<MediaType> mediaTypes = |
|
|
|
List<MediaType> mediaTypes = Arrays.asList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_CBOR); |
|
|
|
Arrays.asList(MediaType.APPLICATION_JSON, MediaType.APPLICATION_CBOR); |
|
|
|
NotAcceptableStatusException ex = new NotAcceptableStatusException(mediaTypes); |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new NotAcceptableStatusException(mediaTypes); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.NOT_ACCEPTABLE); |
|
|
|
assertStatus(ex, HttpStatus.NOT_ACCEPTABLE); |
|
|
|
assertDetail(ex, "Acceptable representations: 'application/json, application/cbor'."); |
|
|
|
assertDetail(ex, "Acceptable representations: [application/json, application/cbor]."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getSupportedMediaTypes()}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).hasSize(1); |
|
|
|
assertThat(ex.getHeaders()).hasSize(1); |
|
|
|
assertThat(ex.getHeaders().getAccept()).isEqualTo(mediaTypes); |
|
|
|
assertThat(ex.getHeaders().getAccept()).isEqualTo(mediaTypes); |
|
|
@ -285,45 +303,65 @@ public class ErrorResponseExceptionTests { |
|
|
|
ErrorResponse ex = new NotAcceptableStatusException( |
|
|
|
ErrorResponse ex = new NotAcceptableStatusException( |
|
|
|
"Could not parse Accept header: Invalid mime type \"foo\": does not contain '/'"); |
|
|
|
"Could not parse Accept header: Invalid mime type \"foo\": does not contain '/'"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.NOT_ACCEPTABLE); |
|
|
|
assertStatus(ex, HttpStatus.NOT_ACCEPTABLE); |
|
|
|
assertDetail(ex, "Could not parse Accept header."); |
|
|
|
assertDetail(ex, "Could not parse Accept header."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, "parseError", null); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
void serverErrorException() { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ServerErrorException ex = new ServerErrorException("Failure", null); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.INTERNAL_SERVER_ERROR); |
|
|
|
|
|
|
|
assertDetail(ex, null); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getReason()}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void missingRequestValueException() { |
|
|
|
void missingRequestValueException() { |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new MissingRequestValueException( |
|
|
|
MissingRequestValueException ex = |
|
|
|
"foo", String.class, "header", this.methodParameter); |
|
|
|
new MissingRequestValueException("foo", String.class, "header", this.methodParameter); |
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertDetail(ex, "Required header 'foo' is not present."); |
|
|
|
assertDetail(ex, "Required header 'foo' is not present."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getLabel(), ex.getName()}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void unsatisfiedRequestParameterException() { |
|
|
|
void unsatisfiedRequestParameterException() { |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new UnsatisfiedRequestParameterException( |
|
|
|
UnsatisfiedRequestParameterException ex = |
|
|
|
Arrays.asList("foo=bar", "bar=baz"), |
|
|
|
new UnsatisfiedRequestParameterException( |
|
|
|
new LinkedMultiValueMap<>(Collections.singletonMap("q", Arrays.asList("1", "2")))); |
|
|
|
Arrays.asList("foo=bar", "bar=baz"), |
|
|
|
|
|
|
|
new LinkedMultiValueMap<>(Collections.singletonMap("q", Arrays.asList("1", "2")))); |
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertDetail(ex, "Invalid request parameters."); |
|
|
|
assertDetail(ex, "Invalid request parameters."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getConditions()}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void webExchangeBindException() { |
|
|
|
void webExchangeBindException() { |
|
|
|
|
|
|
|
|
|
|
|
BindingResult bindingResult = new BindException(new Object(), "object"); |
|
|
|
MessageSourceTestHelper messageSourceHelper = new MessageSourceTestHelper(WebExchangeBindException.class); |
|
|
|
bindingResult.addError(new FieldError("object", "field", "message")); |
|
|
|
BindingResult bindingResult = messageSourceHelper.initBindingResult(); |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new WebExchangeBindException(this.methodParameter, bindingResult); |
|
|
|
WebExchangeBindException ex = new WebExchangeBindException(this.methodParameter, bindingResult); |
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertStatus(ex, HttpStatus.BAD_REQUEST); |
|
|
|
assertDetail(ex, "Invalid request content."); |
|
|
|
assertDetail(ex, "Invalid request content."); |
|
|
|
|
|
|
|
messageSourceHelper.assertDetailMessage(ex); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -331,11 +369,11 @@ public class ErrorResponseExceptionTests { |
|
|
|
void methodNotAllowedException() { |
|
|
|
void methodNotAllowedException() { |
|
|
|
|
|
|
|
|
|
|
|
List<HttpMethod> supportedMethods = Arrays.asList(HttpMethod.GET, HttpMethod.POST); |
|
|
|
List<HttpMethod> supportedMethods = Arrays.asList(HttpMethod.GET, HttpMethod.POST); |
|
|
|
ErrorResponse ex = new MethodNotAllowedException(HttpMethod.PUT, supportedMethods); |
|
|
|
MethodNotAllowedException ex = new MethodNotAllowedException(HttpMethod.PUT, supportedMethods); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.METHOD_NOT_ALLOWED); |
|
|
|
assertStatus(ex, HttpStatus.METHOD_NOT_ALLOWED); |
|
|
|
assertDetail(ex, "Supported methods: 'GET', 'POST'"); |
|
|
|
assertDetail(ex, "Supported methods: [GET, POST]"); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getHttpMethod(), supportedMethods}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).hasSize(1); |
|
|
|
assertThat(ex.getHeaders()).hasSize(1); |
|
|
|
assertThat(ex.getHeaders().getAllow()).containsExactly(HttpMethod.GET, HttpMethod.POST); |
|
|
|
assertThat(ex.getHeaders().getAllow()).containsExactly(HttpMethod.GET, HttpMethod.POST); |
|
|
@ -344,11 +382,12 @@ public class ErrorResponseExceptionTests { |
|
|
|
@Test |
|
|
|
@Test |
|
|
|
void methodNotAllowedExceptionWithoutSupportedMethods() { |
|
|
|
void methodNotAllowedExceptionWithoutSupportedMethods() { |
|
|
|
|
|
|
|
|
|
|
|
ErrorResponse ex = new MethodNotAllowedException(HttpMethod.PUT, Collections.emptyList()); |
|
|
|
MethodNotAllowedException ex = new MethodNotAllowedException(HttpMethod.PUT, Collections.emptyList()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertStatus(ex, HttpStatus.METHOD_NOT_ALLOWED); |
|
|
|
assertStatus(ex, HttpStatus.METHOD_NOT_ALLOWED); |
|
|
|
assertDetail(ex, "Request method 'PUT' is not supported."); |
|
|
|
assertDetail(ex, "Request method 'PUT' is not supported."); |
|
|
|
|
|
|
|
assertDetailMessageCode(ex, null, new Object[] {ex.getHttpMethod(), Collections.emptyList()}); |
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
assertThat(ex.getHeaders()).isEmpty(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -368,8 +407,64 @@ public class ErrorResponseExceptionTests { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void assertDetailMessageCode( |
|
|
|
|
|
|
|
ErrorResponse ex, @Nullable String suffix, @Nullable Object[] arguments) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertThat(ex.getDetailMessageCode()) |
|
|
|
|
|
|
|
.isEqualTo(ErrorResponse.getDefaultDetailMessageCode(((Exception) ex).getClass(), suffix)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (arguments != null) { |
|
|
|
|
|
|
|
assertThat(ex.getDetailMessageArguments()).containsExactlyElementsOf(Arrays.asList(arguments)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
assertThat(ex.getDetailMessageArguments()).isNull(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unused") |
|
|
|
@SuppressWarnings("unused") |
|
|
|
private void handle(String arg) {} |
|
|
|
private void handle(String arg) {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static class MessageSourceTestHelper { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final String code; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public MessageSourceTestHelper(Class<? extends ErrorResponse> exceptionType) { |
|
|
|
|
|
|
|
this.code = "problemDetail." + exceptionType.getName(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public BindingResult initBindingResult() { |
|
|
|
|
|
|
|
BindingResult bindingResult = new BindException(new TestBean(), "myBean"); |
|
|
|
|
|
|
|
bindingResult.reject("bean.invalid.A", "Invalid bean message"); |
|
|
|
|
|
|
|
bindingResult.reject("bean.invalid.B"); |
|
|
|
|
|
|
|
bindingResult.rejectValue("name", "name.required", "Name is required"); |
|
|
|
|
|
|
|
bindingResult.rejectValue("age", "age.min"); |
|
|
|
|
|
|
|
return bindingResult; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void assertDetailMessage(ErrorResponse ex) { |
|
|
|
|
|
|
|
StaticMessageSource messageSource = new StaticMessageSource(); |
|
|
|
|
|
|
|
messageSource.addMessage(this.code, Locale.UK, "Failures {0}. nested failures: {1}"); |
|
|
|
|
|
|
|
messageSource.addMessage("bean.invalid.A", Locale.UK, "Bean A message"); |
|
|
|
|
|
|
|
messageSource.addMessage("bean.invalid.B", Locale.UK, "Bean B message"); |
|
|
|
|
|
|
|
messageSource.addMessage("name.required", Locale.UK, "Required name message"); |
|
|
|
|
|
|
|
messageSource.addMessage("age.min", Locale.UK, "Minimum age message"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
String message = messageSource.getMessage( |
|
|
|
|
|
|
|
ex.getDetailMessageCode(), ex.getDetailMessageArguments(), Locale.UK); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertThat(message).isEqualTo("" + |
|
|
|
|
|
|
|
"Failures ['Invalid bean message', 'bean.invalid.B']. " + |
|
|
|
|
|
|
|
"nested failures: [name: 'Name is required', age: 'age.min']"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
message = messageSource.getMessage( |
|
|
|
|
|
|
|
ex.getDetailMessageCode(), ex.getDetailMessageArguments(messageSource, Locale.UK), Locale.UK); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assertThat(message).isEqualTo("" + |
|
|
|
|
|
|
|
"Failures ['Bean A message', 'Bean B message']. " + |
|
|
|
|
|
|
|
"nested failures: [name: 'Required name message', age: 'Minimum age message']"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|