WebGraphQlTester supports HTTP header input

Closes gh-64
This commit is contained in:
Rossen Stoyanchev
2021-06-25 20:59:18 +01:00
parent 410948bde3
commit 4a6c718394
6 changed files with 185 additions and 107 deletions

View File

@@ -66,6 +66,7 @@ class DefaultGraphQlTester implements GraphQlTester {
&& ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
}
private final RequestStrategy requestStrategy;
@@ -77,13 +78,19 @@ class DefaultGraphQlTester implements GraphQlTester {
this.requestStrategy = requestStrategy;
}
protected RequestStrategy getRequestStrategy() {
return this.requestStrategy;
}
protected static Configuration initJsonPathConfig() {
return (jackson2Present ? Jackson2Configuration.create() : Configuration.builder().build());
}
@Override
public RequestSpec query(String query) {
return new DefaultRequestSpec(query);
return new DefaultRequestSpec(this.requestStrategy, query);
}
/**
@@ -182,7 +189,9 @@ class DefaultGraphQlTester implements GraphQlTester {
/**
* {@link RequestSpec} that collects the query, operationName, and variables.
*/
private final class DefaultRequestSpec implements RequestSpec {
protected static class DefaultRequestSpec implements RequestSpec {
private final RequestStrategy requestStrategy;
private final String query;
@@ -191,8 +200,10 @@ class DefaultGraphQlTester implements GraphQlTester {
private final Map<String, Object> variables = new LinkedHashMap<>();
private DefaultRequestSpec(String query) {
protected DefaultRequestSpec(RequestStrategy requestStrategy, String query) {
Assert.notNull(requestStrategy, "RequestStrategy is required");
Assert.notNull(query, "`query` is required");
this.requestStrategy = requestStrategy;
this.query = query;
}
@@ -216,21 +227,25 @@ class DefaultGraphQlTester implements GraphQlTester {
@Override
public ResponseSpec execute() {
RequestInput input = new RequestInput(this.query, this.operationName, this.variables);
return DefaultGraphQlTester.this.requestStrategy.execute(input);
RequestInput input = createRequestInput();
return this.requestStrategy.execute(input);
}
@Override
public void executeAndVerify() {
RequestInput input = new RequestInput(this.query, this.operationName, this.variables);
ResponseSpec spec = DefaultGraphQlTester.this.requestStrategy.execute(input);
RequestInput input = createRequestInput();
ResponseSpec spec = this.requestStrategy.execute(input);
spec.path("$.errors").valueIsEmpty();
}
@Override
public SubscriptionSpec executeSubscription() {
RequestInput input = new RequestInput(this.query, this.operationName, this.variables);
return DefaultGraphQlTester.this.requestStrategy.executeSubscription(input);
RequestInput input = createRequestInput();
return this.requestStrategy.executeSubscription(input);
}
protected RequestInput createRequestInput() {
return new RequestInput(this.query, this.operationName, this.variables);
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.graphql.test.tester;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.function.Consumer;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
@@ -51,6 +52,12 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
}
@Override
public WebRequestSpec query(String query) {
return new DefaultWebRequestSpec(getRequestStrategy(), query);
}
/**
* {@link RequestStrategy} that works as an HTTP client with requests executed through
* {@link WebTestClient} that in turn may work connect with or without a live server
@@ -69,9 +76,20 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
@Override
public ResponseSpec execute(RequestInput requestInput) {
EntityExchangeResult<byte[]> result = this.client.post().contentType(MediaType.APPLICATION_JSON)
.bodyValue(requestInput).exchange().expectStatus().isOk().expectHeader()
.contentType(MediaType.APPLICATION_JSON).expectBody().returnResult();
Assert.isInstanceOf(WebInput.class, requestInput);
WebInput webInput = (WebInput) requestInput;
EntityExchangeResult<byte[]> result = this.client.post()
.contentType(MediaType.APPLICATION_JSON)
.headers(headers -> headers.putAll(webInput.getHeaders()))
.bodyValue(requestInput)
.exchange()
.expectStatus()
.isOk()
.expectHeader()
.contentType(MediaType.APPLICATION_JSON)
.expectBody()
.returnResult();
byte[] bytes = result.getResponseBodyContent();
Assert.notNull(bytes, "Expected GraphQL response content");
@@ -83,9 +101,19 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
@Override
public SubscriptionSpec executeSubscription(RequestInput requestInput) {
Assert.isInstanceOf(WebInput.class, requestInput);
WebInput webInput = (WebInput) requestInput;
FluxExchangeResult<TestExecutionResult> exchangeResult = this.client.post()
.contentType(MediaType.APPLICATION_JSON).accept(MediaType.TEXT_EVENT_STREAM).bodyValue(requestInput)
.exchange().expectStatus().isOk().expectHeader().contentType(MediaType.TEXT_EVENT_STREAM)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.TEXT_EVENT_STREAM)
.headers(headers -> headers.putAll(webInput.getHeaders()))
.bodyValue(requestInput)
.exchange()
.expectStatus()
.isOk()
.expectHeader()
.contentType(MediaType.TEXT_EVENT_STREAM)
.returnResult(TestExecutionResult.class);
return new DefaultSubscriptionSpec(exchangeResult.getResponseBody().cast(ExecutionResult.class),
@@ -100,10 +128,6 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
*/
private static class WebGraphQlHandlerRequestStrategy extends AbstractDirectRequestStrategy {
private static final URI DEFAULT_URL = URI.create("http://localhost:8080/graphql");
private static final HttpHeaders DEFAULT_HEADERS = new HttpHeaders();
private final WebGraphQlHandler graphQlHandler;
WebGraphQlHandlerRequestStrategy(WebGraphQlHandler handler, Configuration jsonPathConfig) {
@@ -111,12 +135,44 @@ class DefaultWebGraphQlTester extends DefaultGraphQlTester implements WebGraphQl
this.graphQlHandler = handler;
}
protected ExecutionResult executeInternal(RequestInput input) {
WebInput webInput = new WebInput(DEFAULT_URL, DEFAULT_HEADERS, input.toMap(), null);
ExecutionResult result = this.graphQlHandler.handle(webInput).block(DEFAULT_TIMEOUT);
protected ExecutionResult executeInternal(RequestInput requestInput) {
Assert.isInstanceOf(WebInput.class, requestInput);
ExecutionResult result = this.graphQlHandler.handle((WebInput) requestInput).block(DEFAULT_TIMEOUT);
Assert.notNull(result, "Expected ExecutionResult");
return result;
}
}
protected static final class DefaultWebRequestSpec extends DefaultRequestSpec implements WebRequestSpec {
private static final URI DEFAULT_URL = URI.create("");
private final HttpHeaders headers = new HttpHeaders();
public DefaultWebRequestSpec(RequestStrategy requestStrategy, String query) {
super(requestStrategy, query);
}
@Override
public WebRequestSpec header(String headerName, String... headerValues) {
for (String headerValue : headerValues) {
this.headers.add(headerName, headerValue);
}
return this;
}
@Override
public WebRequestSpec headers(Consumer<HttpHeaders> headersConsumer) {
headersConsumer.accept(this.headers);
return this;
}
@Override
protected RequestInput createRequestInput() {
RequestInput requestInput = super.createRequestInput();
return new WebInput(DEFAULT_URL, headers, requestInput.toMap(), null);
}
}
}

View File

@@ -15,7 +15,10 @@
*/
package org.springframework.graphql.test.tester;
import java.util.function.Consumer;
import org.springframework.graphql.web.WebGraphQlHandler;
import org.springframework.http.HttpHeaders;
import org.springframework.test.web.reactive.server.WebTestClient;
/**
@@ -79,6 +82,12 @@ import org.springframework.test.web.reactive.server.WebTestClient;
*/
public interface WebGraphQlTester extends GraphQlTester {
/**
* {@inheritDoc}
* <p>The returned spec for Web request input also allows adding HTTP headers.
*/
WebRequestSpec query(String query);
/**
* Create a {@code WebGraphQlTester} that performs GraphQL requests as an
* HTTP client through the given {@link WebTestClient}. Depending on how the
@@ -101,4 +110,31 @@ public interface WebGraphQlTester extends GraphQlTester {
return new DefaultWebGraphQlTester(handler);
}
/**
* Extends {@link GraphQlTester.RequestSpec} with further input options
* applicable to Web requests.
*/
interface WebRequestSpec extends RequestSpec {
/**
* Add the given, single header value under the given name.
* @param headerName the header name
* @param headerValues the header value(s)
* @return the same instance
*/
WebRequestSpec header(String headerName, String... headerValues);
/**
* Manipulate the request's headers with the given consumer. The
* headers provided to the consumer are "live", so that the consumer can
* be used to {@linkplain HttpHeaders#set(String, String) overwrite}
* existing header values, {@linkplain HttpHeaders#remove(Object) remove}
* values, or use any of the other {@link HttpHeaders} methods.
* @param headersConsumer a function that consumes the {@code HttpHeaders}
* @return this builder
*/
WebRequestSpec headers(Consumer<HttpHeaders> headersConsumer);
}
}