From e67cb5885e99225240714e1981f472f23b88fc11 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Fri, 4 Mar 2022 14:07:11 +0000 Subject: [PATCH] Rename ~Spec in GraphQlClient and GraphQlTester As these are expected to be used as local variables, "Spec" reduces readability and the IDE creates variables called "spec", which increases that effect. Given those are nested within `GraphQlClient` and `GraphQlTester`, it makes sense to drop the spec part and local variable names such as request and response make sense. See gh-10, see gh-317 --- .../AbstractDelegatingGraphQlTester.java | 4 +- .../test/tester/DefaultGraphQlTester.java | 116 +++++++-------- .../tester/DefaultWebSocketGraphQlTester.java | 4 +- .../graphql/test/tester/GraphQlTester.java | 137 +++++++++--------- .../test/tester/GraphQlTesterTests.java | 42 +++--- .../AbstractDelegatingGraphQlClient.java | 4 +- .../graphql/client/DefaultGraphQlClient.java | 36 +++-- .../graphql/client/GraphQlClient.java | 68 ++++----- .../graphql/client/GraphQlClientTests.java | 30 ++-- 9 files changed, 216 insertions(+), 225 deletions(-) diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/AbstractDelegatingGraphQlTester.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/AbstractDelegatingGraphQlTester.java index b1e0248f..ac410321 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/AbstractDelegatingGraphQlTester.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/AbstractDelegatingGraphQlTester.java @@ -40,12 +40,12 @@ public abstract class AbstractDelegatingGraphQlTester implements GraphQlTester { @Override - public RequestSpec document(String document) { + public Request document(String document) { return this.delegate.document(document); } @Override - public RequestSpec documentName(String documentName) { + public Request documentName(String documentName) { return this.delegate.documentName(documentName); } 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 f21d9ad9..5cae4842 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 @@ -90,12 +90,12 @@ final class DefaultGraphQlTester implements GraphQlTester { @Override - public RequestSpec document(String document) { - return new DefaultRequestSpec(document); + public Request document(String document) { + return new DefaultRequest(document); } @Override - public RequestSpec documentName(String documentName) { + public Request documentName(String documentName) { String document = this.documentSource.getDocument(documentName).block(this.responseTimeout); Assert.notNull(document, "Expected document content or an error"); return document(document); @@ -129,9 +129,9 @@ final class DefaultGraphQlTester implements GraphQlTester { /** - * {@link RequestSpec} that gathers the document, operationName, and variables. + * {@link Request} that gathers the document, operationName, and variables. */ - private final class DefaultRequestSpec implements RequestSpec { + private final class DefaultRequest implements Request { private final String document; @@ -140,26 +140,26 @@ final class DefaultGraphQlTester implements GraphQlTester { private final Map variables = new LinkedHashMap<>(); - private DefaultRequestSpec(String document) { + private DefaultRequest(String document) { Assert.notNull(document, "`document` is required"); this.document = document; } @Override - public DefaultRequestSpec operationName(@Nullable String name) { + public DefaultRequest operationName(@Nullable String name) { this.operationName = name; return this; } @Override - public DefaultRequestSpec variable(String name, @Nullable Object value) { + public DefaultRequest variable(String name, @Nullable Object value) { this.variables.put(name, value); return this; } @SuppressWarnings("ConstantConditions") @Override - public ResponseSpec execute() { + public Response execute() { GraphQlRequest request = createRequest(); return transport.execute(request) .map(result -> createResponseSpec(result, assertDecorator(request))) @@ -172,7 +172,7 @@ final class DefaultGraphQlTester implements GraphQlTester { } @Override - public SubscriptionSpec executeSubscription() { + public Subscription executeSubscription() { GraphQlRequest request = createRequest(); return () -> transport.executeSubscription(request) .map(result -> createResponseSpec(result, assertDecorator(request))); @@ -182,11 +182,11 @@ final class DefaultGraphQlTester implements GraphQlTester { return new GraphQlRequest(this.document, this.operationName, this.variables); } - private GraphQlTester.ResponseSpec createResponseSpec( + private Response createResponseSpec( ExecutionResult result, Consumer assertDecorator) { DocumentContext jsonDocument = JsonPath.parse(result.toSpecification(), jsonPathConfig); - return new DefaultResponseSpec(jsonDocument, errorFilter, assertDecorator); + return new DefaultResponse(jsonDocument, errorFilter, assertDecorator); } private Consumer assertDecorator(GraphQlRequest request) { @@ -307,13 +307,13 @@ final class DefaultGraphQlTester implements GraphQlTester { /** - * {@link ResponseSpec} that operates on the response from a GraphQL HTTP request. + * Default {@link GraphQlTester.Response} implementation. */ - private static final class DefaultResponseSpec implements ResponseSpec, ErrorSpec { + private static final class DefaultResponse implements Response, Errors { private final ResponseContainer responseContainer; - private DefaultResponseSpec( + private DefaultResponse( DocumentContext documentContext, @Nullable Predicate errorFilter, Consumer assertDecorator) { @@ -321,36 +321,36 @@ final class DefaultGraphQlTester implements GraphQlTester { } @Override - public PathSpec path(String path) { + public Path path(String path) { this.responseContainer.verifyErrors(); - return new DefaultPathSpec(path, this.responseContainer); + return new DefaultPath(path, this.responseContainer); } @Override - public ErrorSpec errors() { + public Errors errors() { return this; } @Override - public ErrorSpec filter(Predicate predicate) { + public Errors filter(Predicate predicate) { this.responseContainer.filterErrors(predicate); return this; } @Override - public ErrorSpec expect(Predicate predicate) { + public Errors expect(Predicate predicate) { this.responseContainer.expectErrors(predicate); return this; } @Override - public TraverseSpec verify() { + public Traversable verify() { this.responseContainer.verifyErrors(); return this; } @Override - public TraverseSpec satisfy(Consumer> consumer) { + public Traversable satisfy(Consumer> consumer) { this.responseContainer.consumeErrors(consumer); return this; } @@ -358,9 +358,9 @@ final class DefaultGraphQlTester implements GraphQlTester { } /** - * {@link PathSpec} implementation. + * Default {@link GraphQlTester.Path} implementation. */ - private static final class DefaultPathSpec implements PathSpec { + private static final class DefaultPath implements Path { private final String inputPath; @@ -370,7 +370,7 @@ final class DefaultGraphQlTester implements GraphQlTester { private final JsonPathExpectationsHelper pathHelper; - private DefaultPathSpec(String path, ResponseContainer responseContainer) { + private DefaultPath(String path, ResponseContainer responseContainer) { Assert.notNull(path, "`path` is required"); Assert.notNull(responseContainer, "ResponseContainer is required"); this.inputPath = path; @@ -390,78 +390,78 @@ final class DefaultGraphQlTester implements GraphQlTester { } @Override - public PathSpec path(String path) { - return new DefaultPathSpec(path, this.responseContainer); + public Path path(String path) { + return new DefaultPath(path, this.responseContainer); } @Override - public PathSpec pathExists() { + public Path pathExists() { this.responseContainer.doAssert(() -> this.pathHelper.hasJsonPath(this.responseContainer.jsonContent())); return this; } @Override - public PathSpec pathDoesNotExist() { + public Path pathDoesNotExist() { this.responseContainer.doAssert(() -> this.pathHelper.doesNotHaveJsonPath(this.responseContainer.jsonContent())); return this; } @Override - public PathSpec valueExists() { + public Path valueExists() { this.responseContainer.doAssert(() -> this.pathHelper.exists(this.responseContainer.jsonContent())); return this; } @Override - public PathSpec valueDoesNotExist() { + public Path valueDoesNotExist() { this.responseContainer.doAssert(() -> this.pathHelper.doesNotExist(this.responseContainer.jsonContent())); return this; } @Override - public PathSpec valueIsEmpty() { + public Path valueIsEmpty() { this.responseContainer.doAssert(() -> this.pathHelper.assertValueIsEmpty(this.responseContainer.jsonContent())); return this; } @Override - public PathSpec valueIsNotEmpty() { + public Path valueIsNotEmpty() { this.responseContainer.doAssert(() -> this.pathHelper.assertValueIsNotEmpty(this.responseContainer.jsonContent())); return this; } @Override - public EntitySpec entity(Class entityType) { + public Entity entity(Class entityType) { D entity = this.responseContainer.read(this.jsonPath, new TypeRefAdapter<>(entityType)); - return new DefaultEntitySpec<>(entity, this.responseContainer, this.inputPath); + return new DefaultEntity<>(entity, this.responseContainer, this.inputPath); } @Override - public EntitySpec entity(ParameterizedTypeReference entityType) { + public Entity entity(ParameterizedTypeReference entityType) { D entity = this.responseContainer.read(this.jsonPath, new TypeRefAdapter<>(entityType)); - return new DefaultEntitySpec<>(entity, this.responseContainer, this.inputPath); + return new DefaultEntity<>(entity, this.responseContainer, this.inputPath); } @Override - public ListEntitySpec entityList(Class elementType) { + public EntityList entityList(Class elementType) { List entity = this.responseContainer.read(this.jsonPath, new TypeRefAdapter<>(List.class, elementType)); - return new DefaultListEntitySpec<>(entity, this.responseContainer, this.inputPath); + return new DefaultEntityList<>(entity, this.responseContainer, this.inputPath); } @Override - public ListEntitySpec entityList(ParameterizedTypeReference elementType) { + public EntityList entityList(ParameterizedTypeReference elementType) { List entity = this.responseContainer.read(this.jsonPath, new TypeRefAdapter<>(List.class, elementType)); - return new DefaultListEntitySpec<>(entity, this.responseContainer, this.inputPath); + return new DefaultEntityList<>(entity, this.responseContainer, this.inputPath); } @Override - public PathSpec matchesJson(String expectedJson) { + public Path matchesJson(String expectedJson) { matchesJson(expectedJson, false); return this; } @Override - public PathSpec matchesJsonStrictly(String expectedJson) { + public Path matchesJsonStrictly(String expectedJson) { matchesJson(expectedJson, true); return this; } @@ -486,9 +486,9 @@ final class DefaultGraphQlTester implements GraphQlTester { /** - * {@link EntitySpec} implementation. + * Default {@link GraphQlTester.Entity} implementation. */ - private static class DefaultEntitySpec> implements EntitySpec { + private static class DefaultEntity> implements Entity { private final D entity; @@ -496,7 +496,7 @@ final class DefaultGraphQlTester implements GraphQlTester { private final String inputPath; - protected DefaultEntitySpec(D entity, ResponseContainer responseContainer, String path) { + protected DefaultEntity(D entity, ResponseContainer responseContainer, String path) { this.entity = entity; this.responseContainer = responseContainer; this.inputPath = path; @@ -515,8 +515,8 @@ final class DefaultGraphQlTester implements GraphQlTester { } @Override - public PathSpec path(String path) { - return new DefaultPathSpec(path, this.responseContainer); + public Path path(String path) { + return new DefaultPath(path, this.responseContainer); } @Override @@ -569,18 +569,18 @@ final class DefaultGraphQlTester implements GraphQlTester { /** - * {@link ListEntitySpec} implementation. + * Default {@link EntityList} implementation. */ - private static final class DefaultListEntitySpec extends DefaultEntitySpec, ListEntitySpec> - implements ListEntitySpec { + private static final class DefaultEntityList extends DefaultEntity, EntityList> + implements EntityList { - private DefaultListEntitySpec(List entity, ResponseContainer responseContainer, String path) { + private DefaultEntityList(List entity, ResponseContainer responseContainer, String path) { super(entity, responseContainer, path); } @Override @SuppressWarnings("unchecked") - public ListEntitySpec contains(E... elements) { + public EntityList contains(E... elements) { doAssert(() -> { List expected = Arrays.asList(elements); AssertionErrors.assertTrue("List at path '" + getInputPath() + "' does not contain " + expected, @@ -591,7 +591,7 @@ final class DefaultGraphQlTester implements GraphQlTester { @Override @SuppressWarnings("unchecked") - public ListEntitySpec doesNotContain(E... elements) { + public EntityList doesNotContain(E... elements) { doAssert(() -> { List expected = Arrays.asList(elements); AssertionErrors.assertTrue( @@ -603,7 +603,7 @@ final class DefaultGraphQlTester implements GraphQlTester { @Override @SuppressWarnings("unchecked") - public ListEntitySpec containsExactly(E... elements) { + public EntityList containsExactly(E... elements) { doAssert(() -> { List expected = Arrays.asList(elements); AssertionErrors.assertTrue( @@ -614,14 +614,14 @@ final class DefaultGraphQlTester implements GraphQlTester { } @Override - public ListEntitySpec hasSize(int size) { + public EntityList hasSize(int size) { doAssert(() -> AssertionErrors.assertTrue("List at path '" + getInputPath() + "' should have size " + size, getEntity().size() == size)); return this; } @Override - public ListEntitySpec hasSizeLessThan(int boundary) { + public EntityList hasSizeLessThan(int boundary) { doAssert(() -> AssertionErrors.assertTrue( "List at path '" + getInputPath() + "' should have size less than " + boundary, getEntity().size() < boundary)); @@ -629,7 +629,7 @@ final class DefaultGraphQlTester implements GraphQlTester { } @Override - public ListEntitySpec hasSizeGreaterThan(int boundary) { + public EntityList hasSizeGreaterThan(int boundary) { doAssert(() -> AssertionErrors.assertTrue( "List at path '" + getInputPath() + "' should have size greater than " + boundary, getEntity().size() > boundary)); diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebSocketGraphQlTester.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebSocketGraphQlTester.java index 00735f1c..42b2339f 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebSocketGraphQlTester.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/DefaultWebSocketGraphQlTester.java @@ -151,7 +151,7 @@ final class DefaultWebSocketGraphQlTester extends AbstractDelegatingGraphQlTeste .operationName(request.getOperationName()) .variables(request.getVariables()) .execute() - .map(GraphQlClient.ResponseSpec::andReturn); + .map(GraphQlClient.Response::andReturn); } @Override @@ -160,7 +160,7 @@ final class DefaultWebSocketGraphQlTester extends AbstractDelegatingGraphQlTeste .document(request.getDocument()) .operationName(request.getOperationName()) .variables(request.getVariables()) - .executeSubscription().map(GraphQlClient.ResponseSpec::andReturn); + .executeSubscription().map(GraphQlClient.Response::andReturn); } }; } diff --git a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTester.java b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTester.java index 72aa413e..392ed9b7 100644 --- a/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTester.java +++ b/spring-graphql-test/src/main/java/org/springframework/graphql/test/tester/GraphQlTester.java @@ -60,7 +60,7 @@ public interface GraphQlTester { * @return spec for response assertions * @throws AssertionError if the response status is not 200 (OK) */ - RequestSpec document(String document); + Request document(String document); /** * Variant of {@link #document(String)} that uses the given key to resolve @@ -70,7 +70,7 @@ public interface GraphQlTester { * @throws IllegalArgumentException if the documentName cannot be resolved * @throws AssertionError if the response status is not 200 (OK) */ - RequestSpec documentName(String documentName); + Request documentName(String documentName); /** * Create a builder initialized from the configuration of "this" tester. @@ -98,7 +98,7 @@ public interface GraphQlTester { interface Builder> { /** - * Configure a global {@link ErrorSpec#filter(Predicate) filter} that + * Configure a global {@link Errors#filter(Predicate) filter} that * applies to all requests. * @param predicate the error filter to add * @return the same builder instance @@ -126,40 +126,10 @@ public interface GraphQlTester { GraphQlTester build(); } - /** - * Declare options to perform a GraphQL request. - */ - interface ExecuteSpec { - - /** - * Execute the GraphQL request and return a spec for further inspection of - * response data and errors. - * @return options for asserting the response - * @throws AssertionError if the request is performed over HTTP and the response - * status is not 200 (OK). - */ - ResponseSpec execute(); - - /** - * Execute the GraphQL request and verify the response contains no errors. - */ - void executeAndVerify(); - - /** - * Execute the GraphQL request as a subscription and return a spec with options to - * transform the result stream. - * @return spec with options to transform the subscription result stream - * @throws AssertionError if the request is performed over HTTP and the response - * status is not 200 (OK). - */ - SubscriptionSpec executeSubscription(); - - } - /** * Declare options to gather input for a GraphQL request and execute it. */ - interface RequestSpec> extends ExecuteSpec { + interface Request> { /** * Set the operation name. @@ -177,12 +147,35 @@ public interface GraphQlTester { */ T variable(String name, @Nullable Object value); + /** + * Execute the GraphQL request and return a spec for further inspection of + * response data and errors. + * @return options for asserting the response + * @throws AssertionError if the request is performed over HTTP and the response + * status is not 200 (OK). + */ + Response execute(); + + /** + * Execute the GraphQL request and verify the response contains no errors. + */ + void executeAndVerify(); + + /** + * Execute the GraphQL request as a subscription and return a spec with options to + * transform the result stream. + * @return spec with options to transform the subscription result stream + * @throws AssertionError if the request is performed over HTTP and the response + * status is not 200 (OK). + */ + Subscription executeSubscription(); + } /** * Declare options to switch to different part of the GraphQL response. */ - interface TraverseSpec { + interface Traversable { /** * Switch to a path under the "data" section of the GraphQL response. The path can @@ -193,16 +186,16 @@ public interface GraphQlTester { * @return spec for asserting the content under the given path * @throws AssertionError if the GraphQL response contains * errors that have - * not be checked via {@link ResponseSpec#errors()} + * not be checked via {@link Response#errors()} */ - PathSpec path(String path); + Path path(String path); } /** * Declare options to check the data and errors of a GraphQL response. */ - interface ResponseSpec extends TraverseSpec { + interface Response extends Traversable { /** * Return a spec to filter out or inspect errors. This must be used before @@ -210,39 +203,39 @@ public interface GraphQlTester { * be filtered out. * @return the error spec */ - ErrorSpec errors(); + Errors errors(); } /** * Declare options available to assert data at a given path. */ - interface PathSpec extends TraverseSpec { + interface Path extends Traversable { /** * Assert the given path exists, even if the value is {@code null}. * @return spec to assert the converted entity with */ - PathSpec pathExists(); + Path pathExists(); /** * Assert the given path does not {@link #pathExists() exist}. * @return spec to assert the converted entity with */ - PathSpec pathDoesNotExist(); + Path pathDoesNotExist(); /** * Assert a value exists at the given path where the value is any {@code non-null} * value, possibly an empty array or map. * @return spec to assert the converted entity with */ - PathSpec valueExists(); + Path valueExists(); /** * Assert a value does not {@link #valueExists() exist} at the given path. * @return spec to assert the converted entity with */ - PathSpec valueDoesNotExist(); + Path valueDoesNotExist(); /** * Assert the value at the given path does exist but is empty as defined @@ -250,13 +243,13 @@ public interface GraphQlTester { * @return spec to assert the converted entity with * @see org.springframework.util.ObjectUtils#isEmpty(Object) */ - PathSpec valueIsEmpty(); + Path valueIsEmpty(); /** * Assert the value at the given path is not {@link #valueIsEmpty() empty}. * @return spec to assert the converted entity with */ - PathSpec valueIsNotEmpty(); + Path valueIsNotEmpty(); /** * Convert the data at the given path to the target type. @@ -264,7 +257,7 @@ public interface GraphQlTester { * @param the target entity type * @return spec to assert the converted entity with */ - EntitySpec entity(Class entityType); + Entity entity(Class entityType); /** * Convert the data at the given path to the target type. @@ -272,7 +265,7 @@ public interface GraphQlTester { * @param the target entity type * @return spec to assert the converted entity with */ - EntitySpec entity(ParameterizedTypeReference entityType); + Entity entity(ParameterizedTypeReference entityType); /** * Convert the data at the given path to a List of the target type. @@ -280,7 +273,7 @@ public interface GraphQlTester { * @param the target entity type * @return spec to assert the converted List of entities with */ - ListEntitySpec entityList(Class elementType); + EntityList entityList(Class elementType); /** * Convert the data at the given path to a List of the target type. @@ -288,7 +281,7 @@ public interface GraphQlTester { * @param the target entity type * @return spec to assert the converted List of entities with */ - ListEntitySpec entityList(ParameterizedTypeReference elementType); + EntityList entityList(ParameterizedTypeReference elementType); /** * Parse the JSON at the given path and the given expected JSON and assert that @@ -302,7 +295,7 @@ public interface GraphQlTester { * @see org.springframework.test.util.JsonExpectationsHelper#assertJsonEqual(String, * String) */ - TraverseSpec matchesJson(String expectedJson); + Traversable matchesJson(String expectedJson); /** * Parse the JSON at the given path and the given expected JSON and assert that @@ -314,7 +307,7 @@ public interface GraphQlTester { * @see org.springframework.test.util.JsonExpectationsHelper#assertJsonEqual(String, * String, boolean) */ - TraverseSpec matchesJsonStrictly(String expectedJson); + Traversable matchesJsonStrictly(String expectedJson); } @@ -324,7 +317,7 @@ public interface GraphQlTester { * @param the entity type * @param the spec type, including subtypes */ - interface EntitySpec> extends TraverseSpec { + interface Entity> extends Traversable { /** * Assert the converted entity equals the given Object. @@ -383,12 +376,12 @@ public interface GraphQlTester { } /** - * Extension of {@link EntitySpec} with options available to assert data converted to + * Extension of {@link Entity} with options available to assert data converted to * a List of entities. * * @param the type of elements in the list */ - interface ListEntitySpec extends EntitySpec, ListEntitySpec> { + interface EntityList extends Entity, EntityList> { /** * Assert the list contains the given elements. @@ -396,7 +389,7 @@ public interface GraphQlTester { * @return the same spec for more assertions */ @SuppressWarnings("unchecked") - ListEntitySpec contains(E... elements); + EntityList contains(E... elements); /** * Assert the list does not contain the given elements. @@ -404,7 +397,7 @@ public interface GraphQlTester { * @return the same spec for more assertions */ @SuppressWarnings("unchecked") - ListEntitySpec doesNotContain(E... elements); + EntityList doesNotContain(E... elements); /** * Assert the list contains the given elements. @@ -412,28 +405,28 @@ public interface GraphQlTester { * @return the same spec for more assertions */ @SuppressWarnings("unchecked") - ListEntitySpec containsExactly(E... elements); + EntityList containsExactly(E... elements); /** * Assert the list contains the specified number of elements. * @param size the number of elements expected * @return the same spec for more assertions */ - ListEntitySpec hasSize(int size); + EntityList hasSize(int size); /** * Assert the list contains fewer elements than the specified number. * @param boundary the number to compare the number of elements to * @return the same spec for more assertions */ - ListEntitySpec hasSizeLessThan(int boundary); + EntityList hasSizeLessThan(int boundary); /** * Assert the list contains more elements than the specified number. * @param boundary the number to compare the number of elements to * @return the same spec for more assertions */ - ListEntitySpec hasSizeGreaterThan(int boundary); + EntityList hasSizeGreaterThan(int boundary); } @@ -441,7 +434,7 @@ public interface GraphQlTester { * Declare options to filter out expected errors or inspect all errors and verify * there are no unexpected errors. */ - interface ErrorSpec { + interface Errors { /** * Use this to filter out errors that are expected and can be ignored. @@ -449,18 +442,18 @@ public interface GraphQlTester { * with the data. *

The configured filters are applied to all errors. Those that match * are treated as expected and are ignored on {@link #verify()} or when - * {@link TraverseSpec#path(String) traversing} to a data path. + * {@link Traversable#path(String) traversing} to a data path. *

In contrast to {@link #expect(Predicate)}, filters do not have to * match any errors, and don't imply that the errors must be present. * @param errorPredicate the error filter to add * @return the same spec to add more filters before {@link #verify()} */ - ErrorSpec filter(Predicate errorPredicate); + Errors filter(Predicate errorPredicate); /** * Use this to declare errors that are expected. *

Errors that match are treated as expected and are ignored on - * {@link #verify()} or when {@link TraverseSpec#path(String) traversing} + * {@link #verify()} or when {@link Traversable#path(String) traversing} * to a data path. *

In contrast to {@link #filter(Predicate)}, use of this option * does imply that errors are present or else an {@link AssertionError} @@ -468,30 +461,30 @@ public interface GraphQlTester { * @param errorPredicate the predicate for the expected error * @return the same spec to add more filters or expected errors */ - ErrorSpec expect(Predicate errorPredicate); + Errors expect(Predicate errorPredicate); /** * Verify there are either no errors or that there no unexpected errors that have * not been {@link #filter(Predicate) filtered out}. * @return a spec to switch to a data path */ - TraverseSpec verify(); + Traversable verify(); /** * Inspect errors in * the response, if any. Use of this method effectively suppresses all errors and - * allows {@link TraverseSpec#path(String) traversing} to a data path. + * allows {@link Traversable#path(String) traversing} to a data path. * @param errorsConsumer to inspect errors with * @return a spec to switch to a data path */ - TraverseSpec satisfy(Consumer> errorsConsumer); + Traversable satisfy(Consumer> errorsConsumer); } /** * Declare options available to assert a GraphQL Subscription response. */ - interface SubscriptionSpec { + interface Subscription { /** * Return a {@link Flux} of entities converted from some part of the data in each @@ -507,12 +500,12 @@ public interface GraphQlTester { } /** - * Return a {@link Flux} of {@link ResponseSpec} instances, each representing an + * Return a {@link Flux} of {@link Response} instances, each representing an * individual subscription event. * @return a {@code Flux} of {@code ResponseSpec} instances that can be further * inspected, e.g. with {@code reactor.test.StepVerifier} */ - Flux toFlux(); + Flux toFlux(); } diff --git a/spring-graphql-test/src/test/java/org/springframework/graphql/test/tester/GraphQlTesterTests.java b/spring-graphql-test/src/test/java/org/springframework/graphql/test/tester/GraphQlTesterTests.java index abb6b9ea..9ebf9964 100644 --- a/spring-graphql-test/src/test/java/org/springframework/graphql/test/tester/GraphQlTesterTests.java +++ b/spring-graphql-test/src/test/java/org/springframework/graphql/test/tester/GraphQlTesterTests.java @@ -45,11 +45,11 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport { String document = "{me {name, friends}}"; setMockResponse("{\"me\": {\"name\":\"Luke Skywalker\", \"friends\":[]}}"); - GraphQlTester.ResponseSpec spec = graphQlTester().document(document).execute(); + GraphQlTester.Response response = graphQlTester().document(document).execute(); - spec.path("me.name").pathExists().valueExists(); - spec.path("me.friends").pathExists().valueExists(); - spec.path("hero").pathDoesNotExist().valueDoesNotExist(); + response.path("me.name").pathExists().valueExists(); + response.path("me.friends").pathExists().valueExists(); + response.path("hero").pathDoesNotExist().valueDoesNotExist(); assertThat(requestInput().getDocument()).contains(document); } @@ -60,12 +60,12 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport { String document = "{me {name, friends}}"; setMockResponse("{\"me\": {\"name\":null, \"friends\":[]}}"); - GraphQlTester.ResponseSpec spec = graphQlTester().document(document).execute(); + GraphQlTester.Response response = graphQlTester().document(document).execute(); - spec.path("me.name").valueIsEmpty(); - spec.path("me.friends").valueIsEmpty(); + response.path("me.name").valueIsEmpty(); + response.path("me.friends").valueIsEmpty(); - assertThatThrownBy(() -> spec.path("hero").valueIsEmpty()) + assertThatThrownBy(() -> response.path("hero").valueIsEmpty()) .as("Path does not even exist") .hasMessageContaining("No value at JSON path \"$['data']['hero']"); @@ -78,14 +78,14 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport { String document = "{me {name}}"; setMockResponse("{\"me\": {\"name\":\"Luke Skywalker\", \"friends\":[]}}"); - GraphQlTester.ResponseSpec spec = graphQlTester().document(document).execute(); + GraphQlTester.Response response = graphQlTester().document(document).execute(); - spec.path("").matchesJson("{\"me\": {\"name\":\"Luke Skywalker\",\"friends\":[]}}"); - spec.path("me").matchesJson("{\"name\":\"Luke Skywalker\"}"); - spec.path("me").matchesJson("{\"friends\":[]}"); // lenient match with subset of + response.path("").matchesJson("{\"me\": {\"name\":\"Luke Skywalker\",\"friends\":[]}}"); + response.path("me").matchesJson("{\"name\":\"Luke Skywalker\"}"); + response.path("me").matchesJson("{\"friends\":[]}"); // lenient match with subset of // fields - assertThatThrownBy(() -> spec.path("me").matchesJsonStrictly("{\"friends\":[]}")) + assertThatThrownBy(() -> response.path("me").matchesJsonStrictly("{\"friends\":[]}")) .as("Extended fields should fail in strict mode") .hasMessageContaining("Unexpected: name"); @@ -98,13 +98,13 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport { String document = "{me {name}}"; setMockResponse("{\"me\": {\"name\":\"Luke Skywalker\"}}"); - GraphQlTester.ResponseSpec spec = graphQlTester().document(document).execute(); + GraphQlTester.Response response = graphQlTester().document(document).execute(); MovieCharacter luke = MovieCharacter.create("Luke Skywalker"); MovieCharacter han = MovieCharacter.create("Han Solo"); AtomicReference personRef = new AtomicReference<>(); - MovieCharacter actual = spec.path("me").entity(MovieCharacter.class) + MovieCharacter actual = response.path("me").entity(MovieCharacter.class) .isEqualTo(luke) .isNotEqualTo(han) .satisfies(personRef::set) @@ -115,7 +115,7 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport { assertThat(actual.getName()).isEqualTo("Luke Skywalker"); - spec.path("") + response.path("") .entity(new ParameterizedTypeReference>() {}) .isEqualTo(Collections.singletonMap("me", luke)); @@ -133,13 +133,13 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport { " }" + "}"); - GraphQlTester.ResponseSpec spec = graphQlTester().document(document).execute(); + GraphQlTester.Response response = graphQlTester().document(document).execute(); MovieCharacter han = MovieCharacter.create("Han Solo"); MovieCharacter leia = MovieCharacter.create("Leia Organa"); MovieCharacter jabba = MovieCharacter.create("Jabba the Hutt"); - List actual = spec.path("me.friends").entityList(MovieCharacter.class) + List actual = response.path("me.friends").entityList(MovieCharacter.class) .contains(han) .containsExactly(han, leia) .doesNotContain(jabba) @@ -150,7 +150,7 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport { assertThat(actual).containsExactly(han, leia); - spec.path("me.friends") + response.path("me.friends") .entityList(new ParameterizedTypeReference() {}) .containsExactly(han, leia); @@ -168,14 +168,14 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport { setMockResponse("{\"hero\": {\"name\":\"R2-D2\"}}"); - GraphQlTester.ResponseSpec spec = graphQlTester().document(document) + GraphQlTester.Response response = graphQlTester().document(document) .operationName("HeroNameAndFriends") .variable("episode", "JEDI") .variable("foo", "bar") .variable("keyOnly", null) .execute(); - spec.path("hero").entity(MovieCharacter.class).isEqualTo(MovieCharacter.create("R2-D2")); + response.path("hero").entity(MovieCharacter.class).isEqualTo(MovieCharacter.create("R2-D2")); RequestInput input = requestInput(); assertThat(input.getDocument()).contains(document); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractDelegatingGraphQlClient.java b/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractDelegatingGraphQlClient.java index 94035429..c714f32d 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractDelegatingGraphQlClient.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/AbstractDelegatingGraphQlClient.java @@ -42,11 +42,11 @@ public abstract class AbstractDelegatingGraphQlClient implements GraphQlClient { } - public GraphQlClient.RequestSpec document(String document) { + public Request document(String document) { return this.graphQlClient.document(document); } - public GraphQlClient.RequestSpec documentName(String name) { + public Request documentName(String name) { return this.graphQlClient.documentName(name); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlClient.java b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlClient.java index efb53847..42d1e5c7 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlClient.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/DefaultGraphQlClient.java @@ -69,14 +69,14 @@ final class DefaultGraphQlClient implements GraphQlClient { @Override - public RequestSpec document(String document) { - return new DefaultRequestSpec(Mono.just(document), this.transport, this.jsonPathConfig); + public Request document(String document) { + return new DefaultRequest(Mono.just(document), this.transport, this.jsonPathConfig); } @Override - public RequestSpec documentName(String name) { + public Request documentName(String name) { Mono document = this.documentSource.getDocument(name); - return new DefaultRequestSpec(document, this.transport, this.jsonPathConfig); + return new DefaultRequest(document, this.transport, this.jsonPathConfig); } @Override @@ -107,7 +107,10 @@ final class DefaultGraphQlClient implements GraphQlClient { } - private static final class DefaultRequestSpec implements RequestSpec { + /** + * Default {@link GraphQlClient.Request} implementation. + */ + private static final class DefaultRequest implements Request { private final Mono documentMono; @@ -120,7 +123,7 @@ final class DefaultGraphQlClient implements GraphQlClient { private final Configuration jsonPathConfig; - DefaultRequestSpec(Mono documentMono, GraphQlTransport transport, Configuration jsonPathConfig) { + DefaultRequest(Mono documentMono, GraphQlTransport transport, Configuration jsonPathConfig) { Assert.notNull(documentMono, "'documentMono' is required"); this.documentMono = documentMono; this.transport = transport; @@ -128,35 +131,35 @@ final class DefaultGraphQlClient implements GraphQlClient { } @Override - public DefaultRequestSpec operationName(@Nullable String operationName) { + public DefaultRequest operationName(@Nullable String operationName) { this.operationName = operationName; return this; } @Override - public DefaultRequestSpec variable(String name, Object value) { + public DefaultRequest variable(String name, Object value) { this.variables.put(name, value); return this; } @Override - public RequestSpec variables(Map variables) { + public Request variables(Map variables) { this.variables.putAll(variables); return this; } @Override - public Mono execute() { + public Mono execute() { return getRequestMono() .flatMap(this.transport::execute) - .map(payload -> new DefaultResponseSpec(payload, this.jsonPathConfig)); + .map(payload -> new DefaultResponse(payload, this.jsonPathConfig)); } @Override - public Flux executeSubscription() { + public Flux executeSubscription() { return getRequestMono() .flatMapMany(this.transport::executeSubscription) - .map(payload -> new DefaultResponseSpec(payload, this.jsonPathConfig)); + .map(payload -> new DefaultResponse(payload, this.jsonPathConfig)); } private Mono getRequestMono() { @@ -167,7 +170,10 @@ final class DefaultGraphQlClient implements GraphQlClient { } - private static class DefaultResponseSpec implements ResponseSpec { + /** + * Default {@link GraphQlClient.Response} implementation. + */ + private static class DefaultResponse implements Response { private final ExecutionResult result; @@ -175,7 +181,7 @@ final class DefaultGraphQlClient implements GraphQlClient { private final List errors; - private DefaultResponseSpec(ExecutionResult result, Configuration jsonPathConfig) { + private DefaultResponse(ExecutionResult result, Configuration jsonPathConfig) { this.result = result; this.jsonPathDocument = JsonPath.parse(result.toSpecification(), jsonPathConfig); this.errors = result.getErrors(); diff --git a/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClient.java b/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClient.java index 0df68f6d..8d042d0b 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClient.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/client/GraphQlClient.java @@ -54,7 +54,7 @@ public interface GraphQlClient { * @param document the document for the request * @return spec to further define or execute the request */ - RequestSpec document(String document); + Request document(String document); /** * Variant of {@link #document(String)} that uses the given key to resolve @@ -62,7 +62,7 @@ public interface GraphQlClient { * {@link DocumentSource} that the client is configured with. * @throws IllegalArgumentException if the content could not be loaded */ - RequestSpec documentName(String name); + Request documentName(String name); /** * Return a builder initialized from the configuration of "this" client @@ -105,9 +105,32 @@ public interface GraphQlClient { /** - * Declare options for GraphQL request execution. + * Declare options to gather input for a GraphQL request and execute it. */ - interface ExecuteSpec { + interface Request { + + /** + * Set the name of the operation in the {@link #document(String) document} + * to execute, if the document contains multiple operations. + * @param operationName the operation name + * @return this request spec + */ + Request operationName(@Nullable String operationName); + + /** + * Add a value for a variable defined by the operation. + * @param name the variable name + * @param value the variable value + * @return this request spec + */ + Request variable(String name, Object value); + + /** + * Add all given values for variables defined by the operation. + * @param variables the variable values + * @return this request spec + */ + Request variables(Map variables); /** * Execute as a request with a single response such as a "query" or @@ -116,7 +139,7 @@ public interface GraphQlClient { * decoding of the response. The {@code Mono} may end wth an error due * to transport level issues. */ - Mono execute(); + Mono execute(); /** * Execute a "subscription" request with a stream of responses. @@ -132,38 +155,7 @@ public interface GraphQlClient { *

The {@code Flux} may be cancelled to notify the server to end the * subscription stream. */ - Flux executeSubscription(); - - } - - - /** - * Declare options to gather input for a GraphQL request and execute it. - */ - interface RequestSpec extends ExecuteSpec { - - /** - * Set the name of the operation in the {@link #document(String) document} - * to execute, if the document contains multiple operations. - * @param operationName the operation name - * @return this request spec - */ - RequestSpec operationName(@Nullable String operationName); - - /** - * Add a value for a variable defined by the operation. - * @param name the variable name - * @param value the variable value - * @return this request spec - */ - RequestSpec variable(String name, Object value); - - /** - * Add all given values for variables defined by the operation. - * @param variables the variable values - * @return this request spec - */ - RequestSpec variables(Map variables); + Flux executeSubscription(); } @@ -171,7 +163,7 @@ public interface GraphQlClient { /** * Declare options to decode a response. */ - interface ResponseSpec { + interface Response { /** * Switch to the given the "data" path of the GraphQL response and diff --git a/spring-graphql/src/test/java/org/springframework/graphql/client/GraphQlClientTests.java b/spring-graphql/src/test/java/org/springframework/graphql/client/GraphQlClientTests.java index c6562737..dd55995c 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/client/GraphQlClientTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/client/GraphQlClientTests.java @@ -40,12 +40,12 @@ public class GraphQlClientTests extends GraphQlClientTestSupport { String document = "{me {name}}"; setMockResponse("{\"me\": {\"name\":\"Luke Skywalker\"}}"); - GraphQlClient.ResponseSpec spec = execute(document); + GraphQlClient.Response response = execute(document); MovieCharacter luke = MovieCharacter.create("Luke Skywalker"); - assertThat(spec.toEntity("me", MovieCharacter.class)).isEqualTo(luke); + assertThat(response.toEntity("me", MovieCharacter.class)).isEqualTo(luke); - Map map = spec.toEntity("", new ParameterizedTypeReference>() {}); + Map map = response.toEntity("", new ParameterizedTypeReference>() {}); assertThat(map).containsEntry("me", luke); assertThat(request().getDocument()).contains(document); @@ -62,15 +62,15 @@ public class GraphQlClientTests extends GraphQlClientTestSupport { " }" + "}"); - GraphQlClient.ResponseSpec spec = execute(document); + GraphQlClient.Response response = execute(document); MovieCharacter han = MovieCharacter.create("Han Solo"); MovieCharacter leia = MovieCharacter.create("Leia Organa"); - List characters = spec.toEntityList("me.friends", MovieCharacter.class); + List characters = response.toEntityList("me.friends", MovieCharacter.class); assertThat(characters).containsExactly(han, leia); - characters = spec.toEntityList("me.friends", new ParameterizedTypeReference() {}); + characters = response.toEntityList("me.friends", new ParameterizedTypeReference() {}); assertThat(characters).containsExactly(han, leia); assertThat(request().getDocument()).contains(document); @@ -86,7 +86,7 @@ public class GraphQlClientTests extends GraphQlClientTestSupport { "}"; setMockResponse("{\"hero\": {\"name\":\"R2-D2\"}}"); - GraphQlClient.ResponseSpec spec = graphQlClient().document(document) + GraphQlClient.Response response = graphQlClient().document(document) .operationName("HeroNameAndFriends") .variable("episode", "JEDI") .variable("foo", "bar") @@ -94,9 +94,9 @@ public class GraphQlClientTests extends GraphQlClientTestSupport { .execute() .block(TIMEOUT); - assertThat(spec).isNotNull(); + assertThat(response).isNotNull(); - MovieCharacter character = spec.toEntity("hero", MovieCharacter.class); + MovieCharacter character = response.toEntity("hero", MovieCharacter.class); assertThat(character).isEqualTo(MovieCharacter.create("R2-D2")); GraphQlRequest request = request(); @@ -116,16 +116,16 @@ public class GraphQlClientTests extends GraphQlClientTestSupport { GraphqlErrorBuilder.newError().message("some error").build(), GraphqlErrorBuilder.newError().message("some other error").build()); - GraphQlClient.ResponseSpec spec = execute(document); + GraphQlClient.Response response = execute(document); - assertThat(spec.errors()).extracting(GraphQLError::getMessage) + assertThat(response.errors()).extracting(GraphQLError::getMessage) .containsExactly("some error", "some other error"); } - private GraphQlClient.ResponseSpec execute(String document) { - GraphQlClient.ResponseSpec spec = graphQlClient().document(document).execute().block(TIMEOUT); - assertThat(spec).isNotNull(); - return spec; + private GraphQlClient.Response execute(String document) { + GraphQlClient.Response response = graphQlClient().document(document).execute().block(TIMEOUT); + assertThat(response).isNotNull(); + return response; } }