Replace RequestStrategy with GraphQlTransport hierarchy
See gh-317
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import graphql.ExecutionResult;
|
||||
import graphql.GraphQLError;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.graphql.GraphQlRequest;
|
||||
import org.springframework.graphql.RequestOutput;
|
||||
import org.springframework.graphql.client.GraphQlTransport;
|
||||
import org.springframework.test.util.AssertionErrors;
|
||||
import org.springframework.util.AlternativeJdkIdGenerator;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.IdGenerator;
|
||||
|
||||
/**
|
||||
* Abstract base class for a {@link GraphQlTransport} that makes a direct call
|
||||
* to a server-side GraphQL handler or service.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.0.0
|
||||
*/
|
||||
abstract class AbstractDirectTransport implements GraphQlTransport {
|
||||
|
||||
protected static final IdGenerator idGenerator = new AlternativeJdkIdGenerator();
|
||||
|
||||
|
||||
@Override
|
||||
public Mono<ExecutionResult> execute(GraphQlRequest request) {
|
||||
return executeInternal(request).cast(ExecutionResult.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"ConstantConditions", "unchecked"})
|
||||
@Override
|
||||
public Flux<ExecutionResult> executeSubscription(GraphQlRequest request) {
|
||||
return executeInternal(request).flatMapMany(result -> {
|
||||
try {
|
||||
Object data = result.getData();
|
||||
AssertionErrors.assertTrue("Not a Publisher: " + data, data instanceof Publisher);
|
||||
|
||||
List<GraphQLError> errors = result.getErrors();
|
||||
AssertionErrors.assertTrue("Subscription errors: " + errors, CollectionUtils.isEmpty(errors));
|
||||
|
||||
return Flux.from((Publisher<ExecutionResult>) data);
|
||||
}
|
||||
catch (AssertionError ex) {
|
||||
throw new AssertionError(ex.getMessage() + "\nRequest: " + request, ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must implement this to execute requests.
|
||||
*/
|
||||
protected abstract Mono<? extends RequestOutput> executeInternal(GraphQlRequest request);
|
||||
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import graphql.ExecutionResult;
|
||||
import graphql.GraphQLError;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.graphql.RequestInput;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.util.AssertionErrors;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Base class for a {@link RequestStrategy} that performs GraphQL requests
|
||||
* directly against a GraphQL Java server, i.e. without a client.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class DirectRequestStrategySupport extends RequestStrategySupport {
|
||||
|
||||
|
||||
protected DirectRequestStrategySupport(
|
||||
@Nullable Predicate<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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import graphql.ExecutionResult;
|
||||
import graphql.GraphQLError;
|
||||
|
||||
import org.springframework.graphql.GraphQlService;
|
||||
import org.springframework.graphql.RequestInput;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link RequestStrategy} that performs requests via {@link GraphQlService}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.0.0
|
||||
*/
|
||||
final class GraphQlServiceRequestStrategy extends DirectRequestStrategySupport implements RequestStrategy {
|
||||
|
||||
private final GraphQlService graphQlService;
|
||||
|
||||
|
||||
public GraphQlServiceRequestStrategy(GraphQlService service,
|
||||
@Nullable Predicate<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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.graphql.GraphQlRequest;
|
||||
import org.springframework.graphql.GraphQlService;
|
||||
import org.springframework.graphql.RequestInput;
|
||||
import org.springframework.graphql.RequestOutput;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* {@code GraphQlTransport} that calls directly a {@link GraphQlService}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.0.0
|
||||
*/
|
||||
final class GraphQlServiceTransport extends AbstractDirectTransport {
|
||||
|
||||
private final GraphQlService graphQlService;
|
||||
|
||||
|
||||
GraphQlServiceTransport(GraphQlService graphQlService) {
|
||||
Assert.notNull(graphQlService, "GraphQlService is required");
|
||||
this.graphQlService = graphQlService;
|
||||
}
|
||||
|
||||
|
||||
public GraphQlService getGraphQlService() {
|
||||
return this.graphQlService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Mono<RequestOutput> executeInternal(GraphQlRequest request) {
|
||||
|
||||
RequestInput requestInput = new RequestInput(
|
||||
request.getDocument(), request.getOperationName(), request.getVariables(),
|
||||
idGenerator.generateId().toString(), null);
|
||||
|
||||
return this.graphQlService.execute(requestInput);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
import org.springframework.graphql.RequestInput;
|
||||
|
||||
/**
|
||||
* Abstracts how a GraphQL request is performed, given {@link RequestInput}, and
|
||||
* resulting in the creation of a response spec.
|
||||
*
|
||||
* <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);
|
||||
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import com.jayway.jsonpath.DocumentContext;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
import graphql.ExecutionResult;
|
||||
import graphql.GraphQLError;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Base class support for {@link RequestStrategy} and
|
||||
* {@link WebRequestStrategy} implementations.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class RequestStrategySupport {
|
||||
|
||||
@Nullable
|
||||
private final Predicate<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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import graphql.GraphQLError;
|
||||
|
||||
import org.springframework.graphql.web.WebGraphQlHandler;
|
||||
import org.springframework.graphql.web.WebInput;
|
||||
import org.springframework.graphql.web.WebOutput;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link WebRequestStrategy} that performs requests directly against a
|
||||
* {@link WebGraphQlHandler}, i.e. without a client.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class WebGraphQlHandlerRequestStrategy extends DirectRequestStrategySupport implements WebRequestStrategy {
|
||||
|
||||
private final WebGraphQlHandler graphQlHandler;
|
||||
|
||||
|
||||
WebGraphQlHandlerRequestStrategy(WebGraphQlHandler handler,
|
||||
@Nullable Predicate<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.handleRequest(webInput).block(getResponseTimeout());
|
||||
Assert.notNull(webOutput, "Expected WebOutput");
|
||||
return webOutput;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.graphql.GraphQlRequest;
|
||||
import org.springframework.graphql.web.WebGraphQlHandler;
|
||||
import org.springframework.graphql.web.WebInput;
|
||||
import org.springframework.graphql.web.WebOutput;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
* {@code GraphQlTransport} that calls directly a {@link WebGraphQlHandler}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.0.0
|
||||
*/
|
||||
final class WebGraphQlHandlerTransport extends AbstractDirectTransport {
|
||||
|
||||
private final URI url;
|
||||
|
||||
private final HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
private final WebGraphQlHandler graphQlHandler;
|
||||
|
||||
|
||||
WebGraphQlHandlerTransport(@Nullable URI url, HttpHeaders headers, WebGraphQlHandler graphQlHandler) {
|
||||
this.url = (url != null ? url : URI.create(""));
|
||||
this.headers.addAll(headers);
|
||||
this.graphQlHandler = graphQlHandler;
|
||||
}
|
||||
|
||||
|
||||
public URI getUrl() {
|
||||
return this.url;
|
||||
}
|
||||
|
||||
public HttpHeaders getHeaders() {
|
||||
return this.headers;
|
||||
}
|
||||
|
||||
public WebGraphQlHandler getGraphQlHandler() {
|
||||
return this.graphQlHandler;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Mono<WebOutput> executeInternal(GraphQlRequest request) {
|
||||
return this.graphQlHandler.handleRequest(
|
||||
new WebInput(this.url, this.headers, request.toMap(), idGenerator.generateId().toString(), null));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
import org.springframework.graphql.web.WebInput;
|
||||
|
||||
/**
|
||||
* Abstracts how a GraphQL request is performed in the a Web context, given
|
||||
* {@link WebInput}, and resulting in the creation of a response spec.
|
||||
*
|
||||
* <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);
|
||||
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import com.jayway.jsonpath.DocumentContext;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
import graphql.GraphQLError;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.graphql.web.WebInput;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.web.reactive.server.EntityExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.FluxExchangeResult;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link WebRequestStrategy} that uses {@link WebTestClient} to perform
|
||||
* requests. Depending on how the client is configured, this may be used with
|
||||
* Spring MVC and WebFlux controllers, without a server, or against a live server.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.0.0
|
||||
*/
|
||||
final class WebTestClientRequestStrategy extends RequestStrategySupport implements WebRequestStrategy {
|
||||
|
||||
private final WebTestClient client;
|
||||
|
||||
|
||||
WebTestClientRequestStrategy(WebTestClient client,
|
||||
@Nullable Predicate<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()
|
||||
.contentTypeCompatibleWith(MediaType.APPLICATION_JSON)
|
||||
.expectBody()
|
||||
.returnResult();
|
||||
|
||||
byte[] bytes = result.getResponseBodyContent();
|
||||
Assert.notNull(bytes, "Expected GraphQL response content");
|
||||
String content = new String(bytes, StandardCharsets.UTF_8);
|
||||
|
||||
DocumentContext documentContext = JsonPath.parse(content, getJsonPathConfig());
|
||||
GraphQlTester.ResponseSpec responseSpec = createResponseSpec(documentContext, result::assertWithDiagnostics);
|
||||
return DefaultWebGraphQlTester.createResponseSpec(responseSpec, result.getResponseHeaders());
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebGraphQlTester.WebSubscriptionSpec executeSubscription(WebInput webInput) {
|
||||
FluxExchangeResult<TestExecutionResult> exchangeResult = this.client.post()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.TEXT_EVENT_STREAM)
|
||||
.headers(headers -> {
|
||||
Locale locale = webInput.getLocale();
|
||||
if (locale != null) {
|
||||
headers.setAcceptLanguageAsLocales(Collections.singletonList(locale));
|
||||
}
|
||||
headers.putAll(webInput.getHeaders());
|
||||
})
|
||||
.bodyValue(webInput.toMap())
|
||||
.exchange()
|
||||
.expectStatus()
|
||||
.isOk()
|
||||
.expectHeader()
|
||||
.contentType(MediaType.TEXT_EVENT_STREAM)
|
||||
.returnResult(TestExecutionResult.class);
|
||||
|
||||
Flux<GraphQlTester.ResponseSpec> flux = exchangeResult.getResponseBody()
|
||||
.map((result) -> createResponseSpec(result, exchangeResult::assertWithDiagnostics));
|
||||
|
||||
return DefaultWebGraphQlTester.createSubscriptionSpec(() -> flux, exchangeResult.getResponseHeaders());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.graphql.test.tester;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import graphql.ExecutionResult;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.graphql.GraphQlRequest;
|
||||
import org.springframework.graphql.client.GraphQlTransport;
|
||||
import org.springframework.graphql.support.MapExecutionResult;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@code GraphQlTransport} for GraphQL over HTTP via {@link WebTestClient}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 1.0.0
|
||||
*/
|
||||
final class WebTestClientTransport implements GraphQlTransport {
|
||||
|
||||
private static final ParameterizedTypeReference<Map<String, Object>> MAP_TYPE =
|
||||
new ParameterizedTypeReference<Map<String, Object>>() {};
|
||||
|
||||
|
||||
private final WebTestClient webTestClient;
|
||||
|
||||
|
||||
WebTestClientTransport(WebTestClient webTestClient) {
|
||||
Assert.notNull(webTestClient, "WebTestClient is required");
|
||||
this.webTestClient = webTestClient;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Mono<ExecutionResult> execute(GraphQlRequest request) {
|
||||
|
||||
Map<String, Object> resultMap = this.webTestClient.post()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.bodyValue(request.toMap())
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectHeader().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)
|
||||
.expectBody(MAP_TYPE)
|
||||
.returnResult()
|
||||
.getResponseBody();
|
||||
|
||||
resultMap = (resultMap != null ? resultMap : Collections.emptyMap());
|
||||
ExecutionResult result = MapExecutionResult.from(resultMap);
|
||||
return Mono.just(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<ExecutionResult> executeSubscription(GraphQlRequest request) {
|
||||
throw new UnsupportedOperationException("Subscriptions not supported over HTTP");
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user