From 8ea65e2abb1dac2917855a7d3de0f93d1ff3a512 Mon Sep 17 00:00:00 2001 From: Tom Jegge Date: Mon, 4 Sep 2023 14:20:16 +0200 Subject: [PATCH] fix(#978): Allow custom http status codes Co-authored-by: Timon Borter --- .../HttpClientResponseActionBuilder.java | 3 +- .../HttpServerResponseActionBuilder.java | 3 +- .../controller/HttpMessageController.java | 7 ++-- .../http/message/HttpMessage.java | 33 +++++++----------- .../http/message/HttpMessageConverter.java | 13 ++----- .../message/HttpMessageConverterTest.java | 34 +++++++++++++++---- .../http/message/HttpMessageTest.java | 22 +++++++++--- .../provider/http/HttpCodeProvider.java | 6 +++- .../ReceiveHttpResponseActionProvider.java | 10 ++++-- .../http/SendHttpResponseActionProvider.java | 10 ++++-- .../provider/http/HttpCodeProviderTest.java | 3 +- 11 files changed, 90 insertions(+), 54 deletions(-) diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpClientResponseActionBuilder.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpClientResponseActionBuilder.java index b4e065a458..92b4536c6b 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpClientResponseActionBuilder.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpClientResponseActionBuilder.java @@ -26,6 +26,7 @@ import org.citrusframework.message.Message; import org.citrusframework.message.builder.ReceiveMessageBuilderSupport; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; /** * @author Christoph Deppisch @@ -95,7 +96,7 @@ public HttpMessageBuilderSupport status(HttpStatus status) { * @return */ public HttpMessageBuilderSupport statusCode(Integer statusCode) { - httpMessage.statusCode(statusCode); + httpMessage.status(HttpStatusCode.valueOf(statusCode)); return this; } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerResponseActionBuilder.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerResponseActionBuilder.java index 53fd1d378d..02e68e034e 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerResponseActionBuilder.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerResponseActionBuilder.java @@ -25,6 +25,7 @@ import org.citrusframework.message.Message; import org.citrusframework.message.builder.SendMessageBuilderSupport; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; /** * @author Christoph Deppisch @@ -93,7 +94,7 @@ public HttpMessageBuilderSupport status(HttpStatus status) { * @return */ public HttpMessageBuilderSupport statusCode(Integer statusCode) { - httpMessage.statusCode(statusCode); + httpMessage.status(HttpStatusCode.valueOf(statusCode)); return this; } diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/controller/HttpMessageController.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/controller/HttpMessageController.java index a0f80c3de0..3f22b7d17f 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/controller/HttpMessageController.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/controller/HttpMessageController.java @@ -31,10 +31,7 @@ import org.citrusframework.http.message.HttpMessage; import org.citrusframework.http.server.HttpServerSettings; import org.citrusframework.message.Message; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.stereotype.Controller; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.RequestMapping; @@ -179,7 +176,7 @@ private ResponseEntity handleRequestInternal(HttpMethod method, HttpEntity } if (httpResponse.getStatusCode() == null) { - httpResponse.status(HttpStatus.valueOf(endpointConfiguration.getDefaultStatusCode())); + httpResponse.status(HttpStatusCode.valueOf(endpointConfiguration.getDefaultStatusCode())); } responseEntity = (ResponseEntity) endpointConfiguration.getMessageConverter().convertOutbound(httpResponse, endpointConfiguration, null); diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessage.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessage.java index 91e4b375d1..03b144c2bb 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessage.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessage.java @@ -36,6 +36,7 @@ import jakarta.servlet.http.Cookie; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMethod; @@ -126,26 +127,17 @@ public HttpMessage version(final String version) { return this; } - /** - * Sets the Http response status code. - * - * @param statusCode The status code header to respond with - * @return The altered HttpMessage - */ - public HttpMessage status(final HttpStatus statusCode) { - statusCode(statusCode.value()); - reasonPhrase(statusCode.name()); - return this; - } - /** * Sets the Http response status code header. * * @param statusCode The status code header value to respond with * @return The altered HttpMessage */ - public HttpMessage statusCode(final Integer statusCode) { - setHeader(HttpMessageHeaders.HTTP_STATUS_CODE, statusCode); + public HttpMessage status(final HttpStatusCode statusCode) { + setHeader(HttpMessageHeaders.HTTP_STATUS_CODE, statusCode.value()); + if (HttpStatus.resolve(statusCode.value()) != null) { + setHeader(HttpMessageHeaders.HTTP_REASON_PHRASE, HttpStatus.resolve(statusCode.value()).name()); + } return this; } @@ -392,19 +384,18 @@ public String getQueryParamString() { * * @return The status code of the message */ - public HttpStatus getStatusCode() { + public HttpStatusCode getStatusCode() { final Object statusCode = getHeader(HttpMessageHeaders.HTTP_STATUS_CODE); if (statusCode != null) { - if (statusCode instanceof HttpStatus) { - return (HttpStatus) statusCode; + if (statusCode instanceof HttpStatusCode) { + return (HttpStatusCode) statusCode; } else if (statusCode instanceof Integer) { - return HttpStatus.valueOf((Integer) statusCode); + return HttpStatusCode.valueOf((Integer) statusCode); } else { - return HttpStatus.valueOf(Integer.valueOf(statusCode.toString())); + return HttpStatusCode.valueOf(Integer.valueOf(statusCode.toString())); } } - return null; } @@ -546,7 +537,7 @@ public static HttpMessage fromResponseData(final String responseData) { } if (statusLine.length > 1) { - response.status(HttpStatus.valueOf(Integer.valueOf(statusLine[1]))); + response.status(HttpStatusCode.valueOf(Integer.valueOf(statusLine[1]))); } return parseHttpMessage(reader, response); diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageConverter.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageConverter.java index 5e02ee9235..540fbac5ec 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageConverter.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/message/HttpMessageConverter.java @@ -16,10 +16,7 @@ package org.citrusframework.http.message; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import org.citrusframework.context.TestContext; import org.citrusframework.http.client.HttpEndpointConfiguration; @@ -28,11 +25,7 @@ import org.citrusframework.message.MessageHeaderUtils; import org.citrusframework.message.MessageHeaders; import jakarta.servlet.http.Cookie; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMethod; @@ -91,7 +84,7 @@ public HttpMessage convertInbound(HttpEntity message, } if (message instanceof ResponseEntity) { - httpMessage.status(HttpStatus.valueOf(((ResponseEntity) message).getStatusCode().value())); + httpMessage.status(((ResponseEntity) message).getStatusCode()); // We've no information here about the HTTP Version in this context. // Because HTTP/2 is not supported anyway currently, this should be acceptable. diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageConverterTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageConverterTest.java index c8ecb0969d..370df18a2d 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageConverterTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageConverterTest.java @@ -20,12 +20,7 @@ import org.citrusframework.http.client.HttpEndpointConfiguration; import org.citrusframework.message.DefaultMessage; import org.citrusframework.message.Message; -import org.springframework.http.HttpEntity; -import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.integration.mapping.HeaderMapper; import org.springframework.messaging.MessageHeaders; import org.testng.annotations.BeforeMethod; @@ -319,6 +314,19 @@ public void testHttpMessageWithStatusCodeContainsNoCookiesOnOutbound(){ assertNull(httpEntity.getHeaders().get("Cookie")); } + @Test + public void testCustomStatusCodeIsSetOnOutbound(){ + + //GIVEN + message.setHeader(HttpMessageHeaders.HTTP_STATUS_CODE, "555"); + + //WHEN + final HttpEntity httpEntity = messageConverter.convertOutbound(message, endpointConfiguration, testContext); + + //THEN + assertEquals(HttpStatusCode.valueOf(555), ((ResponseEntity) httpEntity).getStatusCode()); + } + @Test public void testSpringIntegrationHeaderMapperIsUsedOnOutbound(){ @@ -443,6 +451,20 @@ public void testStatusCodeIsSetOnInbound(){ assertEquals(HttpStatus.FORBIDDEN, httpMessage.getStatusCode()); } + @Test + public void testCustomStatusCodeIsSetOnInbound(){ + + //GIVEN + final ResponseEntity responseEntity = new ResponseEntity<>(null, null, 555); + + //WHEN + final HttpMessage httpMessage = + messageConverter.convertInbound(responseEntity, endpointConfiguration, testContext); + + //THEN + assertEquals(HttpStatusCode.valueOf(555), httpMessage.getStatusCode()); + } + @Test public void testHttpVersionIsSetOnInbound(){ diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageTest.java index c50769c2b1..fa85b4b48d 100644 --- a/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageTest.java +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/message/HttpMessageTest.java @@ -18,6 +18,7 @@ import org.citrusframework.endpoint.resolver.EndpointUriResolver; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -231,7 +232,7 @@ public void testDefaultStatusCodeIsNull() { //WHEN - final HttpStatus statusCode = httpMessage.getStatusCode(); + final HttpStatusCode statusCode = httpMessage.getStatusCode(); //THEN assertNull(statusCode); @@ -244,7 +245,7 @@ public void testStringStatusCodeIsParsed() { httpMessage.header(HttpMessageHeaders.HTTP_STATUS_CODE, "404"); //WHEN - final HttpStatus statusCode = httpMessage.getStatusCode(); + final HttpStatusCode statusCode = httpMessage.getStatusCode(); //THEN assertEquals(statusCode, HttpStatus.NOT_FOUND); @@ -257,7 +258,7 @@ public void testIntegerStatusCodeIsParsed() { httpMessage.header(HttpMessageHeaders.HTTP_STATUS_CODE, 403); //WHEN - final HttpStatus statusCode = httpMessage.getStatusCode(); + final HttpStatusCode statusCode = httpMessage.getStatusCode(); //THEN assertEquals(statusCode, HttpStatus.FORBIDDEN); @@ -270,12 +271,25 @@ public void testStatusCodeObjectIsPreserved() { httpMessage.header(HttpMessageHeaders.HTTP_STATUS_CODE, HttpStatus.I_AM_A_TEAPOT); //WHEN - final HttpStatus statusCode = httpMessage.getStatusCode(); + final HttpStatusCode statusCode = httpMessage.getStatusCode(); //THEN assertEquals(statusCode, HttpStatus.I_AM_A_TEAPOT); } + @Test + public void testCanHandleCustomStatusCode() { + + //GIVEN + httpMessage.header(HttpMessageHeaders.HTTP_STATUS_CODE, 555); + + //WHEN + final HttpStatusCode statusCode = httpMessage.getStatusCode(); + + //THEN + assertEquals(statusCode, HttpStatusCode.valueOf(555)); + } + @Test public void testQueryParamWithMultipleParams() { diff --git a/tools/test-generator/src/main/java/org/citrusframework/generate/provider/http/HttpCodeProvider.java b/tools/test-generator/src/main/java/org/citrusframework/generate/provider/http/HttpCodeProvider.java index 092aae31c0..b05768ede5 100644 --- a/tools/test-generator/src/main/java/org/citrusframework/generate/provider/http/HttpCodeProvider.java +++ b/tools/test-generator/src/main/java/org/citrusframework/generate/provider/http/HttpCodeProvider.java @@ -43,7 +43,11 @@ void provideRequestConfiguration(final CodeBlock.Builder code, final HttpMessage } void provideResponseConfiguration(final CodeBlock.Builder code, final HttpMessage message) { - code.add(".response($T.$L)\n", HttpStatus.class, message.getStatusCode().name()); + if (message.getStatusCode() instanceof HttpStatus) { + code.add(".response($T.$L)\n", HttpStatus.class, ((HttpStatus) message.getStatusCode()).name()); + } else { + code.add(".response($T.$L)\n", HttpStatus.class, "Status"); + } messageCodeProvider.provideHeaderAndPayload(code, message); } diff --git a/tools/test-generator/src/main/java/org/citrusframework/generate/provider/http/ReceiveHttpResponseActionProvider.java b/tools/test-generator/src/main/java/org/citrusframework/generate/provider/http/ReceiveHttpResponseActionProvider.java index e63c0ccd81..5a6a29d7fb 100644 --- a/tools/test-generator/src/main/java/org/citrusframework/generate/provider/http/ReceiveHttpResponseActionProvider.java +++ b/tools/test-generator/src/main/java/org/citrusframework/generate/provider/http/ReceiveHttpResponseActionProvider.java @@ -20,6 +20,7 @@ import org.citrusframework.http.message.HttpMessage; import org.citrusframework.message.MessageHeaders; import org.citrusframework.model.testcase.http.*; +import org.springframework.http.HttpStatus; import java.util.Optional; @@ -40,8 +41,13 @@ public ReceiveResponseModel getAction(String endpoint, HttpMessage message) { response.setBody(body); ReceiveResponseModel.Headers responseHeaders = new ReceiveResponseModel.Headers(); - responseHeaders.setStatus(message.getStatusCode().toString()); - responseHeaders.setReasonPhrase(message.getStatusCode().getReasonPhrase()); + if (message.getStatusCode() instanceof HttpStatus) { + responseHeaders.setStatus(((HttpStatus) message.getStatusCode()).toString()); + responseHeaders.setReasonPhrase(((HttpStatus) message.getStatusCode()).getReasonPhrase()); + } else { + responseHeaders.setStatus("Status" + message.getStatusCode().value()); + responseHeaders.setReasonPhrase("Custom Status Code " + message.getStatusCode().value()); + } message.getHeaders().entrySet().stream() .filter(entry -> !entry.getKey().startsWith(MessageHeaders.PREFIX)) diff --git a/tools/test-generator/src/main/java/org/citrusframework/generate/provider/http/SendHttpResponseActionProvider.java b/tools/test-generator/src/main/java/org/citrusframework/generate/provider/http/SendHttpResponseActionProvider.java index 8a1038f272..a1a9345bd8 100644 --- a/tools/test-generator/src/main/java/org/citrusframework/generate/provider/http/SendHttpResponseActionProvider.java +++ b/tools/test-generator/src/main/java/org/citrusframework/generate/provider/http/SendHttpResponseActionProvider.java @@ -20,6 +20,7 @@ import org.citrusframework.http.message.HttpMessage; import org.citrusframework.message.MessageHeaders; import org.citrusframework.model.testcase.http.*; +import org.springframework.http.HttpStatus; import java.util.Optional; @@ -40,8 +41,13 @@ public SendResponseModel getAction(String endpoint, HttpMessage message) { response.setBody(body); ResponseHeadersType responseHeaders = new ResponseHeadersType(); - responseHeaders.setStatus(message.getStatusCode().toString()); - responseHeaders.setReasonPhrase(message.getStatusCode().getReasonPhrase()); + if (message.getStatusCode() instanceof HttpStatus) { + responseHeaders.setStatus(((HttpStatus) message.getStatusCode()).toString()); + responseHeaders.setReasonPhrase(((HttpStatus) message.getStatusCode()).getReasonPhrase()); + } else { + responseHeaders.setStatus("Status" + message.getStatusCode().value()); + responseHeaders.setReasonPhrase("Custom Status Code " + message.getStatusCode().value()); + } message.getHeaders().entrySet().stream() .filter(entry -> !entry.getKey().startsWith(MessageHeaders.PREFIX)) diff --git a/tools/test-generator/src/test/java/org/citrusframework/generate/provider/http/HttpCodeProviderTest.java b/tools/test-generator/src/test/java/org/citrusframework/generate/provider/http/HttpCodeProviderTest.java index 192828b09e..42a8806c3a 100644 --- a/tools/test-generator/src/test/java/org/citrusframework/generate/provider/http/HttpCodeProviderTest.java +++ b/tools/test-generator/src/test/java/org/citrusframework/generate/provider/http/HttpCodeProviderTest.java @@ -21,6 +21,7 @@ import com.squareup.javapoet.CodeBlock; import org.apache.hc.core5.http.HttpStatus; import org.junit.jupiter.api.Test; +import org.springframework.http.HttpStatusCode; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -77,7 +78,7 @@ void testQueryParameterCodeIsGenerated() { void testResponseConfiguration() { //GIVEN - message.statusCode(HttpStatus.SC_NOT_FOUND); + message.status(HttpStatusCode.valueOf(HttpStatus.SC_NOT_FOUND)); final String expectedCode = ".response(org.springframework.http.HttpStatus.NOT_FOUND)\n.message()\n"; //WHEN