diff --git a/endpoints/citrus-http/pom.xml b/endpoints/citrus-http/pom.xml index 7d12033e39..640190b243 100644 --- a/endpoints/citrus-http/pom.xml +++ b/endpoints/citrus-http/pom.xml @@ -65,6 +65,15 @@ provided + + com.fasterxml.jackson.core + jackson-core + + + com.fasterxml.jackson.core + jackson-databind + + org.springframework spring-core diff --git a/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerActionBuilder.java b/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerActionBuilder.java index ebe65dc94e..9d9c552ba1 100644 --- a/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerActionBuilder.java +++ b/endpoints/citrus-http/src/main/java/org/citrusframework/http/actions/HttpServerActionBuilder.java @@ -16,15 +16,21 @@ package org.citrusframework.http.actions; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import org.citrusframework.TestAction; import org.citrusframework.TestActionBuilder; import org.citrusframework.endpoint.Endpoint; +import org.citrusframework.exceptions.CitrusRuntimeException; import org.citrusframework.spi.ReferenceResolver; import org.citrusframework.spi.ReferenceResolverAware; import org.citrusframework.util.ObjectHelper; import org.citrusframework.util.StringUtils; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; + +import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT; /** * Action executes http server operations such as receiving requests and sending response messages. @@ -34,6 +40,8 @@ */ public class HttpServerActionBuilder implements TestActionBuilder.DelegatingTestActionBuilder, ReferenceResolverAware { + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper().enable(INDENT_OUTPUT); + /** Bean reference resolver */ private ReferenceResolver referenceResolver; @@ -73,6 +81,32 @@ public HttpServerResponseActionBuilder respond(HttpStatus status) { return new HttpServerSendActionBuilder().response(status); } + /** + * Generic response builder for sending JSON response messages to client with response status 200 (OK). + * + * @return + */ + public HttpServerResponseActionBuilder.HttpMessageBuilderSupport respondOkJson(String json) { + return new HttpServerSendActionBuilder() + .response(HttpStatus.OK) + .message() + .contentType(MediaType.APPLICATION_JSON_VALUE) + .body(json); + } + + /** + * Generic response builder for sending JSON response messages to client with response status 200 (OK). + * + * @return + */ + public HttpServerResponseActionBuilder.HttpMessageBuilderSupport respondOkJson(Object json) { + try { + return respondOkJson(OBJECT_MAPPER.writeValueAsString(json)); + } catch (JsonProcessingException e) { + throw new CitrusRuntimeException("Failed to write JSON body as string!", e); + } + } + /** * Receive Http requests as server. */ diff --git a/endpoints/citrus-http/src/test/java/org/citrusframework/http/actions/HttpServerActionBuilderTest.java b/endpoints/citrus-http/src/test/java/org/citrusframework/http/actions/HttpServerActionBuilderTest.java new file mode 100644 index 0000000000..8a2b9aea44 --- /dev/null +++ b/endpoints/citrus-http/src/test/java/org/citrusframework/http/actions/HttpServerActionBuilderTest.java @@ -0,0 +1,55 @@ +package org.citrusframework.http.actions; + +import org.citrusframework.endpoint.Endpoint; +import org.citrusframework.http.message.HttpMessage; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import static org.mockito.Mockito.mock; +import static org.springframework.test.util.ReflectionTestUtils.getField; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; + +public class HttpServerActionBuilderTest { + + private static final TestJsonObject JSON_OBJECT_REPRESENTATION = new TestJsonObject("value"); + private static final String JSON_STRING_REPRESENTATION = """ + { + "property" : "value" + }"""; + + private HttpServerActionBuilder fixture; + + private static void verifyOkJsonResponse(HttpServerResponseActionBuilder.HttpMessageBuilderSupport httpMessageBuilderSupport) { + Object responseMessage = getField(httpMessageBuilderSupport, "httpMessage"); + assertTrue(responseMessage instanceof HttpMessage); + + HttpMessage httpMessage = (HttpMessage) responseMessage; + + assertEquals(HttpStatus.OK, httpMessage.getStatusCode()); + assertEquals(MediaType.APPLICATION_JSON_VALUE, httpMessage.getContentType()); + assertEquals(JSON_STRING_REPRESENTATION, httpMessage.getPayload(String.class).replace("\r\n", "\n")); + } + + @BeforeMethod + public void beforeMethodSetup() { + fixture = new HttpServerActionBuilder(mock(Endpoint.class)); + } + + @Test + public void sendOkJsonFromString() { + HttpServerResponseActionBuilder.HttpMessageBuilderSupport httpMessageBuilderSupport = fixture.respondOkJson(JSON_STRING_REPRESENTATION); + verifyOkJsonResponse(httpMessageBuilderSupport); + } + + @Test + public void sendOkJsonFromObject() { + HttpServerResponseActionBuilder.HttpMessageBuilderSupport httpMessageBuilderSupport = fixture.respondOkJson(JSON_OBJECT_REPRESENTATION); + verifyOkJsonResponse(httpMessageBuilderSupport); + } + + private record TestJsonObject(String property) { + } +}