diff --git a/spring-graphql/src/test/java/org/springframework/graphql/server/webflux/GraphQlHttpHandlerTests.java b/spring-graphql/src/test/java/org/springframework/graphql/server/webflux/GraphQlHttpHandlerTests.java index 30d8cbf8..a21c68e9 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/server/webflux/GraphQlHttpHandlerTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/server/webflux/GraphQlHttpHandlerTests.java @@ -23,22 +23,24 @@ import java.util.Locale; import com.jayway.jsonpath.DocumentContext; import com.jayway.jsonpath.JsonPath; import org.junit.jupiter.api.Test; -import reactor.core.publisher.Mono; +import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; +import reactor.test.StepVerifier; -import org.springframework.graphql.GraphQlRequest; import org.springframework.graphql.GraphQlSetup; import org.springframework.graphql.server.support.SerializableGraphQlRequest; import org.springframework.http.MediaType; +import org.springframework.http.codec.DecoderHttpMessageReader; import org.springframework.http.codec.EncoderHttpMessageWriter; +import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.codec.HttpMessageWriter; +import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.mock.http.server.reactive.MockServerHttpRequest; import org.springframework.mock.http.server.reactive.MockServerHttpResponse; -import org.springframework.mock.web.reactive.function.server.MockServerRequest; import org.springframework.mock.web.server.MockServerWebExchange; +import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.result.view.ViewResolver; -import org.springframework.web.server.ServerWebExchange; import static org.assertj.core.api.Assertions.assertThat; @@ -48,95 +50,100 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class GraphQlHttpHandlerTests { - private final GraphQlHttpHandler greetingHandler = GraphQlSetup.schemaContent("type Query { greeting: String }") - .queryFetcher("greeting", (env) -> "Hello").toHttpHandlerWebFlux(); + private static final List> MESSAGE_READERS = + List.of(new DecoderHttpMessageReader<>(new Jackson2JsonDecoder())); + + private final GraphQlHttpHandler greetingHandler = + GraphQlSetup.schemaContent("type Query { greeting: String }") + .queryFetcher("greeting", (env) -> "Hello") + .toHttpHandlerWebFlux(); @Test - void shouldProduceApplicationJsonByDefault() { - MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/") - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.ALL).build(); - + void shouldProduceApplicationJsonByDefault() throws Exception { String document = "{greeting}"; - MockServerHttpResponse httpResponse = handleRequest( - httpRequest, this.greetingHandler, initRequest(document)); + MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.ALL) + .body(initRequestBody(document)); - assertThat(httpResponse.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON); + MockServerHttpResponse response = handleRequest(httpRequest, this.greetingHandler); + + assertThat(response.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON); + StepVerifier.create(response.getBodyAsString()) + .expectNext("{\"data\":{\"greeting\":\"Hello\"}}") + .verifyComplete(); } @Test - void shouldProduceApplicationGraphQl() { + void shouldProduceApplicationGraphQl() throws Exception { MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/") - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_GRAPHQL_RESPONSE).build(); + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_GRAPHQL_RESPONSE) + .body(initRequestBody("{greeting}")); - MockServerHttpResponse httpResponse = handleRequest( - httpRequest, this.greetingHandler, initRequest("{greeting}")); + MockServerHttpResponse httpResponse = handleRequest(httpRequest, this.greetingHandler); assertThat(httpResponse.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_GRAPHQL_RESPONSE); } @Test - void shouldProduceApplicationJson() { + void shouldProduceApplicationJson() throws Exception { MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/") - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).build(); + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .body(initRequestBody("{greeting}")); - MockServerHttpResponse httpResponse = handleRequest( - httpRequest, this.greetingHandler, initRequest("{greeting}")); + MockServerHttpResponse httpResponse = handleRequest(httpRequest, this.greetingHandler); assertThat(httpResponse.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON); } @Test - void locale() { + void locale() throws Exception { GraphQlHttpHandler handler = GraphQlSetup.schemaContent("type Query { greeting: String }") .queryFetcher("greeting", (env) -> "Hello in " + env.getLocale()) .toHttpHandlerWebFlux(); MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/") - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_GRAPHQL_RESPONSE) - .acceptLanguageAsLocales(Locale.FRENCH).build(); + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_GRAPHQL_RESPONSE) + .acceptLanguageAsLocales(Locale.FRENCH) + .body(initRequestBody("{greeting}")); - MockServerHttpResponse httpResponse = handleRequest( - httpRequest, handler, initRequest("{greeting}")); + MockServerHttpResponse httpResponse = handleRequest(httpRequest, handler); assertThat(httpResponse.getBodyAsString().block()) .isEqualTo("{\"data\":{\"greeting\":\"Hello in fr\"}}"); } @Test - void shouldSetExecutionId() { + void shouldSetExecutionId() throws Exception { GraphQlHttpHandler handler = GraphQlSetup.schemaContent("type Query { showId: String }") .queryFetcher("showId", (env) -> env.getExecutionId().toString()) .toHttpHandlerWebFlux(); MockServerHttpRequest httpRequest = MockServerHttpRequest.post("/") - .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_GRAPHQL_RESPONSE).build(); + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_GRAPHQL_RESPONSE) + .body(initRequestBody("{showId}")); - MockServerHttpResponse httpResponse = handleRequest( - httpRequest, handler, initRequest("{showId}")); + MockServerHttpResponse httpResponse = handleRequest(httpRequest, handler); DocumentContext document = JsonPath.parse(httpResponse.getBodyAsString().block()); String id = document.read("data.showId", String.class); assertThat(id).isEqualTo(httpRequest.getId()); } - private static SerializableGraphQlRequest initRequest(String document) { + private static String initRequestBody(String document) throws Exception { SerializableGraphQlRequest request = new SerializableGraphQlRequest(); request.setQuery(document); - return request; + return new ObjectMapper().writeValueAsString(request); } - private MockServerHttpResponse handleRequest( - MockServerHttpRequest httpRequest, GraphQlHttpHandler handler, GraphQlRequest body) { - + private MockServerHttpResponse handleRequest(MockServerHttpRequest httpRequest, GraphQlHttpHandler handler) { MockServerWebExchange exchange = MockServerWebExchange.from(httpRequest); - - MockServerRequest serverRequest = MockServerRequest.builder() - .exchange(exchange) - .uri(((ServerWebExchange) exchange).getRequest().getURI()) - .method(((ServerWebExchange) exchange).getRequest().getMethod()) - .headers(((ServerWebExchange) exchange).getRequest().getHeaders()) - .body(Mono.just(body)); + ServerRequest serverRequest = ServerRequest.create(exchange, MESSAGE_READERS); handler.handleRequest(serverRequest) .flatMap(response -> response.writeTo(exchange, new DefaultContext())) diff --git a/spring-graphql/src/test/java/org/springframework/graphql/server/webmvc/GraphQlHttpHandlerTests.java b/spring-graphql/src/test/java/org/springframework/graphql/server/webmvc/GraphQlHttpHandlerTests.java index da8d7cf7..90d7f547 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/server/webmvc/GraphQlHttpHandlerTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/server/webmvc/GraphQlHttpHandlerTests.java @@ -21,6 +21,7 @@ import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.UUID; import com.jayway.jsonpath.DocumentContext; @@ -29,9 +30,11 @@ import graphql.execution.preparsed.persisted.ApolloPersistedQuerySupport; import graphql.execution.preparsed.persisted.InMemoryPersistedQueryCache; import jakarta.servlet.ServletException; import org.junit.jupiter.api.Test; +import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.graphql.GraphQlSetup; +import org.springframework.graphql.server.support.SerializableGraphQlRequest; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; @@ -57,23 +60,24 @@ public class GraphQlHttpHandlerTests { private final GraphQlHttpHandler greetingHandler = GraphQlSetup.schemaContent("type Query { greeting: String }") .queryFetcher("greeting", (env) -> "Hello").toHttpHandler(); + @Test void shouldProduceApplicationJsonByDefault() throws Exception { - MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ greeting }\"}", "*/*"); - MockHttpServletResponse servletResponse = handleRequest(servletRequest, this.greetingHandler); - assertThat(servletResponse.getContentType()).isEqualTo(MediaType.APPLICATION_JSON_VALUE); + MockHttpServletRequest request = createServletRequest("{ greeting }", "*/*"); + MockHttpServletResponse response = handleRequest(request, this.greetingHandler); + assertThat(response.getContentType()).isEqualTo(MediaType.APPLICATION_JSON_VALUE); } @Test void shouldProduceApplicationGraphQl() throws Exception { - MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ greeting }\"}", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); - MockHttpServletResponse servletResponse = handleRequest(servletRequest, this.greetingHandler); - assertThat(servletResponse.getContentType()).isEqualTo(MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); + MockHttpServletRequest request = createServletRequest("{ greeting }", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); + MockHttpServletResponse response = handleRequest(request, this.greetingHandler); + assertThat(response.getContentType()).isEqualTo(MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); } @Test void shouldProduceApplicationJson() throws Exception { - MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ greeting }\"}", "application/json"); + MockHttpServletRequest servletRequest = createServletRequest("{ greeting }", "application/json"); MockHttpServletResponse servletResponse = handleRequest(servletRequest, this.greetingHandler); assertThat(servletResponse.getContentType()).isEqualTo("application/json"); } @@ -83,14 +87,15 @@ public class GraphQlHttpHandlerTests { GraphQlHttpHandler handler = GraphQlSetup.schemaContent("type Query { greeting: String }") .queryFetcher("greeting", (env) -> "Hello in " + env.getLocale()) .toHttpHandler(); - MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ greeting }\"}", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); + + MockHttpServletRequest request = createServletRequest( + "{ greeting }", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); + LocaleContextHolder.setLocale(Locale.FRENCH); try { - MockHttpServletResponse servletResponse = handleRequest(servletRequest, handler); - - assertThat(servletResponse.getContentAsString()) - .isEqualTo("{\"data\":{\"greeting\":\"Hello in fr\"}}"); + MockHttpServletResponse response = handleRequest(request, handler); + assertThat(response.getContentAsString()).isEqualTo("{\"data\":{\"greeting\":\"Hello in fr\"}}"); } finally { LocaleContextHolder.resetLocaleContext(); @@ -103,10 +108,12 @@ public class GraphQlHttpHandlerTests { .queryFetcher("showId", (env) -> env.getExecutionId().toString()) .toHttpHandler(); - MockHttpServletRequest servletRequest = createServletRequest("{\"query\":\"{ showId }\"}", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); + MockHttpServletRequest request = createServletRequest( + "{ showId }", MediaType.APPLICATION_GRAPHQL_RESPONSE_VALUE); - MockHttpServletResponse servletResponse = handleRequest(servletRequest, handler); - DocumentContext document = JsonPath.parse(servletResponse.getContentAsString()); + MockHttpServletResponse response = handleRequest(request, handler); + + DocumentContext document = JsonPath.parse(response.getContentAsString()); String id = document.read("data.showId", String.class); assertThatNoException().isThrownBy(() -> UUID.fromString(id)); } @@ -121,44 +128,44 @@ public class GraphQlHttpHandlerTests { .configureGraphQl(builder -> builder.preparsedDocumentProvider(documentProvider)) .toHttpHandler(); - String document = """ - { - "query" : "{__typename}", - "extensions": { - "persistedQuery": { - "version":1, - "sha256Hash":"ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38" - } - } - }"""; + SerializableGraphQlRequest request = new SerializableGraphQlRequest(); + request.setQuery("{__typename}"); + request.setExtensions(Map.of("persistedQuery", Map.of( + "version", "1", + "sha256Hash", "ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38"))); - MockHttpServletResponse servletResponse = handleRequest(createServletRequest(document, "*/*"), handler); - assertThat(servletResponse.getContentAsString()).isEqualTo("{\"data\":{\"__typename\":\"Query\"}}"); + MockHttpServletResponse response = handleRequest(createServletRequest(request, "*/*"), handler); + assertThat(response.getContentAsString()).isEqualTo("{\"data\":{\"__typename\":\"Query\"}}"); - document = """ - { - "extensions":{ - "persistedQuery":{ - "version":1, - "sha256Hash":"ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38" - } - } - }"""; + request = new SerializableGraphQlRequest(); + request.setQuery("{__typename}"); + request.setExtensions(Map.of("persistedQuery", Map.of( + "version", "1", + "sha256Hash", "ecf4edb46db40b5132295c0291d62fb65d6759a9eedfa4d5d612dd5ec54a6b38"))); - servletResponse = handleRequest(createServletRequest(document, "*/*"), handler); - assertThat(servletResponse.getContentAsString()).isEqualTo("{\"data\":{\"__typename\":\"Query\"}}"); + response = handleRequest(createServletRequest(request, "*/*"), handler); + assertThat(response.getContentAsString()).isEqualTo("{\"data\":{\"__typename\":\"Query\"}}"); } + private MockHttpServletRequest createServletRequest(String document, String accept) throws Exception { + SerializableGraphQlRequest request = new SerializableGraphQlRequest(); + request.setQuery(document); + return createServletRequest(request, accept); + } - private MockHttpServletRequest createServletRequest(String query, String accept) { + private MockHttpServletRequest createServletRequest(SerializableGraphQlRequest request, String accept) throws Exception { MockHttpServletRequest servletRequest = new MockHttpServletRequest("POST", "/"); servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE); - servletRequest.setContent(query.getBytes(StandardCharsets.UTF_8)); + servletRequest.setContent(initRequestBody(request)); servletRequest.addHeader("Accept", accept); servletRequest.setAsyncSupported(true); return servletRequest; } + private static byte[] initRequestBody(SerializableGraphQlRequest request) throws Exception { + return new ObjectMapper().writeValueAsString(request).getBytes(StandardCharsets.UTF_8); + } + private MockHttpServletResponse handleRequest( MockHttpServletRequest servletRequest, GraphQlHttpHandler handler) throws ServletException, IOException { @@ -180,7 +187,6 @@ public class GraphQlHttpHandlerTests { public List> messageConverters() { return MESSAGE_READERS; } - } }