Make GraphQlTester builders and request strategies top level classes
This commit is contained in:
@@ -16,38 +16,26 @@
|
||||
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import com.jayway.jsonpath.DocumentContext;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
import com.jayway.jsonpath.PathNotFoundException;
|
||||
import com.jayway.jsonpath.TypeRef;
|
||||
import com.jayway.jsonpath.spi.json.JacksonJsonProvider;
|
||||
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
|
||||
import graphql.ExecutionResult;
|
||||
import graphql.GraphQLError;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.graphql.GraphQlService;
|
||||
import org.springframework.graphql.RequestInput;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.util.AssertionErrors;
|
||||
import org.springframework.test.util.JsonExpectationsHelper;
|
||||
import org.springframework.test.util.JsonPathExpectationsHelper;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -74,280 +62,30 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
|
||||
|
||||
/**
|
||||
* Base class support for
|
||||
* {@link GraphQlTester.Builder} and {@link WebGraphQlTester.Builder}.
|
||||
* Factory for {@link GraphQlTester.ResponseSpec}, for use from
|
||||
* {@link RequestStrategy} implementations.
|
||||
*
|
||||
* @param documentContext the parsed response content
|
||||
* @param errorFilter a globally defined filter for expected errors (to be ignored)
|
||||
* @param assertDecorator decorator to apply around assertions, e.g. to add extra
|
||||
*/
|
||||
static class BuilderSupport {
|
||||
static GraphQlTester.ResponseSpec createResponseSpec(
|
||||
DocumentContext documentContext, @Nullable Predicate<GraphQLError> errorFilter,
|
||||
Consumer<Runnable> assertDecorator) {
|
||||
|
||||
@Nullable
|
||||
private Predicate<GraphQLError> errorFilter;
|
||||
|
||||
@Nullable
|
||||
private Configuration jsonPathConfig;
|
||||
|
||||
@Nullable
|
||||
private Duration responseTimeout = Duration.ofSeconds(5);
|
||||
|
||||
protected void addErrorFilter(Predicate<GraphQLError> predicate) {
|
||||
this.errorFilter = (this.errorFilter != null ? errorFilter.and(predicate) : predicate);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Predicate<GraphQLError> getErrorFilter() {
|
||||
return errorFilter;
|
||||
}
|
||||
|
||||
protected void setJsonPathConfig(Configuration config) {
|
||||
this.jsonPathConfig = config;
|
||||
}
|
||||
|
||||
protected void setResponseTimeout(Duration timeout) {
|
||||
Assert.notNull(timeout, "'timeout' is required");
|
||||
this.responseTimeout = timeout;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Duration getResponseTimeout() {
|
||||
return this.responseTimeout;
|
||||
}
|
||||
|
||||
protected Configuration initJsonPathConfig() {
|
||||
return JsonPathConfiguration.initialize(this.jsonPathConfig);
|
||||
}
|
||||
|
||||
protected Duration initResponseTimeout() {
|
||||
return (this.responseTimeout != null ? this.responseTimeout : Duration.ofSeconds(5));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation to build {@link GraphQlTester}.
|
||||
*/
|
||||
static class DefaultBuilder extends BuilderSupport implements Builder<DefaultBuilder> {
|
||||
|
||||
private final GraphQlService service;
|
||||
|
||||
DefaultBuilder(GraphQlService service) {
|
||||
Assert.notNull(service, "GraphQlService is required.");
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultBuilder errorFilter(Predicate<GraphQLError> predicate) {
|
||||
addErrorFilter(predicate);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultBuilder jsonPathConfig(Configuration config) {
|
||||
setJsonPathConfig(config);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultBuilder responseTimeout(Duration timeout) {
|
||||
setResponseTimeout(timeout);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphQlTester build() {
|
||||
RequestStrategy strategy = new GraphQlServiceRequestStrategy(
|
||||
this.service, getErrorFilter(), initJsonPathConfig(), initResponseTimeout());
|
||||
|
||||
return new DefaultGraphQlTester(strategy);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal strategy abstracting how a GraphQL request is performed.
|
||||
*/
|
||||
interface RequestStrategy {
|
||||
|
||||
/**
|
||||
* Perform a request with the given {@link RequestInput} container.
|
||||
* @param input the request input
|
||||
* @return the response spec
|
||||
*/
|
||||
ResponseSpec execute(RequestInput input);
|
||||
|
||||
/**
|
||||
* Perform a subscription with the given {@link RequestInput} container.
|
||||
* @param input the request input
|
||||
* @return the subscription spec
|
||||
*/
|
||||
SubscriptionSpec executeSubscription(RequestInput input);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class support for {@link RequestStrategy} and
|
||||
* {@link DefaultWebGraphQlTester.WebRequestStrategy} implementations.
|
||||
*/
|
||||
static class RequestStrategySupport {
|
||||
|
||||
@Nullable
|
||||
private final Predicate<GraphQLError> errorFilter;
|
||||
|
||||
private final Configuration jsonPathConfig;
|
||||
|
||||
private final Duration responseTimeout;
|
||||
|
||||
protected RequestStrategySupport(
|
||||
@Nullable Predicate<GraphQLError> 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 ResponseSpec createResponseSpec(ExecutionResult result, Consumer<Runnable> assertDecorator) {
|
||||
DocumentContext context = JsonPath.parse(result.toSpecification(), this.jsonPathConfig);
|
||||
return createResponseSpec(context, assertDecorator);
|
||||
}
|
||||
|
||||
protected ResponseSpec createResponseSpec(DocumentContext context, Consumer<Runnable> assertDecorator) {
|
||||
return new DefaultResponseSpec(context, this.errorFilter, assertDecorator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for a {@link RequestStrategy} that perform GraphQL requests
|
||||
* without an underlying transport and where {@link RequestInput} provides
|
||||
* sufficient input.
|
||||
*/
|
||||
static class DirectRequestStrategySupport extends RequestStrategySupport {
|
||||
|
||||
protected DirectRequestStrategySupport(
|
||||
@Nullable Predicate<GraphQLError> errorFilter, Configuration jsonPathConfig, Duration timeout) {
|
||||
|
||||
super(errorFilter, jsonPathConfig, timeout);
|
||||
}
|
||||
|
||||
protected ResponseSpec createResponseSpec(RequestInput input, ExecutionResult result) {
|
||||
return createResponseSpec(result, assertDecorator(input));
|
||||
}
|
||||
|
||||
protected SubscriptionSpec createSubscriptionSpec(RequestInput input, ExecutionResult result) {
|
||||
Consumer<Runnable> 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<? extends ExecutionResult> publisher = result.getData();
|
||||
return Flux.from(publisher).map((current) -> createResponseSpec(current, assertDecorator));
|
||||
};
|
||||
}
|
||||
|
||||
private Consumer<Runnable> assertDecorator(RequestInput input) {
|
||||
return (assertion) -> {
|
||||
try {
|
||||
assertion.run();
|
||||
}
|
||||
catch (AssertionError ex) {
|
||||
throw new AssertionError(ex.getMessage() + "\nRequest: " + input, ex);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link RequestStrategy} that performs requests through a {@link GraphQlService}.
|
||||
*/
|
||||
protected static class GraphQlServiceRequestStrategy
|
||||
extends DirectRequestStrategySupport implements RequestStrategy {
|
||||
|
||||
private final GraphQlService graphQlService;
|
||||
|
||||
protected GraphQlServiceRequestStrategy(GraphQlService service,
|
||||
@Nullable Predicate<GraphQLError> errorFilter, Configuration jsonPathConfig, Duration timeout) {
|
||||
|
||||
super(errorFilter, jsonPathConfig, timeout);
|
||||
Assert.notNull(service, "GraphQlService is required.");
|
||||
this.graphQlService = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseSpec execute(RequestInput input) {
|
||||
return createResponseSpec(input, executeInternal(input));
|
||||
}
|
||||
|
||||
@Override
|
||||
public 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class support for
|
||||
* {@link GraphQlTester.RequestSpec} and {@link WebGraphQlTester.RequestSpec}.
|
||||
*/
|
||||
static class RequestSpecSupport {
|
||||
|
||||
private final String query;
|
||||
|
||||
@Nullable
|
||||
private String operationName;
|
||||
|
||||
private final Map<String, Object> variables = new LinkedHashMap<>();
|
||||
|
||||
protected RequestSpecSupport(String query) {
|
||||
Assert.notNull(query, "`query` is required");
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
protected void setOperationName(@Nullable String name) {
|
||||
this.operationName = name;
|
||||
}
|
||||
|
||||
protected void addVariable(String name, Object value) {
|
||||
this.variables.put(name, value);
|
||||
}
|
||||
|
||||
protected void verify(ResponseSpec responseSpec) {
|
||||
responseSpec.path("$.errors").valueIsEmpty();
|
||||
}
|
||||
|
||||
protected RequestInput createRequestInput() {
|
||||
return new RequestInput(this.query, this.operationName, this.variables);
|
||||
}
|
||||
return new DefaultResponseSpec(documentContext, errorFilter, assertDecorator);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link RequestSpec} that collects the query, operationName, and variables.
|
||||
*/
|
||||
static class DefaultRequestSpec extends RequestSpecSupport implements RequestSpec<DefaultRequestSpec> {
|
||||
private static final class DefaultRequestSpec
|
||||
extends GraphQlTesterRequestSpecSupport implements RequestSpec<DefaultRequestSpec> {
|
||||
|
||||
private final RequestStrategy requestStrategy;
|
||||
|
||||
protected DefaultRequestSpec(RequestStrategy requestStrategy, String query) {
|
||||
private DefaultRequestSpec(RequestStrategy requestStrategy, String query) {
|
||||
super(query);
|
||||
Assert.notNull(requestStrategy, "RequestStrategy is required");
|
||||
this.requestStrategy = requestStrategy;
|
||||
@@ -383,9 +121,9 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
|
||||
|
||||
/**
|
||||
* Container for a GraphQL response with access to data and errors.
|
||||
* Container for GraphQL response data and errors along with convenience methods.
|
||||
*/
|
||||
private static class ResponseContainer {
|
||||
private final static class ResponseContainer {
|
||||
|
||||
private static final TypeRef<List<TestGraphQlError>> ERROR_LIST_TYPE = new TypeRef<List<TestGraphQlError>>() {};
|
||||
|
||||
@@ -403,7 +141,7 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
private final Consumer<Runnable> assertDecorator;
|
||||
|
||||
|
||||
ResponseContainer(
|
||||
private ResponseContainer(
|
||||
DocumentContext documentContext, @Nullable Predicate<GraphQLError> errorFilter,
|
||||
Consumer<Runnable> assertDecorator) {
|
||||
|
||||
@@ -482,17 +220,11 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
/**
|
||||
* {@link ResponseSpec} that operates on the response from a GraphQL HTTP request.
|
||||
*/
|
||||
protected static final class DefaultResponseSpec implements ResponseSpec, ErrorSpec {
|
||||
private static final class DefaultResponseSpec implements ResponseSpec, ErrorSpec {
|
||||
|
||||
private final ResponseContainer responseContainer;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
* @param documentContext the parsed response content
|
||||
* @param errorFilter a globally defined filter for expected errors (to be ignored)
|
||||
* @param assertDecorator decorator to apply around assertions, e.g. to add extra
|
||||
*/
|
||||
protected DefaultResponseSpec(
|
||||
private DefaultResponseSpec(
|
||||
DocumentContext documentContext, @Nullable Predicate<GraphQLError> errorFilter,
|
||||
Consumer<Runnable> assertDecorator) {
|
||||
|
||||
@@ -533,7 +265,7 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
/**
|
||||
* {@link PathSpec} implementation.
|
||||
*/
|
||||
private static class DefaultPathSpec implements PathSpec {
|
||||
private static final class DefaultPathSpec implements PathSpec {
|
||||
|
||||
private final String inputPath;
|
||||
|
||||
@@ -543,7 +275,7 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
|
||||
private final JsonPathExpectationsHelper pathHelper;
|
||||
|
||||
DefaultPathSpec(String path, ResponseContainer responseContainer) {
|
||||
private DefaultPathSpec(String path, ResponseContainer responseContainer) {
|
||||
Assert.notNull(path, "`path` is required");
|
||||
Assert.notNull(responseContainer, "ResponseContainer is required");
|
||||
this.inputPath = path;
|
||||
@@ -678,7 +410,7 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
|
||||
private final String inputPath;
|
||||
|
||||
DefaultEntitySpec(D entity, ResponseContainer responseContainer, String path) {
|
||||
protected DefaultEntitySpec(D entity, ResponseContainer responseContainer, String path) {
|
||||
this.entity = entity;
|
||||
this.responseContainer = responseContainer;
|
||||
this.inputPath = path;
|
||||
@@ -753,10 +485,10 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
/**
|
||||
* {@link ListEntitySpec} implementation.
|
||||
*/
|
||||
private static class DefaultListEntitySpec<E> extends DefaultEntitySpec<List<E>, ListEntitySpec<E>>
|
||||
private static final class DefaultListEntitySpec<E> extends DefaultEntitySpec<List<E>, ListEntitySpec<E>>
|
||||
implements ListEntitySpec<E> {
|
||||
|
||||
DefaultListEntitySpec(List<E> entity, ResponseContainer responseContainer, String path) {
|
||||
private DefaultListEntitySpec(List<E> entity, ResponseContainer responseContainer, String path) {
|
||||
super(entity, responseContainer, path);
|
||||
}
|
||||
|
||||
@@ -766,7 +498,7 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
doAssert(() -> {
|
||||
List<E> expected = Arrays.asList(elements);
|
||||
AssertionErrors.assertTrue("List at path '" + getInputPath() + "' does not contain " + expected,
|
||||
(getEntity() != null && getEntity().containsAll(expected)));
|
||||
getEntity().containsAll(expected));
|
||||
});
|
||||
return this;
|
||||
}
|
||||
@@ -778,7 +510,7 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
List<E> expected = Arrays.asList(elements);
|
||||
AssertionErrors.assertTrue(
|
||||
"List at path '" + getInputPath() + "' should not have contained " + expected,
|
||||
(getEntity() == null || !getEntity().containsAll(expected)));
|
||||
!getEntity().containsAll(expected));
|
||||
});
|
||||
return this;
|
||||
}
|
||||
@@ -790,7 +522,7 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
List<E> expected = Arrays.asList(elements);
|
||||
AssertionErrors.assertTrue(
|
||||
"List at path '" + getInputPath() + "' should have contained exactly " + expected,
|
||||
(getEntity() != null && getEntity().containsAll(expected)));
|
||||
getEntity().containsAll(expected));
|
||||
});
|
||||
return this;
|
||||
}
|
||||
@@ -798,7 +530,7 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
@Override
|
||||
public ListEntitySpec<E> hasSize(int size) {
|
||||
doAssert(() -> AssertionErrors.assertTrue("List at path '" + getInputPath() + "' should have size " + size,
|
||||
(getEntity() != null && getEntity().size() == size)));
|
||||
getEntity().size() == size));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -806,7 +538,7 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
public ListEntitySpec<E> hasSizeLessThan(int boundary) {
|
||||
doAssert(() -> AssertionErrors.assertTrue(
|
||||
"List at path '" + getInputPath() + "' should have size less than " + boundary,
|
||||
(getEntity() != null && getEntity().size() < boundary)));
|
||||
getEntity().size() < boundary));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -814,45 +546,9 @@ class DefaultGraphQlTester implements GraphQlTester {
|
||||
public ListEntitySpec<E> hasSizeGreaterThan(int boundary) {
|
||||
doAssert(() -> AssertionErrors.assertTrue(
|
||||
"List at path '" + getInputPath() + "' should have size greater than " + boundary,
|
||||
(getEntity() != null && getEntity().size() > boundary)));
|
||||
getEntity().size() > boundary));
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class JsonPathConfiguration {
|
||||
|
||||
private static final boolean jackson2Present;
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = JsonPathConfiguration.class.getClassLoader();
|
||||
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
|
||||
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
|
||||
}
|
||||
|
||||
|
||||
static Configuration initialize(@Nullable Configuration jsonPathConfig) {
|
||||
if (jsonPathConfig != null) {
|
||||
return jsonPathConfig;
|
||||
}
|
||||
else if (jackson2Present) {
|
||||
return Jackson2Configuration.create();
|
||||
}
|
||||
else {
|
||||
return Configuration.builder().build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class Jackson2Configuration {
|
||||
|
||||
static Configuration create() {
|
||||
return Configuration.builder()
|
||||
.jsonProvider(new JacksonJsonProvider())
|
||||
.mappingProvider(new JacksonMappingProvider())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.GraphQlService;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of a {@link GraphQlTester.Builder}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class DefaultGraphQlTesterBuilder
|
||||
extends GraphQlTesterBuilderSupport implements GraphQlTester.Builder<DefaultGraphQlTesterBuilder> {
|
||||
|
||||
private final GraphQlService service;
|
||||
|
||||
|
||||
DefaultGraphQlTesterBuilder(GraphQlService service) {
|
||||
Assert.notNull(service, "GraphQlService is required.");
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DefaultGraphQlTesterBuilder errorFilter(Predicate<GraphQLError> predicate) {
|
||||
addErrorFilter(predicate);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultGraphQlTesterBuilder jsonPathConfig(Configuration config) {
|
||||
setJsonPathConfig(config);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultGraphQlTesterBuilder responseTimeout(Duration timeout) {
|
||||
setResponseTimeout(timeout);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphQlTester build() {
|
||||
RequestStrategy strategy = new GraphQlServiceRequestStrategy(
|
||||
this.service, getErrorFilter(), initJsonPathConfig(), initResponseTimeout());
|
||||
|
||||
return new DefaultGraphQlTester(strategy);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,26 +17,13 @@
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
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.GraphQLError;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
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.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;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@@ -67,215 +54,32 @@ class DefaultWebGraphQlTester implements WebGraphQlTester {
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation to build {@link WebGraphQlTester}.
|
||||
* Factory for {@link WebGraphQlTester.ResponseSpec}, for use from
|
||||
* {@link WebRequestStrategy} implementations.
|
||||
*/
|
||||
final static class DefaultBuilder
|
||||
extends DefaultGraphQlTester.BuilderSupport implements WebGraphQlTester.Builder {
|
||||
static WebResponseSpec createResponseSpec(
|
||||
ResponseSpec responseSpec, @Nullable HttpHeaders responseHeaders) {
|
||||
|
||||
@Nullable
|
||||
private final WebTestClient client;
|
||||
return new DefaultWebResponseSpec(responseSpec, responseHeaders);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private final WebGraphQlHandler handler;
|
||||
/**
|
||||
* Factory for {@link WebGraphQlTester.SubscriptionSpec}, for use from
|
||||
* {@link WebRequestStrategy} implementations.
|
||||
*/
|
||||
static WebSubscriptionSpec createSubscriptionSpec(
|
||||
SubscriptionSpec subscriptionSpec, @Nullable HttpHeaders responseHeaders) {
|
||||
|
||||
@Nullable
|
||||
private HttpHeaders headers;
|
||||
|
||||
DefaultBuilder(WebTestClient client) {
|
||||
Assert.notNull(client, "WebTestClient is required.");
|
||||
this.client = client;
|
||||
this.handler = null;
|
||||
}
|
||||
|
||||
DefaultBuilder(WebGraphQlHandler handler) {
|
||||
Assert.notNull(handler, "WebGraphQlHandler is required.");
|
||||
this.handler = handler;
|
||||
this.client = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebGraphQlTester.Builder errorFilter(Predicate<GraphQLError> predicate) {
|
||||
addErrorFilter(predicate);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultBuilder jsonPathConfig(Configuration config) {
|
||||
setJsonPathConfig(config);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultBuilder responseTimeout(Duration timeout) {
|
||||
setResponseTimeout(timeout);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultBuilder defaultHeader(String headerName, String... headerValues) {
|
||||
this.headers = (this.headers != null ? this.headers : new HttpHeaders());
|
||||
for (String headerValue : headerValues) {
|
||||
this.headers.add(headerName, headerValue);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebGraphQlTester.Builder defaultHeaders(Consumer<HttpHeaders> headersConsumer) {
|
||||
this.headers = (this.headers != null ? this.headers : new HttpHeaders());
|
||||
headersConsumer.accept(this.headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebGraphQlTester build() {
|
||||
WebRequestStrategy requestStrategy;
|
||||
if (this.client != null) {
|
||||
WebTestClient clientToUse = this.client;
|
||||
if (getResponseTimeout() != null) {
|
||||
clientToUse = this.client.mutate().responseTimeout(getResponseTimeout()).build();
|
||||
}
|
||||
requestStrategy = new WebTestClientRequestStrategy(
|
||||
clientToUse, getErrorFilter(), initJsonPathConfig(), getResponseTimeout());
|
||||
}
|
||||
else if (this.handler != null) {
|
||||
requestStrategy = new WebGraphQlHandlerRequestStrategy(
|
||||
this.handler, getErrorFilter(), initJsonPathConfig(), initResponseTimeout());
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Neither client nor handler");
|
||||
}
|
||||
return new DefaultWebGraphQlTester(requestStrategy, this.headers);
|
||||
}
|
||||
return new DefaultWebSubscriptionSpec(subscriptionSpec, responseHeaders);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extension of {@code RequestStrategy} for performing a GraphQL request
|
||||
* in a web environment.
|
||||
* {@link WebRequestSpec} that also collects HTTP request headers, in
|
||||
* addition to the query, operationName, and variables.
|
||||
*/
|
||||
interface WebRequestStrategy {
|
||||
|
||||
/**
|
||||
* Perform a request with the given {@link WebInput} container.
|
||||
* @param input the request input
|
||||
* @return the response spec
|
||||
*/
|
||||
WebResponseSpec execute(WebInput input);
|
||||
|
||||
/**
|
||||
* Perform a subscription with the given {@link WebInput} container.
|
||||
* @param input the request input
|
||||
* @return the subscription spec
|
||||
*/
|
||||
WebSubscriptionSpec executeSubscription(WebInput input);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@link WebRequestStrategy} that works as an HTTP client with requests executed through
|
||||
* {@link WebTestClient} that in turn may work connect with or without a live server
|
||||
* for Spring MVC and WebFlux.
|
||||
*/
|
||||
private static class WebTestClientRequestStrategy
|
||||
extends DefaultGraphQlTester.RequestStrategySupport implements WebRequestStrategy {
|
||||
|
||||
private final WebTestClient client;
|
||||
|
||||
public WebTestClientRequestStrategy(WebTestClient client,
|
||||
@Nullable Predicate<GraphQLError> errorFilter, Configuration jsonPathConfig, Duration responseTimeout) {
|
||||
|
||||
super(errorFilter, jsonPathConfig, responseTimeout);
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebResponseSpec execute(WebInput webInput) {
|
||||
EntityExchangeResult<byte[]> result = this.client.post()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.headers(headers -> headers.putAll(webInput.getHeaders()))
|
||||
.bodyValue(webInput.toMap())
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(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());
|
||||
ResponseSpec responseSpec = createResponseSpec(documentContext, result::assertWithDiagnostics);
|
||||
return new DefaultWebResponseSpec(responseSpec, result.getResponseHeaders());
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSubscriptionSpec executeSubscription(WebInput webInput) {
|
||||
FluxExchangeResult<TestExecutionResult> exchangeResult = this.client.post()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.TEXT_EVENT_STREAM)
|
||||
.headers(headers -> headers.putAll(webInput.getHeaders()))
|
||||
.bodyValue(webInput.toMap())
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(MediaType.TEXT_EVENT_STREAM)
|
||||
.returnResult(TestExecutionResult.class);
|
||||
|
||||
Flux<ResponseSpec> flux = exchangeResult.getResponseBody()
|
||||
.map((result) -> createResponseSpec(result, exchangeResult::assertWithDiagnostics));
|
||||
|
||||
return new DefaultWebSubscriptionSpec(() -> flux, exchangeResult.getResponseHeaders());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link WebRequestStrategy} that performs requests directly on
|
||||
* {@link WebGraphQlHandler}, i.e. Web request testing without a transport.
|
||||
*/
|
||||
private static class WebGraphQlHandlerRequestStrategy
|
||||
extends DefaultGraphQlTester.DirectRequestStrategySupport implements WebRequestStrategy {
|
||||
|
||||
private final WebGraphQlHandler graphQlHandler;
|
||||
|
||||
WebGraphQlHandlerRequestStrategy(WebGraphQlHandler handler,
|
||||
@Nullable Predicate<GraphQLError> errorFilter, Configuration jsonPathConfig, Duration timeout) {
|
||||
|
||||
super(errorFilter, jsonPathConfig, timeout);
|
||||
this.graphQlHandler = handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebResponseSpec execute(WebInput input) {
|
||||
WebOutput webOutput = executeInternal(input);
|
||||
ResponseSpec responseSpec = createResponseSpec(input, webOutput);
|
||||
return new DefaultWebResponseSpec(responseSpec, webOutput.getResponseHeaders());
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSubscriptionSpec executeSubscription(WebInput input) {
|
||||
WebOutput webOutput = executeInternal(input);
|
||||
SubscriptionSpec subscriptionSpec = createSubscriptionSpec(input, webOutput);
|
||||
return new DefaultWebSubscriptionSpec(subscriptionSpec, webOutput.getResponseHeaders());
|
||||
}
|
||||
|
||||
private WebOutput executeInternal(WebInput webInput) {
|
||||
WebOutput webOutput = this.graphQlHandler.handle(webInput).block(getResponseTimeout());
|
||||
Assert.notNull(webOutput, "Expected WebOutput");
|
||||
return webOutput;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static final class DefaultWebRequestSpec
|
||||
extends DefaultGraphQlTester.RequestSpecSupport implements WebRequestSpec {
|
||||
extends GraphQlTesterRequestSpecSupport implements WebRequestSpec {
|
||||
|
||||
private static final URI DEFAULT_URL = URI.create("");
|
||||
|
||||
@@ -283,7 +87,7 @@ class DefaultWebGraphQlTester implements WebGraphQlTester {
|
||||
|
||||
private final HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
DefaultWebRequestSpec(
|
||||
private DefaultWebRequestSpec(
|
||||
WebRequestStrategy requestStrategy, @Nullable HttpHeaders defaultHeaders, String query) {
|
||||
|
||||
super(query);
|
||||
@@ -341,20 +145,24 @@ class DefaultWebGraphQlTester implements WebGraphQlTester {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link WebResponseSpec} that exposes response headers and delegates
|
||||
* all other methods to the given {@link GraphQlTester.ResponseSpec}.
|
||||
*/
|
||||
private static final class DefaultWebResponseSpec implements WebResponseSpec {
|
||||
|
||||
private final ResponseSpec responseSpec;
|
||||
|
||||
private final HttpHeaders headers;
|
||||
private final HttpHeaders responseHeaders;
|
||||
|
||||
public DefaultWebResponseSpec(ResponseSpec responseSpec, @Nullable HttpHeaders headers) {
|
||||
public DefaultWebResponseSpec(ResponseSpec responseSpec, @Nullable HttpHeaders responseHeaders) {
|
||||
this.responseSpec = responseSpec;
|
||||
this.headers = (headers != null ? headers : new HttpHeaders());
|
||||
this.responseHeaders = (responseHeaders != null ? responseHeaders : new HttpHeaders());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseSpec httpHeadersSatisfy(Consumer<HttpHeaders> consumer) {
|
||||
consumer.accept(this.headers);
|
||||
consumer.accept(this.responseHeaders);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -370,13 +178,17 @@ class DefaultWebGraphQlTester implements WebGraphQlTester {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link WebSubscriptionSpec} that exposes response headers and delegates
|
||||
* all other methods to the given {@link GraphQlTester.SubscriptionSpec}.
|
||||
*/
|
||||
private static final class DefaultWebSubscriptionSpec implements WebSubscriptionSpec {
|
||||
|
||||
private final SubscriptionSpec delegate;
|
||||
|
||||
private final HttpHeaders headers;
|
||||
|
||||
public DefaultWebSubscriptionSpec(SubscriptionSpec delegate, @Nullable HttpHeaders headers) {
|
||||
private DefaultWebSubscriptionSpec(SubscriptionSpec delegate, @Nullable HttpHeaders headers) {
|
||||
this.delegate = delegate;
|
||||
this.headers = (headers != null ? headers : new HttpHeaders());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.GraphQLError;
|
||||
|
||||
import org.springframework.graphql.web.WebGraphQlHandler;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of a {@link WebGraphQlTester.Builder}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.0.0
|
||||
*/
|
||||
final class DefaultWebGraphQlTesterBuilder
|
||||
extends GraphQlTesterBuilderSupport implements WebGraphQlTester.Builder {
|
||||
|
||||
@Nullable
|
||||
private final WebTestClient client;
|
||||
|
||||
@Nullable
|
||||
private final WebGraphQlHandler handler;
|
||||
|
||||
@Nullable
|
||||
private HttpHeaders headers;
|
||||
|
||||
|
||||
DefaultWebGraphQlTesterBuilder(WebTestClient client) {
|
||||
Assert.notNull(client, "WebTestClient is required.");
|
||||
this.client = client;
|
||||
this.handler = null;
|
||||
}
|
||||
|
||||
DefaultWebGraphQlTesterBuilder(WebGraphQlHandler handler) {
|
||||
Assert.notNull(handler, "WebGraphQlHandler is required.");
|
||||
this.handler = handler;
|
||||
this.client = null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public WebGraphQlTester.Builder errorFilter(Predicate<GraphQLError> predicate) {
|
||||
addErrorFilter(predicate);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultWebGraphQlTesterBuilder jsonPathConfig(Configuration config) {
|
||||
setJsonPathConfig(config);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultWebGraphQlTesterBuilder responseTimeout(Duration timeout) {
|
||||
setResponseTimeout(timeout);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultWebGraphQlTesterBuilder defaultHeader(String headerName, String... headerValues) {
|
||||
this.headers = (this.headers != null ? this.headers : new HttpHeaders());
|
||||
for (String headerValue : headerValues) {
|
||||
this.headers.add(headerName, headerValue);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebGraphQlTester.Builder defaultHeaders(Consumer<HttpHeaders> headersConsumer) {
|
||||
this.headers = (this.headers != null ? this.headers : new HttpHeaders());
|
||||
headersConsumer.accept(this.headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebGraphQlTester build() {
|
||||
return new DefaultWebGraphQlTester(initRequestStrategy(), this.headers);
|
||||
}
|
||||
|
||||
private WebRequestStrategy initRequestStrategy() {
|
||||
if (this.client != null) {
|
||||
WebTestClient clientToUse = this.client;
|
||||
if (getResponseTimeout() != null) {
|
||||
clientToUse = this.client.mutate().responseTimeout(getResponseTimeout()).build();
|
||||
}
|
||||
return new WebTestClientRequestStrategy(
|
||||
clientToUse, getErrorFilter(), initJsonPathConfig(), getResponseTimeout());
|
||||
}
|
||||
|
||||
if (this.handler != null) {
|
||||
return new WebGraphQlHandlerRequestStrategy(
|
||||
this.handler, getErrorFilter(), initJsonPathConfig(), initResponseTimeout());
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Neither client nor handler");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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<GraphQLError> 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<Runnable> 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<? extends ExecutionResult> publisher = result.getData();
|
||||
return Flux.from(publisher).map((current) -> createResponseSpec(current, assertDecorator));
|
||||
};
|
||||
}
|
||||
|
||||
private Consumer<Runnable> assertDecorator(RequestInput input) {
|
||||
return (assertion) -> {
|
||||
try {
|
||||
assertion.run();
|
||||
}
|
||||
catch (AssertionError ex) {
|
||||
throw new AssertionError(ex.getMessage() + "\nRequest: " + input, ex);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* 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<GraphQLError> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -69,7 +69,7 @@ public interface GraphQlTester {
|
||||
* @return the builder to use
|
||||
*/
|
||||
static Builder<?> builder(GraphQlService service) {
|
||||
return new DefaultGraphQlTester.DefaultBuilder(service);
|
||||
return new DefaultGraphQlTesterBuilder(service);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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 com.jayway.jsonpath.spi.json.JacksonJsonProvider;
|
||||
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
|
||||
import graphql.GraphQLError;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Base class support for implementations of
|
||||
* {@link GraphQlTester.Builder} and {@link WebGraphQlTester.Builder}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class GraphQlTesterBuilderSupport {
|
||||
|
||||
private static final boolean jackson2Present;
|
||||
|
||||
static {
|
||||
ClassLoader classLoader = GraphQlTesterBuilderSupport.class.getClassLoader();
|
||||
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
|
||||
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
|
||||
}
|
||||
|
||||
private static final Duration DEFAULT_RESPONSE_DURATION = Duration.ofSeconds(5);
|
||||
|
||||
|
||||
@Nullable
|
||||
private Predicate<GraphQLError> errorFilter;
|
||||
|
||||
@Nullable
|
||||
private Configuration jsonPathConfig;
|
||||
|
||||
@Nullable
|
||||
private Duration responseTimeout;
|
||||
|
||||
|
||||
protected void addErrorFilter(Predicate<GraphQLError> predicate) {
|
||||
this.errorFilter = (this.errorFilter != null ? errorFilter.and(predicate) : predicate);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Predicate<GraphQLError> getErrorFilter() {
|
||||
return errorFilter;
|
||||
}
|
||||
|
||||
protected void setJsonPathConfig(Configuration config) {
|
||||
this.jsonPathConfig = config;
|
||||
}
|
||||
|
||||
protected void setResponseTimeout(Duration timeout) {
|
||||
Assert.notNull(timeout, "'timeout' is required");
|
||||
this.responseTimeout = timeout;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Duration getResponseTimeout() {
|
||||
return this.responseTimeout;
|
||||
}
|
||||
|
||||
protected Configuration initJsonPathConfig() {
|
||||
if (this.jsonPathConfig != null) {
|
||||
return this.jsonPathConfig;
|
||||
}
|
||||
else if (jackson2Present) {
|
||||
return Jackson2Configuration.create();
|
||||
}
|
||||
else {
|
||||
return Configuration.builder().build();
|
||||
}
|
||||
}
|
||||
|
||||
protected Duration initResponseTimeout() {
|
||||
return (this.responseTimeout != null ? this.responseTimeout : DEFAULT_RESPONSE_DURATION);
|
||||
}
|
||||
|
||||
|
||||
private static class Jackson2Configuration {
|
||||
|
||||
static Configuration create() {
|
||||
return Configuration.builder()
|
||||
.jsonProvider(new JacksonJsonProvider())
|
||||
.mappingProvider(new JacksonMappingProvider())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.graphql.RequestInput;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class support for implementations of
|
||||
* {@link GraphQlTester.RequestSpec} and {@link WebGraphQlTester.RequestSpec}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class GraphQlTesterRequestSpecSupport {
|
||||
|
||||
private final String query;
|
||||
|
||||
@Nullable
|
||||
private String operationName;
|
||||
|
||||
private final Map<String, Object> variables = new LinkedHashMap<>();
|
||||
|
||||
|
||||
protected GraphQlTesterRequestSpecSupport(String query) {
|
||||
Assert.notNull(query, "`query` is required");
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
|
||||
protected void setOperationName(@Nullable String name) {
|
||||
this.operationName = name;
|
||||
}
|
||||
|
||||
protected void addVariable(String name, Object value) {
|
||||
this.variables.put(name, value);
|
||||
}
|
||||
|
||||
protected void verify(GraphQlTester.ResponseSpec responseSpec) {
|
||||
responseSpec.path("$.errors").valueIsEmpty();
|
||||
}
|
||||
|
||||
protected RequestInput createRequestInput() {
|
||||
return new RequestInput(this.query, this.operationName, this.variables);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* <p>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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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<GraphQLError> errorFilter;
|
||||
|
||||
private final Configuration jsonPathConfig;
|
||||
|
||||
private final Duration responseTimeout;
|
||||
|
||||
|
||||
protected RequestStrategySupport(
|
||||
@Nullable Predicate<GraphQLError> 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<Runnable> assertDecorator) {
|
||||
|
||||
DocumentContext context = JsonPath.parse(result.toSpecification(), this.jsonPathConfig);
|
||||
return createResponseSpec(context, assertDecorator);
|
||||
}
|
||||
|
||||
protected GraphQlTester.ResponseSpec createResponseSpec(
|
||||
DocumentContext context, Consumer<Runnable> assertDecorator) {
|
||||
|
||||
return DefaultGraphQlTester.createResponseSpec(context, this.errorFilter, assertDecorator);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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<GraphQLError> 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.handle(webInput).block(getResponseTimeout());
|
||||
Assert.notNull(webOutput, "Expected WebOutput");
|
||||
return webOutput;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -117,7 +117,7 @@ public interface WebGraphQlTester extends GraphQlTester {
|
||||
* @return the builder to use
|
||||
*/
|
||||
static Builder builder(WebTestClient client) {
|
||||
return new DefaultWebGraphQlTester.DefaultBuilder(client);
|
||||
return new DefaultWebGraphQlTesterBuilder(client);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,7 +126,7 @@ public interface WebGraphQlTester extends GraphQlTester {
|
||||
* @return the builder to use
|
||||
*/
|
||||
static Builder builder(WebGraphQlHandler handler) {
|
||||
return new DefaultWebGraphQlTester.DefaultBuilder(handler);
|
||||
return new DefaultWebGraphQlTesterBuilder(handler);
|
||||
}
|
||||
|
||||
|
||||
@@ -206,7 +206,7 @@ public interface WebGraphQlTester extends GraphQlTester {
|
||||
|
||||
|
||||
/**
|
||||
* Extension of {@code ResponseSpec} with access to HTTP response headers.
|
||||
* Extension of {@code ResponseSpec} to expose access to HTTP response headers.
|
||||
*/
|
||||
interface WebResponseSpec extends ResponseSpec {
|
||||
|
||||
@@ -221,7 +221,7 @@ public interface WebGraphQlTester extends GraphQlTester {
|
||||
|
||||
|
||||
/**
|
||||
* Extension of {@code SubscriptionSpec} with access to HTTP response headers.
|
||||
* Extension of {@code SubscriptionSpec} to expose access to HTTP response headers.
|
||||
*/
|
||||
interface WebSubscriptionSpec extends SubscriptionSpec {
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* <p>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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
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<GraphQLError> errorFilter, Configuration jsonPathConfig, Duration responseTimeout) {
|
||||
|
||||
super(errorFilter, jsonPathConfig, responseTimeout);
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public WebGraphQlTester.WebResponseSpec execute(WebInput webInput) {
|
||||
EntityExchangeResult<byte[]> result = this.client.post()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.headers(headers -> headers.putAll(webInput.getHeaders()))
|
||||
.bodyValue(webInput.toMap())
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(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<TestExecutionResult> exchangeResult = this.client.post()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.TEXT_EVENT_STREAM)
|
||||
.headers(headers -> headers.putAll(webInput.getHeaders()))
|
||||
.bodyValue(webInput.toMap())
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(MediaType.TEXT_EVENT_STREAM)
|
||||
.returnResult(TestExecutionResult.class);
|
||||
|
||||
Flux<GraphQlTester.ResponseSpec> flux = exchangeResult.getResponseBody()
|
||||
.map((result) -> createResponseSpec(result, exchangeResult::assertWithDiagnostics));
|
||||
|
||||
return DefaultWebGraphQlTester.createSubscriptionSpec(() -> flux, exchangeResult.getResponseHeaders());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user