diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTester.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTester.java index 67f165dc..e505bcce 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTester.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultGraphQlTester.java @@ -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 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 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 errorFilter() { - return this.builderConfig.getErrorFilter(); - } + private final Predicate errorFilter; - private Configuration jsonPathConfig() { - return this.builderConfig.getJsonPathConfig(); + private final Configuration jsonPathConfig; + + private final Duration responseTimeout; + + protected AbstractDirectRequestStrategy( + @Nullable Predicate 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 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(); + } + } + } diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebGraphQlTester.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebGraphQlTester.java index d5206922..dbeffcf6 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebGraphQlTester.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebGraphQlTester.java @@ -71,40 +71,55 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl */ final static class DefaultBuilder implements WebGraphQlTester.Builder { - private final Supplier requestStrategySupplier; + @Nullable + private Predicate errorFilter; - private final GraphQlTesterBuilderConfig builderConfig = new GraphQlTesterBuilderConfig(); + @Nullable + private Configuration jsonPathConfig; + + @Nullable + private Duration responseTimeout; + + private final Supplier 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 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 errorFilter() { - return this.builderConfig.getErrorFilter(); - } + private final Predicate errorFilter; - private Configuration jsonPathConfig() { - return this.builderConfig.getJsonPathConfig(); + private final Configuration jsonPathConfig; + + public WebTestClientRequestStrategy( + WebTestClient client, @Nullable Predicate 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 errorFilter, Configuration jsonPathConfig, Duration timeout) { + + super(errorFilter, jsonPathConfig, timeout); this.graphQlHandler = handler; } diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTesterBuilderConfig.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTesterBuilderConfig.java deleted file mode 100644 index 055f0c13..00000000 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTesterBuilderConfig.java +++ /dev/null @@ -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 errorFilter; - - @Nullable - private Configuration jsonPathConfig; - - private Duration responseTimeout = Duration.ofSeconds(5); - - public void errorFilter(Predicate 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 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(); - } - - } - -}