Inline GraphQlTesterBuilderConfig in DefaultGraphQlTester

It's simpler to pass the config options explicitly.
This commit is contained in:
Rossen Stoyanchev
2021-09-30 15:54:52 +01:00
parent f0f883cc39
commit fb8e82dcc0
3 changed files with 117 additions and 151 deletions

View File

@@ -32,6 +32,8 @@ 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;
@@ -45,6 +47,7 @@ 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;
@@ -58,10 +61,6 @@ class DefaultGraphQlTester implements GraphQlTester {
private final RequestStrategy requestStrategy;
DefaultGraphQlTester(GraphQlService service, GraphQlTesterBuilderConfig builderConfig) {
this(new GraphQlServiceRequestStrategy(service, builderConfig));
}
DefaultGraphQlTester(RequestStrategy requestStrategy) {
this.requestStrategy = requestStrategy;
}
@@ -85,7 +84,13 @@ class DefaultGraphQlTester implements GraphQlTester {
private final GraphQlService service;
private final GraphQlTesterBuilderConfig builderConfig = new GraphQlTesterBuilderConfig();
@Nullable
private Predicate<GraphQLError> errorFilter;
@Nullable
private Configuration jsonPathConfig;
private Duration responseTimeout = Duration.ofSeconds(5);
DefaultBuilder(GraphQlService service) {
Assert.notNull(service, "GraphQlService is required.");
@@ -94,25 +99,31 @@ class DefaultGraphQlTester implements GraphQlTester {
@Override
public DefaultBuilder errorFilter(Predicate<GraphQLError> predicate) {
this.builderConfig.errorFilter(predicate);
this.errorFilter = (this.errorFilter != null ? errorFilter.and(predicate) : predicate);
return this;
}
@Override
public DefaultBuilder jsonPathConfig(Configuration config) {
this.builderConfig.jsonPathConfig(config);
this.jsonPathConfig = config;
return this;
}
@Override
public DefaultBuilder responseTimeout(Duration timeout) {
this.builderConfig.responseTimeout(timeout);
Assert.notNull(timeout, "'timeout' is required");
this.responseTimeout = timeout;
return this;
}
@Override
public GraphQlTester build() {
return new DefaultGraphQlTester(this.service, this.builderConfig);
Configuration jsonPathConfig = JsonPathConfiguration.initialize(this.jsonPathConfig);
RequestStrategy strategy = new GraphQlServiceRequestStrategy(
this.service, this.errorFilter, jsonPathConfig, this.responseTimeout);
return new DefaultGraphQlTester(strategy);
}
}
@@ -146,30 +157,30 @@ class DefaultGraphQlTester implements GraphQlTester {
*/
protected abstract static class AbstractDirectRequestStrategy implements RequestStrategy {
private final GraphQlTesterBuilderConfig builderConfig;
protected AbstractDirectRequestStrategy(GraphQlTesterBuilderConfig builderConfig) {
this.builderConfig = builderConfig;
}
@Nullable
private Predicate<GraphQLError> errorFilter() {
return this.builderConfig.getErrorFilter();
}
private final Predicate<GraphQLError> errorFilter;
private Configuration jsonPathConfig() {
return this.builderConfig.getJsonPathConfig();
private final Configuration jsonPathConfig;
private final Duration responseTimeout;
protected AbstractDirectRequestStrategy(
@Nullable Predicate<GraphQLError> errorFilter, Configuration jsonPathConfig, Duration timeout) {
this.errorFilter = errorFilter;
this.jsonPathConfig = jsonPathConfig;
this.responseTimeout = timeout;
}
protected Duration responseTimeout() {
return this.builderConfig.getResponseTimeout();
return this.responseTimeout;
}
@Override
public ResponseSpec execute(RequestInput input) {
ExecutionResult executionResult = executeInternal(input);
DocumentContext context = JsonPath.parse(executionResult.toSpecification(), jsonPathConfig());
return new DefaultResponseSpec(context, errorFilter(), assertDecorator(input));
ExecutionResult result = executeInternal(input);
DocumentContext context = JsonPath.parse(result.toSpecification(), this.jsonPathConfig);
return new DefaultResponseSpec(context, this.errorFilter, assertDecorator(input));
}
@Override
@@ -182,7 +193,8 @@ class DefaultGraphQlTester implements GraphQlTester {
assertDecorator.accept(() -> AssertionErrors.assertTrue(
"Response has " + errors.size() + " unexpected error(s).", CollectionUtils.isEmpty(errors)));
return new DefaultSubscriptionSpec(result.getData(), errorFilter(), jsonPathConfig(), assertDecorator);
return new DefaultSubscriptionSpec(
result.getData(), this.errorFilter, this.jsonPathConfig, assertDecorator);
}
/**
@@ -210,8 +222,10 @@ class DefaultGraphQlTester implements GraphQlTester {
private final GraphQlService graphQlService;
protected GraphQlServiceRequestStrategy(GraphQlService service, GraphQlTesterBuilderConfig builderConfig) {
super(builderConfig);
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;
}
@@ -759,4 +773,40 @@ class DefaultGraphQlTester implements GraphQlTester {
}
}
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();
}
}
}

View File

@@ -71,40 +71,55 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
*/
final static class DefaultBuilder implements WebGraphQlTester.Builder {
private final Supplier<RequestStrategy> requestStrategySupplier;
@Nullable
private Predicate<GraphQLError> errorFilter;
private final GraphQlTesterBuilderConfig builderConfig = new GraphQlTesterBuilderConfig();
@Nullable
private Configuration jsonPathConfig;
@Nullable
private Duration responseTimeout;
private final Supplier<RequestStrategy> requestStrategySupplier;
@Nullable
private HttpHeaders headers;
DefaultBuilder(WebTestClient client) {
this.requestStrategySupplier = () -> {
Duration timeout = this.builderConfig.getResponseTimeout();
WebTestClient clientToUse = client.mutate().responseTimeout(timeout).build();
return new WebTestClientRequestStrategy(clientToUse, this.builderConfig);
WebTestClient clientToUse = (this.responseTimeout != null ?
client.mutate().responseTimeout(this.responseTimeout).build() : client);
return new WebTestClientRequestStrategy(clientToUse, this.errorFilter, initJsonPathConfig());
};
}
DefaultBuilder(WebGraphQlHandler handler) {
this.requestStrategySupplier = () -> new WebGraphQlHandlerRequestStrategy(handler, this.builderConfig);
this.requestStrategySupplier = () ->
new WebGraphQlHandlerRequestStrategy(
handler, this.errorFilter, initJsonPathConfig(),
(this.responseTimeout != null ? this.responseTimeout : Duration.ofSeconds(5)));
}
private Configuration initJsonPathConfig() {
return JsonPathConfiguration.initialize(this.jsonPathConfig);
}
@Override
public WebGraphQlTester.Builder errorFilter(Predicate<GraphQLError> predicate) {
this.builderConfig.errorFilter(predicate);
this.errorFilter = (this.errorFilter != null ? errorFilter.and(predicate) : predicate);
return this;
}
@Override
public DefaultBuilder jsonPathConfig(Configuration config) {
this.builderConfig.jsonPathConfig(config);
this.jsonPathConfig = config;
return this;
}
@Override
public DefaultBuilder responseTimeout(Duration timeout) {
this.builderConfig.responseTimeout(timeout);
Assert.notNull(timeout, "'timeout' is required");
this.responseTimeout = timeout;
return this;
}
@@ -139,20 +154,17 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
private final WebTestClient client;
private final GraphQlTesterBuilderConfig builderConfig;
WebTestClientRequestStrategy(WebTestClient client, GraphQlTesterBuilderConfig builderConfig) {
this.client = client;
this.builderConfig = builderConfig;
}
@Nullable
private Predicate<GraphQLError> errorFilter() {
return this.builderConfig.getErrorFilter();
}
private final Predicate<GraphQLError> errorFilter;
private Configuration jsonPathConfig() {
return this.builderConfig.getJsonPathConfig();
private final Configuration jsonPathConfig;
public WebTestClientRequestStrategy(
WebTestClient client, @Nullable Predicate<GraphQLError> errorFilter, Configuration jsonPathConfig) {
this.client = client;
this.errorFilter = errorFilter;
this.jsonPathConfig = jsonPathConfig;
}
@Override
@@ -172,9 +184,9 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
byte[] bytes = result.getResponseBodyContent();
Assert.notNull(bytes, "Expected GraphQL response content");
String content = new String(bytes, StandardCharsets.UTF_8);
DocumentContext documentContext = JsonPath.parse(content, jsonPathConfig());
DocumentContext documentContext = JsonPath.parse(content, this.jsonPathConfig);
return new DefaultResponseSpec(documentContext, errorFilter(), result::assertWithDiagnostics);
return new DefaultResponseSpec(documentContext, this.errorFilter, result::assertWithDiagnostics);
}
@Override
@@ -193,7 +205,7 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
return new DefaultSubscriptionSpec(
exchangeResult.getResponseBody().cast(ExecutionResult.class),
errorFilter(), jsonPathConfig(), exchangeResult::assertWithDiagnostics);
this.errorFilter, this.jsonPathConfig, exchangeResult::assertWithDiagnostics);
}
private HttpHeaders getHeaders(RequestInput requestInput) {
@@ -211,8 +223,10 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
private final WebGraphQlHandler graphQlHandler;
WebGraphQlHandlerRequestStrategy(WebGraphQlHandler handler, GraphQlTesterBuilderConfig builderConfig) {
super(builderConfig);
WebGraphQlHandlerRequestStrategy(WebGraphQlHandler handler,
@Nullable Predicate<GraphQLError> errorFilter, Configuration jsonPathConfig, Duration timeout) {
super(errorFilter, jsonPathConfig, timeout);
this.graphQlHandler = handler;
}

View File

@@ -1,98 +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 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;
/**
* Holds the input required for {@link GraphQlTester.Builder}, providing a
* convenient way to pass it together, while also helping to avoid challenges
* with builder hierarchy generics.
*
* @author Rossen Stoyanchev
*/
final class GraphQlTesterBuilderConfig {
private static final boolean jackson2Present;
static {
ClassLoader classLoader = DefaultGraphQlTester.class.getClassLoader();
jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader)
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
}
@Nullable
private Predicate<GraphQLError> errorFilter;
@Nullable
private Configuration jsonPathConfig;
private Duration responseTimeout = Duration.ofSeconds(5);
public void errorFilter(Predicate<GraphQLError> predicate) {
this.errorFilter = (this.errorFilter != null ? errorFilter.and(predicate) : predicate);
}
public void jsonPathConfig(@Nullable Configuration config) {
this.jsonPathConfig = config;
}
public void responseTimeout(Duration timeout) {
Assert.notNull(timeout, "'timeout' is required");
this.responseTimeout = timeout;
}
@Nullable
public Predicate<GraphQLError> getErrorFilter() {
return this.errorFilter;
}
public Configuration getJsonPathConfig() {
if (this.jsonPathConfig == null) {
this.jsonPathConfig = (jackson2Present ?
Jackson2Configuration.create() : Configuration.builder().build());
}
return this.jsonPathConfig;
}
public Duration getResponseTimeout() {
return this.responseTimeout;
}
private static class Jackson2Configuration {
static Configuration create() {
return Configuration.builder()
.jsonProvider(new JacksonJsonProvider())
.mappingProvider(new JacksonMappingProvider())
.build();
}
}
}