diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/AbstractDirectTransport.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/AbstractDirectTransport.java new file mode 100644 index 00000000..da972660 --- /dev/null +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/AbstractDirectTransport.java @@ -0,0 +1,76 @@ +/* + * Copyright 2002-2022 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.graphql.test.tester; + +import java.util.List; + +import graphql.ExecutionResult; +import graphql.GraphQLError; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import org.springframework.graphql.GraphQlRequest; +import org.springframework.graphql.RequestOutput; +import org.springframework.graphql.client.GraphQlTransport; +import org.springframework.test.util.AssertionErrors; +import org.springframework.util.AlternativeJdkIdGenerator; +import org.springframework.util.CollectionUtils; +import org.springframework.util.IdGenerator; + +/** + * Abstract base class for a {@link GraphQlTransport} that makes a direct call + * to a server-side GraphQL handler or service. + * + * @author Rossen Stoyanchev + * @since 1.0.0 + */ +abstract class AbstractDirectTransport implements GraphQlTransport { + + protected static final IdGenerator idGenerator = new AlternativeJdkIdGenerator(); + + + @Override + public Mono execute(GraphQlRequest request) { + return executeInternal(request).cast(ExecutionResult.class); + } + + @SuppressWarnings({"ConstantConditions", "unchecked"}) + @Override + public Flux executeSubscription(GraphQlRequest request) { + return executeInternal(request).flatMapMany(result -> { + try { + Object data = result.getData(); + AssertionErrors.assertTrue("Not a Publisher: " + data, data instanceof Publisher); + + List errors = result.getErrors(); + AssertionErrors.assertTrue("Subscription errors: " + errors, CollectionUtils.isEmpty(errors)); + + return Flux.from((Publisher) data); + } + catch (AssertionError ex) { + throw new AssertionError(ex.getMessage() + "\nRequest: " + request, ex); + } + }); + } + + /** + * Subclasses must implement this to execute requests. + */ + protected abstract Mono executeInternal(GraphQlRequest request); + +} diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DirectRequestStrategySupport.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DirectRequestStrategySupport.java deleted file mode 100644 index 85286bb3..00000000 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DirectRequestStrategySupport.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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.graphql.test.tester; - -import java.time.Duration; -import java.util.function.Consumer; -import java.util.function.Predicate; - -import com.jayway.jsonpath.Configuration; -import graphql.ExecutionResult; -import graphql.GraphQLError; -import org.reactivestreams.Publisher; -import reactor.core.publisher.Flux; - -import org.springframework.graphql.RequestInput; -import org.springframework.lang.Nullable; -import org.springframework.test.util.AssertionErrors; -import org.springframework.util.CollectionUtils; - -/** - * Base class for a {@link RequestStrategy} that performs GraphQL requests - * directly against a GraphQL Java server, i.e. without a client. - * - * @author Rossen Stoyanchev - * @since 1.0.0 - */ -class DirectRequestStrategySupport extends RequestStrategySupport { - - - protected DirectRequestStrategySupport( - @Nullable Predicate errorFilter, Configuration jsonPathConfig, Duration timeout) { - - super(errorFilter, jsonPathConfig, timeout); - } - - - protected GraphQlTester.ResponseSpec createResponseSpec(RequestInput input, ExecutionResult result) { - return createResponseSpec(result, assertDecorator(input)); - } - - protected GraphQlTester.SubscriptionSpec createSubscriptionSpec(RequestInput input, ExecutionResult result) { - Consumer assertDecorator = assertDecorator(input); - - assertDecorator.accept(() -> AssertionErrors.assertTrue( - "Subscription did not return Publisher", - result.getData() instanceof Publisher)); - - assertDecorator.accept(() -> AssertionErrors.assertTrue( - "Response has " + result.getErrors().size() + " unexpected error(s).", - CollectionUtils.isEmpty(result.getErrors()))); - - return () -> { - Publisher publisher = result.getData(); - return Flux.from(publisher).map((current) -> createResponseSpec(current, assertDecorator)); - }; - } - - private Consumer assertDecorator(RequestInput input) { - return (assertion) -> { - try { - assertion.run(); - } - catch (AssertionError ex) { - throw new AssertionError(ex.getMessage() + "\nRequest: " + input, ex); - } - }; - } - -} diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlServiceRequestStrategy.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlServiceRequestStrategy.java deleted file mode 100644 index bea51b66..00000000 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlServiceRequestStrategy.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.graphql.test.tester; - -import java.time.Duration; -import java.util.function.Predicate; - -import com.jayway.jsonpath.Configuration; -import graphql.ExecutionResult; -import graphql.GraphQLError; - -import org.springframework.graphql.GraphQlService; -import org.springframework.graphql.RequestInput; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; - -/** - * {@link RequestStrategy} that performs requests via {@link GraphQlService}. - * - * @author Rossen Stoyanchev - * @since 1.0.0 - */ -final class GraphQlServiceRequestStrategy extends DirectRequestStrategySupport implements RequestStrategy { - - private final GraphQlService graphQlService; - - - public GraphQlServiceRequestStrategy(GraphQlService service, - @Nullable Predicate errorFilter, Configuration jsonPathConfig, Duration timeout) { - - super(errorFilter, jsonPathConfig, timeout); - Assert.notNull(service, "GraphQlService is required."); - this.graphQlService = service; - } - - - @Override - public GraphQlTester.ResponseSpec execute(RequestInput input) { - return createResponseSpec(input, executeInternal(input)); - } - - @Override - public GraphQlTester.SubscriptionSpec executeSubscription(RequestInput input) { - return createSubscriptionSpec(input, executeInternal(input)); - } - - private ExecutionResult executeInternal(RequestInput input) { - ExecutionResult result = this.graphQlService.execute(input).block(getResponseTimeout()); - Assert.notNull(result, "Expected ExecutionResult"); - return result; - } - -} diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlServiceTransport.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlServiceTransport.java new file mode 100644 index 00000000..1c911e50 --- /dev/null +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlServiceTransport.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2022 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.graphql.test.tester; + + +import reactor.core.publisher.Mono; + +import org.springframework.graphql.GraphQlRequest; +import org.springframework.graphql.GraphQlService; +import org.springframework.graphql.RequestInput; +import org.springframework.graphql.RequestOutput; +import org.springframework.util.Assert; + + +/** + * {@code GraphQlTransport} that calls directly a {@link GraphQlService}. + * + * @author Rossen Stoyanchev + * @since 1.0.0 + */ +final class GraphQlServiceTransport extends AbstractDirectTransport { + + private final GraphQlService graphQlService; + + + GraphQlServiceTransport(GraphQlService graphQlService) { + Assert.notNull(graphQlService, "GraphQlService is required"); + this.graphQlService = graphQlService; + } + + + public GraphQlService getGraphQlService() { + return this.graphQlService; + } + + @Override + protected Mono executeInternal(GraphQlRequest request) { + + RequestInput requestInput = new RequestInput( + request.getDocument(), request.getOperationName(), request.getVariables(), + idGenerator.generateId().toString(), null); + + return this.graphQlService.execute(requestInput); + } + +} diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/RequestStrategy.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/RequestStrategy.java deleted file mode 100644 index 8f4ba4c9..00000000 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/RequestStrategy.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.graphql.test.tester; - -import org.springframework.graphql.RequestInput; - -/** - * Abstracts how a GraphQL request is performed, given {@link RequestInput}, and - * resulting in the creation of a response spec. - * - *

For internal use use from {@link DefaultGraphQlTester}. - * - * @author Rossen Stoyanchev - * @since 1.0.0 - */ -interface RequestStrategy { - - /** - * Perform a request with the given {@link RequestInput} container. - * @param input the request input - * @return the response spec - */ - GraphQlTester.ResponseSpec execute(RequestInput input); - - /** - * Perform a subscription with the given {@link RequestInput} container. - * @param input the request input - * @return the subscription spec - */ - GraphQlTester.SubscriptionSpec executeSubscription(RequestInput input); - -} diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/RequestStrategySupport.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/RequestStrategySupport.java deleted file mode 100644 index 0b1a6e13..00000000 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/RequestStrategySupport.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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.graphql.test.tester; - -import java.time.Duration; -import java.util.function.Consumer; -import java.util.function.Predicate; - -import com.jayway.jsonpath.Configuration; -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import graphql.ExecutionResult; -import graphql.GraphQLError; - -import org.springframework.lang.Nullable; - -/** - * Base class support for {@link RequestStrategy} and - * {@link WebRequestStrategy} implementations. - * - * @author Rossen Stoyanchev - * @since 1.0.0 - */ -class RequestStrategySupport { - - @Nullable - private final Predicate errorFilter; - - private final Configuration jsonPathConfig; - - private final Duration responseTimeout; - - - protected RequestStrategySupport( - @Nullable Predicate errorFilter, Configuration jsonPathConfig, Duration timeout) { - - this.errorFilter = errorFilter; - this.jsonPathConfig = jsonPathConfig; - this.responseTimeout = timeout; - } - - - protected Configuration getJsonPathConfig() { - return this.jsonPathConfig; - } - - protected Duration getResponseTimeout() { - return this.responseTimeout; - } - - protected GraphQlTester.ResponseSpec createResponseSpec( - ExecutionResult result, Consumer assertDecorator) { - - DocumentContext context = JsonPath.parse(result.toSpecification(), this.jsonPathConfig); - return createResponseSpec(context, assertDecorator); - } - - protected GraphQlTester.ResponseSpec createResponseSpec( - DocumentContext context, Consumer assertDecorator) { - - return DefaultGraphQlTester.createResponseSpec(context, this.errorFilter, assertDecorator); - } - -} diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebGraphQlHandlerRequestStrategy.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebGraphQlHandlerRequestStrategy.java deleted file mode 100644 index 4e704014..00000000 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebGraphQlHandlerRequestStrategy.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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.graphql.test.tester; - -import java.time.Duration; -import java.util.function.Predicate; - -import com.jayway.jsonpath.Configuration; -import graphql.GraphQLError; - -import org.springframework.graphql.web.WebGraphQlHandler; -import org.springframework.graphql.web.WebInput; -import org.springframework.graphql.web.WebOutput; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; - -/** - * {@link WebRequestStrategy} that performs requests directly against a - * {@link WebGraphQlHandler}, i.e. without a client. - * - * @author Rossen Stoyanchev - * @since 1.0.0 - */ -class WebGraphQlHandlerRequestStrategy extends DirectRequestStrategySupport implements WebRequestStrategy { - - private final WebGraphQlHandler graphQlHandler; - - - WebGraphQlHandlerRequestStrategy(WebGraphQlHandler handler, - @Nullable Predicate errorFilter, Configuration jsonPathConfig, Duration timeout) { - - super(errorFilter, jsonPathConfig, timeout); - this.graphQlHandler = handler; - } - - - @Override - public WebGraphQlTester.WebResponseSpec execute(WebInput input) { - WebOutput webOutput = executeInternal(input); - GraphQlTester.ResponseSpec responseSpec = createResponseSpec(input, webOutput); - return DefaultWebGraphQlTester.createResponseSpec(responseSpec, webOutput.getResponseHeaders()); - } - - @Override - public WebGraphQlTester.WebSubscriptionSpec executeSubscription(WebInput input) { - WebOutput webOutput = executeInternal(input); - GraphQlTester.SubscriptionSpec subscriptionSpec = createSubscriptionSpec(input, webOutput); - return DefaultWebGraphQlTester.createSubscriptionSpec(subscriptionSpec, webOutput.getResponseHeaders()); - } - - private WebOutput executeInternal(WebInput webInput) { - WebOutput webOutput = this.graphQlHandler.handleRequest(webInput).block(getResponseTimeout()); - Assert.notNull(webOutput, "Expected WebOutput"); - return webOutput; - } - -} diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebGraphQlHandlerTransport.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebGraphQlHandlerTransport.java new file mode 100644 index 00000000..ed3bad49 --- /dev/null +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebGraphQlHandlerTransport.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2022 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.graphql.test.tester; + + +import java.net.URI; + +import reactor.core.publisher.Mono; + +import org.springframework.graphql.GraphQlRequest; +import org.springframework.graphql.web.WebGraphQlHandler; +import org.springframework.graphql.web.WebInput; +import org.springframework.graphql.web.WebOutput; +import org.springframework.http.HttpHeaders; +import org.springframework.lang.Nullable; + + +/** + * {@code GraphQlTransport} that calls directly a {@link WebGraphQlHandler}. + * + * @author Rossen Stoyanchev + * @since 1.0.0 + */ +final class WebGraphQlHandlerTransport extends AbstractDirectTransport { + + private final URI url; + + private final HttpHeaders headers = new HttpHeaders(); + + private final WebGraphQlHandler graphQlHandler; + + + WebGraphQlHandlerTransport(@Nullable URI url, HttpHeaders headers, WebGraphQlHandler graphQlHandler) { + this.url = (url != null ? url : URI.create("")); + this.headers.addAll(headers); + this.graphQlHandler = graphQlHandler; + } + + + public URI getUrl() { + return this.url; + } + + public HttpHeaders getHeaders() { + return this.headers; + } + + public WebGraphQlHandler getGraphQlHandler() { + return this.graphQlHandler; + } + + + @Override + protected Mono executeInternal(GraphQlRequest request) { + return this.graphQlHandler.handleRequest( + new WebInput(this.url, this.headers, request.toMap(), idGenerator.generateId().toString(), null)); + } + +} diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebRequestStrategy.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebRequestStrategy.java deleted file mode 100644 index 3f758f73..00000000 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebRequestStrategy.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.graphql.test.tester; - -import org.springframework.graphql.web.WebInput; - -/** - * Abstracts how a GraphQL request is performed in the a Web context, given - * {@link WebInput}, and resulting in the creation of a response spec. - * - *

For internal use use from {@link DefaultWebGraphQlTester}. - * - * @author Rossen Stoyanchev - * @since 1.0.0 - */ -interface WebRequestStrategy { - - /** - * Perform a request with the given {@link WebInput}. - * @param input the request input - * @return the response spec - */ - WebGraphQlTester.WebResponseSpec execute(WebInput input); - - /** - * Perform a subscription with the given {@link WebInput}. - * @param input the request input - * @return the subscription spec - */ - WebGraphQlTester.WebSubscriptionSpec executeSubscription(WebInput input); - -} diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebTestClientRequestStrategy.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebTestClientRequestStrategy.java deleted file mode 100644 index 59c7ff98..00000000 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebTestClientRequestStrategy.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2002-2022 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.graphql.test.tester; - -import java.nio.charset.StandardCharsets; -import java.time.Duration; -import java.util.Collections; -import java.util.Locale; -import java.util.function.Predicate; - -import com.jayway.jsonpath.Configuration; -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import graphql.GraphQLError; -import reactor.core.publisher.Flux; - -import org.springframework.graphql.web.WebInput; -import org.springframework.http.MediaType; -import org.springframework.lang.Nullable; -import org.springframework.test.web.reactive.server.EntityExchangeResult; -import org.springframework.test.web.reactive.server.FluxExchangeResult; -import org.springframework.test.web.reactive.server.WebTestClient; -import org.springframework.util.Assert; - -/** - * {@link WebRequestStrategy} that uses {@link WebTestClient} to perform - * requests. Depending on how the client is configured, this may be used with - * Spring MVC and WebFlux controllers, without a server, or against a live server. - * - * @author Rossen Stoyanchev - * @since 1.0.0 - */ -final class WebTestClientRequestStrategy extends RequestStrategySupport implements WebRequestStrategy { - - private final WebTestClient client; - - - WebTestClientRequestStrategy(WebTestClient client, - @Nullable Predicate errorFilter, Configuration jsonPathConfig, Duration responseTimeout) { - - super(errorFilter, jsonPathConfig, responseTimeout); - this.client = client; - } - - - @Override - public WebGraphQlTester.WebResponseSpec execute(WebInput webInput) { - EntityExchangeResult result = this.client.post() - .contentType(MediaType.APPLICATION_JSON) - .headers(headers -> headers.putAll(webInput.getHeaders())) - .bodyValue(webInput.toMap()) - .exchange() - .expectStatus() - .isOk() - .expectHeader() - .contentTypeCompatibleWith(MediaType.APPLICATION_JSON) - .expectBody() - .returnResult(); - - byte[] bytes = result.getResponseBodyContent(); - Assert.notNull(bytes, "Expected GraphQL response content"); - String content = new String(bytes, StandardCharsets.UTF_8); - - DocumentContext documentContext = JsonPath.parse(content, getJsonPathConfig()); - GraphQlTester.ResponseSpec responseSpec = createResponseSpec(documentContext, result::assertWithDiagnostics); - return DefaultWebGraphQlTester.createResponseSpec(responseSpec, result.getResponseHeaders()); - } - - @Override - public WebGraphQlTester.WebSubscriptionSpec executeSubscription(WebInput webInput) { - FluxExchangeResult exchangeResult = this.client.post() - .contentType(MediaType.APPLICATION_JSON) - .accept(MediaType.TEXT_EVENT_STREAM) - .headers(headers -> { - Locale locale = webInput.getLocale(); - if (locale != null) { - headers.setAcceptLanguageAsLocales(Collections.singletonList(locale)); - } - headers.putAll(webInput.getHeaders()); - }) - .bodyValue(webInput.toMap()) - .exchange() - .expectStatus() - .isOk() - .expectHeader() - .contentType(MediaType.TEXT_EVENT_STREAM) - .returnResult(TestExecutionResult.class); - - Flux flux = exchangeResult.getResponseBody() - .map((result) -> createResponseSpec(result, exchangeResult::assertWithDiagnostics)); - - return DefaultWebGraphQlTester.createSubscriptionSpec(() -> flux, exchangeResult.getResponseHeaders()); - } - -} diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebTestClientTransport.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebTestClientTransport.java new file mode 100644 index 00000000..b16218d4 --- /dev/null +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/WebTestClientTransport.java @@ -0,0 +1,79 @@ +/* + * Copyright 2002-2022 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.graphql.test.tester; + +import java.util.Collections; +import java.util.Map; + +import graphql.ExecutionResult; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.graphql.GraphQlRequest; +import org.springframework.graphql.client.GraphQlTransport; +import org.springframework.graphql.support.MapExecutionResult; +import org.springframework.http.MediaType; +import org.springframework.test.web.reactive.server.WebTestClient; +import org.springframework.util.Assert; + +/** + * {@code GraphQlTransport} for GraphQL over HTTP via {@link WebTestClient}. + * + * @author Rossen Stoyanchev + * @since 1.0.0 + */ +final class WebTestClientTransport implements GraphQlTransport { + + private static final ParameterizedTypeReference> MAP_TYPE = + new ParameterizedTypeReference>() {}; + + + private final WebTestClient webTestClient; + + + WebTestClientTransport(WebTestClient webTestClient) { + Assert.notNull(webTestClient, "WebTestClient is required"); + this.webTestClient = webTestClient; + } + + + @Override + public Mono execute(GraphQlRequest request) { + + Map resultMap = this.webTestClient.post() + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .bodyValue(request.toMap()) + .exchange() + .expectStatus().isOk() + .expectHeader().contentTypeCompatibleWith(MediaType.APPLICATION_JSON) + .expectBody(MAP_TYPE) + .returnResult() + .getResponseBody(); + + resultMap = (resultMap != null ? resultMap : Collections.emptyMap()); + ExecutionResult result = MapExecutionResult.from(resultMap); + return Mono.just(result); + } + + @Override + public Flux executeSubscription(GraphQlRequest request) { + throw new UnsupportedOperationException("Subscriptions not supported over HTTP"); + } + +}