From 62b1e38b30ec607ee4b8c0cb6dd71249d982bfb6 Mon Sep 17 00:00:00 2001 From: Ashley Scopes <73482956+ascopes@users.noreply.github.com> Date: Sat, 14 Aug 2021 17:05:17 +0100 Subject: [PATCH 1/3] Added utility methods to DefaultResponseCreator This enables the ability to fluently add single headers like you can already with the mock request specification APIs by chaining `.header(name, value)` repeatedly. This reduces code clutter within test cases. Added the ability to add cookies as this simplifies tests that work with sessions. Added the ability to override the character encoding used for setting a string body on a response, as this is useful when working in environments that do not automatically assume UTF-8, such as integrating with legacy applications from a new Spring one. --- .../response/DefaultResponseCreator.java | 72 +++++++++++++++++-- 1 file changed, 68 insertions(+), 4 deletions(-) diff --git a/spring-test/src/main/java/org/springframework/test/web/client/response/DefaultResponseCreator.java b/spring-test/src/main/java/org/springframework/test/web/client/response/DefaultResponseCreator.java index 5170d5a515dd..e03991462d7d 100644 --- a/spring-test/src/main/java/org/springframework/test/web/client/response/DefaultResponseCreator.java +++ b/spring-test/src/main/java/org/springframework/test/web/client/response/DefaultResponseCreator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,18 +19,25 @@ import java.io.IOException; import java.io.InputStream; import java.net.URI; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.springframework.core.io.Resource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.ResponseCookie; import org.springframework.http.client.ClientHttpRequest; import org.springframework.http.client.ClientHttpResponse; import org.springframework.lang.Nullable; import org.springframework.mock.http.client.MockClientHttpResponse; import org.springframework.test.web.client.ResponseCreator; import org.springframework.util.Assert; +import org.springframework.util.MultiValueMap; /** * A {@code ResponseCreator} with builder-style methods for adding response details. @@ -40,7 +47,7 @@ */ public class DefaultResponseCreator implements ResponseCreator { - private HttpStatus statusCode; + private final HttpStatus statusCode; private byte[] content = new byte[0]; @@ -59,7 +66,6 @@ protected DefaultResponseCreator(HttpStatus statusCode) { this.statusCode = statusCode; } - /** * Set the body as a UTF-8 String. */ @@ -68,6 +74,14 @@ public DefaultResponseCreator body(String content) { return this; } + /** + * Set the body from a string using the given character set. + */ + public DefaultResponseCreator body(String content, Charset charset) { + this.content = content.getBytes(charset); + return this; + } + /** * Set the body as a byte array. */ @@ -77,7 +91,7 @@ public DefaultResponseCreator body(byte[] content) { } /** - * Set the body as a {@link Resource}. + * Set the body from a {@link Resource}. */ public DefaultResponseCreator body(Resource resource) { this.contentResource = resource; @@ -100,6 +114,26 @@ public DefaultResponseCreator location(URI location) { return this; } + /** + * Add a single header. + */ + public DefaultResponseCreator header(String name, String value) { + // This is really just an alias, but it makes the interface more fluent. + return headers(name, value); + } + + /** + * Add one or more headers. + */ + public DefaultResponseCreator headers(String name, String ... value) { + List valueList = Stream.of(value) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + this.headers.addAll(name, valueList); + return this; + } + /** * Copy all given headers. */ @@ -108,6 +142,36 @@ public DefaultResponseCreator headers(HttpHeaders headers) { return this; } + /** + * Add a single cookie. + */ + public DefaultResponseCreator cookie(ResponseCookie cookie) { + // This is really just an alias, but it makes the interface more fluent. + return cookies(cookie); + } + + /** + * Add one or more cookies. + */ + public DefaultResponseCreator cookies(ResponseCookie... cookies) { + for (ResponseCookie cookie : cookies) { + this.headers.add(HttpHeaders.SET_COOKIE, cookie.toString()); + } + + return this; + } + + /** + * Copy all given cookies. + */ + public DefaultResponseCreator cookies(MultiValueMap cookies) { + cookies.values() + .stream() + .flatMap(List::stream) + .forEach(cookie -> this.headers.add(HttpHeaders.SET_COOKIE, cookie.toString())); + + return this; + } @Override public ClientHttpResponse createResponse(@Nullable ClientHttpRequest request) throws IOException { From 674660910c025cc394b911dfd066ec367f5774a1 Mon Sep 17 00:00:00 2001 From: Ashley Scopes <73482956+ascopes@users.noreply.github.com> Date: Sat, 14 Aug 2021 17:09:11 +0100 Subject: [PATCH 2/3] Added unit tests for DefaultResponseCreator These were already *partially* tested by the MockRestResponseCreator, but some existing calls prior to this PR were missing, and this was also an opportunity for me to directly test the changes I added. --- .../response/DefaultResponseCreatorTests.java | 230 ++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 spring-test/src/test/java/org/springframework/test/web/client/response/DefaultResponseCreatorTests.java diff --git a/spring-test/src/test/java/org/springframework/test/web/client/response/DefaultResponseCreatorTests.java b/spring-test/src/test/java/org/springframework/test/web/client/response/DefaultResponseCreatorTests.java new file mode 100644 index 000000000000..a11607e40e11 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/web/client/response/DefaultResponseCreatorTests.java @@ -0,0 +1,230 @@ +/* + * Copyright 2002-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.web.client.response; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collections; + +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseCookie; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.mock.http.client.MockClientHttpRequest; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.util.UriComponentsBuilder; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assumptions.assumeThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.mock; + +/** + * Tests for the {@link DefaultResponseCreator} factory methods. + * + * @author Ashley Scopes + */ +class DefaultResponseCreatorTests { + @ParameterizedTest(name = "expect status to be set [{0}]") + @ValueSource(ints = {200, 401, 429}) + void expectStatus(int statusValue) throws IOException { + HttpStatus status = HttpStatus.valueOf(statusValue); + ClientHttpResponse response = createResponse(new DefaultResponseCreator(status)); + assertThat(response.getStatusCode()).isEqualTo(status); + } + + @Test + void setBodyFromString() throws IOException { + // Use unicode codepoint for "thinking" emoji to help verify correct encoding is used internally. + ClientHttpResponse response = createResponse(new DefaultResponseCreator(HttpStatus.OK) + .body("hello, world! \uD83E\uDD14")); + + assertThat(IOUtils.toByteArray(response.getBody())) + .isEqualTo("hello, world! \uD83E\uDD14".getBytes(StandardCharsets.UTF_8)); + } + + @ParameterizedTest(name = "setBodyFromStringWithCharset [{0}]") + @ValueSource(strings = {"Cp1047", "UTF-8", "UTF-16", "US-ASCII", "ISO-8859-1"}) + void setBodyFromStringWithCharset(String charset) throws IOException { + + assumeThat(Charset.isSupported(charset)) + .overridingErrorMessage("charset %s is not supported by this JVM", charset) + .isTrue(); + + Charset charsetObj = Charset.forName(charset); + + String content = "hello! €½$~@><·─"; + + ClientHttpResponse response = createResponse(new DefaultResponseCreator(HttpStatus.OK) + .body(content, charsetObj)); + + ByteBuffer expectBuff = charsetObj.encode(content); + byte[] expect = new byte[expectBuff.remaining()]; + expectBuff.get(expect); + + assertThat(IOUtils.toByteArray(response.getBody())).isEqualTo(expect); + } + + @Test + void setBodyFromByteArray() throws IOException { + byte[] body = { 0, 9, 18, 27, 36, 45, 54, 63, 72, 81, 90 }; + ClientHttpResponse response = createResponse(new DefaultResponseCreator(HttpStatus.OK).body(body)); + assertThat(IOUtils.toByteArray(response.getBody())).isEqualTo(body); + } + + @Test + void setBodyFromResource() throws IOException { + byte[] resourceContent = {7, 14, 21, 28, 35}; + + Resource resource = mock(Resource.class); + given(resource.getInputStream()).willReturn(new ByteArrayInputStream(resourceContent)); + + ClientHttpResponse response = createResponse(new DefaultResponseCreator(HttpStatus.OK).body(resource)); + + then(resource).should().getInputStream(); + + assertThat(IOUtils.toByteArray(response.getBody())).isEqualTo(resourceContent); + } + + @Test + void setContentType() throws IOException { + ClientHttpResponse response = createResponse(new DefaultResponseCreator(HttpStatus.OK) + .contentType(MediaType.APPLICATION_JSON)); + + assertThat(response.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON); + } + + @Test + void setLocation() throws IOException { + URI uri = UriComponentsBuilder + .fromUriString("https://docs.spring.io/spring-framework/docs/current/reference/html/testing.html") + .build() + .toUri(); + + ClientHttpResponse response = createResponse(new DefaultResponseCreator(HttpStatus.OK).location(uri)); + assertThat(response.getHeaders().getLocation()).isEqualTo(uri); + } + + @Test + void setHeader() throws IOException { + + ClientHttpResponse response = createResponse(new DefaultResponseCreator(HttpStatus.OK) + .header("foo", "bar") + .header("baz", "bork") + .headers("lorem", "ipsum", "dolor", "sit", "amet")); + + HttpHeaders headers = response.getHeaders(); + assertThat(headers.get("foo")).isNotNull().isEqualTo(Collections.singletonList("bar")); + assertThat(headers.get("baz")).isNotNull().isEqualTo(Collections.singletonList("bork")); + assertThat(headers.get("lorem")).isNotNull().isEqualTo(Arrays.asList("ipsum", "dolor", "sit", "amet")); + } + + @Test + void setHeaders() throws IOException { + + HttpHeaders firstHeaders = new HttpHeaders(); + firstHeaders.setContentType(MediaType.APPLICATION_JSON); + firstHeaders.setOrigin("https://github.com"); + + HttpHeaders secondHeaders = new HttpHeaders(); + secondHeaders.setAllow(Collections.singleton(HttpMethod.PUT)); + + ClientHttpResponse response = createResponse(new DefaultResponseCreator(HttpStatus.OK) + .headers(firstHeaders) + .headers(secondHeaders)); + + HttpHeaders responseHeaders = response.getHeaders(); + + assertThat(responseHeaders.getContentType()).isEqualTo(MediaType.APPLICATION_JSON); + assertThat(responseHeaders.getOrigin()).isEqualTo("https://github.com"); + assertThat(responseHeaders.getAllow()).isEqualTo(Collections.singleton(HttpMethod.PUT)); + } + + @Test + void setCookie() throws IOException { + ResponseCookie firstCookie = ResponseCookie.from("user-id", "1234").build(); + ResponseCookie secondCookie = ResponseCookie.from("group-id", "5432").build(); + ResponseCookie thirdCookie = ResponseCookie.from("cookie-cookie", "cookies").build(); + ResponseCookie fourthCookie = ResponseCookie.from("foobar", "bazbork").build(); + + ClientHttpResponse response = createResponse(new DefaultResponseCreator(HttpStatus.OK) + .cookie(firstCookie) + .cookie(secondCookie) + .cookies(thirdCookie, fourthCookie)); + + HttpHeaders responseHeaders = response.getHeaders(); + + assertThat(responseHeaders.get(HttpHeaders.SET_COOKIE)) + .isNotNull() + .containsExactly( + firstCookie.toString(), + secondCookie.toString(), + thirdCookie.toString(), + fourthCookie.toString() + ); + } + + @Test + void setCookies() throws IOException { + ResponseCookie firstCookie = ResponseCookie.from("user-id", "1234").build(); + ResponseCookie secondCookie = ResponseCookie.from("group-id", "5432").build(); + MultiValueMap firstCookies = new LinkedMultiValueMap<>(); + firstCookies.add(firstCookie.getName(), firstCookie); + firstCookies.add(secondCookie.getName(), secondCookie); + + ResponseCookie thirdCookie = ResponseCookie.from("cookie-cookie", "cookies").build(); + ResponseCookie fourthCookie = ResponseCookie.from("foobar", "bazbork").build(); + MultiValueMap secondCookies = new LinkedMultiValueMap<>(); + firstCookies.add(thirdCookie.getName(), thirdCookie); + firstCookies.add(fourthCookie.getName(), fourthCookie); + + ClientHttpResponse response = createResponse(new DefaultResponseCreator(HttpStatus.OK) + .cookies(firstCookies) + .cookies(secondCookies)); + + HttpHeaders responseHeaders = response.getHeaders(); + + assertThat(responseHeaders.get(HttpHeaders.SET_COOKIE)) + .isNotNull() + .containsExactly( + firstCookie.toString(), + secondCookie.toString(), + thirdCookie.toString(), + fourthCookie.toString() + ); + } + + private static ClientHttpResponse createResponse(DefaultResponseCreator creator) throws IOException { + URI uri = UriComponentsBuilder.fromUriString("/foo/bar").build().toUri(); + return creator.createResponse(new MockClientHttpRequest(HttpMethod.POST, uri)); + } +} From 92c061f859efe82a90cfc9edd62918a0bc05679b Mon Sep 17 00:00:00 2001 From: Ashley Scopes <73482956+ascopes@users.noreply.github.com> Date: Sat, 14 Aug 2021 17:12:31 +0100 Subject: [PATCH 3/3] Added common response statuses to MockRestResponseCreators It appears that a couple of the more commonly used HTTP status codes were missed out from the default methods in MockRestResponseCreators. The methods included are common enough that most test packs will probably have at least one case that uses one of these calls, so it enables keeping the fluent API tidy. I added a couple of additional edge cases for common response statuses that will occur when working in cloud environments, such as AWS, CloudFlare, or using gateways such as Kong, where resillient applications should be able to respond to ratelimits, gateway errors, and gateway timeouts (which may occur if a remote service is down). Added test cases for any changes made. --- .../response/MockRestResponseCreators.java | 68 ++++++++++++++- .../response/ResponseCreatorsTests.java | 84 +++++++++++++++++++ 2 files changed, 151 insertions(+), 1 deletion(-) diff --git a/spring-test/src/main/java/org/springframework/test/web/client/response/MockRestResponseCreators.java b/spring-test/src/main/java/org/springframework/test/web/client/response/MockRestResponseCreators.java index cb9c9d84a642..8d4450d55e8a 100644 --- a/spring-test/src/main/java/org/springframework/test/web/client/response/MockRestResponseCreators.java +++ b/spring-test/src/main/java/org/springframework/test/web/client/response/MockRestResponseCreators.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 the original author or authors. + * Copyright 2002-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.net.URI; import org.springframework.core.io.Resource; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.lang.Nullable; @@ -81,6 +82,13 @@ public static DefaultResponseCreator withCreatedEntity(URI location) { return new DefaultResponseCreator(HttpStatus.CREATED).location(location); } + /** + * {@code ResponseCreator} for a 202 response (ACCEPTED). + */ + public static DefaultResponseCreator withAccepted() { + return new DefaultResponseCreator(HttpStatus.ACCEPTED); + } + /** * {@code ResponseCreator} for a 204 response (NO_CONTENT). */ @@ -102,6 +110,43 @@ public static DefaultResponseCreator withUnauthorizedRequest() { return new DefaultResponseCreator(HttpStatus.UNAUTHORIZED); } + /** + * {@code ResponseCreator} for a 403 response (FORBIDDEN). + */ + public static DefaultResponseCreator withForbiddenRequest() { + return new DefaultResponseCreator(HttpStatus.FORBIDDEN); + } + + /** + * {@code ResponseCreator} for a 404 response (NOT_FOUND). + */ + public static DefaultResponseCreator withResourceNotFound() { + return new DefaultResponseCreator(HttpStatus.NOT_FOUND); + } + + /** + * {@code ResponseCreator} for a 409 response (CONFLICT). + */ + public static DefaultResponseCreator withRequestConflict() { + return new DefaultResponseCreator(HttpStatus.CONFLICT); + } + + /** + * {@code ResponseCreator} for a 429 ratelimited response (TOO_MANY_REQUESTS). + */ + public static DefaultResponseCreator withTooManyRequests() { + return new DefaultResponseCreator(HttpStatus.TOO_MANY_REQUESTS); + } + + /** + * {@code ResponseCreator} for a 429 ratelimited response (TOO_MANY_REQUESTS) with a {@code Retry-After} header + * in seconds. + */ + public static DefaultResponseCreator withTooManyRequests(int retryAfter) { + return new DefaultResponseCreator(HttpStatus.TOO_MANY_REQUESTS) + .header(HttpHeaders.RETRY_AFTER, Integer.toString(retryAfter)); + } + /** * {@code ResponseCreator} for a 500 response (SERVER_ERROR). */ @@ -109,6 +154,27 @@ public static DefaultResponseCreator withServerError() { return new DefaultResponseCreator(HttpStatus.INTERNAL_SERVER_ERROR); } + /** + * {@code ResponseCreator} for a 502 response (BAD_GATEWAY). + */ + public static DefaultResponseCreator withBadGateway() { + return new DefaultResponseCreator(HttpStatus.BAD_GATEWAY); + } + + /** + * {@code ResponseCreator} for a 503 response (SERVICE_UNAVAILABLE). + */ + public static DefaultResponseCreator withServiceUnavailable() { + return new DefaultResponseCreator(HttpStatus.SERVICE_UNAVAILABLE); + } + + /** + * {@code ResponseCreator} for a 504 response (GATEWAY_TIMEOUT). + */ + public static DefaultResponseCreator withGatewayTimeout() { + return new DefaultResponseCreator(HttpStatus.GATEWAY_TIMEOUT); + } + /** * {@code ResponseCreator} with a specific HTTP status. * @param status the response status diff --git a/spring-test/src/test/java/org/springframework/test/web/client/response/ResponseCreatorsTests.java b/spring-test/src/test/java/org/springframework/test/web/client/response/ResponseCreatorsTests.java index 9742d0cef510..1960acf232d9 100644 --- a/spring-test/src/test/java/org/springframework/test/web/client/response/ResponseCreatorsTests.java +++ b/spring-test/src/test/java/org/springframework/test/web/client/response/ResponseCreatorsTests.java @@ -21,6 +21,7 @@ import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.mock.http.client.MockClientHttpResponse; @@ -78,6 +79,15 @@ void created() throws Exception { assertThat(StreamUtils.copyToByteArray(response.getBody()).length).isEqualTo(0); } + @Test + void accepted() throws Exception { + DefaultResponseCreator responseCreator = MockRestResponseCreators.withAccepted(); + MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); + assertThat(StreamUtils.copyToByteArray(response.getBody()).length).isEqualTo(0); + } + @Test void noContent() throws Exception { DefaultResponseCreator responseCreator = MockRestResponseCreators.withNoContent(); @@ -108,6 +118,53 @@ void unauthorized() throws Exception { assertThat(StreamUtils.copyToByteArray(response.getBody()).length).isEqualTo(0); } + @Test + void forbiddenRequest() throws Exception { + DefaultResponseCreator responseCreator = MockRestResponseCreators.withForbiddenRequest(); + MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN); + assertThat(StreamUtils.copyToByteArray(response.getBody()).length).isEqualTo(0); + } + + @Test + void resourceNotFound() throws Exception { + DefaultResponseCreator responseCreator = MockRestResponseCreators.withResourceNotFound(); + MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); + assertThat(StreamUtils.copyToByteArray(response.getBody()).length).isEqualTo(0); + } + + @Test + void requestConflict() throws Exception { + DefaultResponseCreator responseCreator = MockRestResponseCreators.withRequestConflict(); + MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CONFLICT); + assertThat(StreamUtils.copyToByteArray(response.getBody()).length).isEqualTo(0); + } + + @Test + void tooManyRequests() throws Exception { + DefaultResponseCreator responseCreator = MockRestResponseCreators.withTooManyRequests(); + MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.TOO_MANY_REQUESTS); + assertThat(response.getHeaders()).doesNotContainKey(HttpHeaders.RETRY_AFTER); + assertThat(StreamUtils.copyToByteArray(response.getBody()).length).isEqualTo(0); + } + + @Test + void tooManyRequestsWithRetryAfter() throws Exception { + DefaultResponseCreator responseCreator = MockRestResponseCreators.withTooManyRequests(512); + MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.TOO_MANY_REQUESTS); + assertThat(response.getHeaders().getFirst(HttpHeaders.RETRY_AFTER)).isEqualTo("512"); + assertThat(StreamUtils.copyToByteArray(response.getBody()).length).isEqualTo(0); + } + @Test void serverError() throws Exception { DefaultResponseCreator responseCreator = MockRestResponseCreators.withServerError(); @@ -118,6 +175,33 @@ void serverError() throws Exception { assertThat(StreamUtils.copyToByteArray(response.getBody()).length).isEqualTo(0); } + @Test + void badGateway() throws Exception { + DefaultResponseCreator responseCreator = MockRestResponseCreators.withBadGateway(); + MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.BAD_GATEWAY); + assertThat(StreamUtils.copyToByteArray(response.getBody()).length).isEqualTo(0); + } + + @Test + void serviceUnavailable() throws Exception { + DefaultResponseCreator responseCreator = MockRestResponseCreators.withServiceUnavailable(); + MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.SERVICE_UNAVAILABLE); + assertThat(StreamUtils.copyToByteArray(response.getBody()).length).isEqualTo(0); + } + + @Test + void gatewayTimeout() throws Exception { + DefaultResponseCreator responseCreator = MockRestResponseCreators.withGatewayTimeout(); + MockClientHttpResponse response = (MockClientHttpResponse) responseCreator.createResponse(null); + + assertThat(response.getStatusCode()).isEqualTo(HttpStatus.GATEWAY_TIMEOUT); + assertThat(StreamUtils.copyToByteArray(response.getBody()).length).isEqualTo(0); + } + @Test void withStatus() throws Exception { DefaultResponseCreator responseCreator = MockRestResponseCreators.withStatus(HttpStatus.FORBIDDEN);