Refactoring in spring-graphql tests
Add GraphQlResponse wrapper around ExecutionResult to provide access to data with JSONPath and type conversion, along with convenience methods to verify errors.
This commit is contained in:
@@ -35,6 +35,7 @@ dependencies {
|
||||
testImplementation 'com.querydsl:querydsl-core'
|
||||
testImplementation 'com.querydsl:querydsl-collections'
|
||||
testImplementation 'javax.servlet:javax.servlet-api'
|
||||
testImplementation 'com.jayway.jsonpath:json-path'
|
||||
testImplementation 'com.fasterxml.jackson.core:jackson-databind'
|
||||
|
||||
testRuntimeOnly 'org.apache.logging.log4j:log4j-core'
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
import com.jayway.jsonpath.DocumentContext;
|
||||
import com.jayway.jsonpath.JsonPath;
|
||||
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.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Wrap an {@link ExecutionResult} for testing purposes. Provide data access
|
||||
* methods with JSONPath and type conversion, transparently check for no errors,
|
||||
* and provide convenience methods to verify errors.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class GraphQlResponse {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(GraphQlResponse.class);
|
||||
|
||||
|
||||
private final DocumentContext documentContext;
|
||||
|
||||
private final List<GraphQLError> errors;
|
||||
|
||||
private boolean errorsChecked;
|
||||
|
||||
|
||||
private GraphQlResponse(ExecutionResult result) {
|
||||
this.documentContext = JsonPath.parse(result.toSpecification(), initJsonPathConfig());
|
||||
this.errors = result.getErrors();
|
||||
}
|
||||
|
||||
private static Configuration initJsonPathConfig() {
|
||||
return Configuration.builder()
|
||||
.jsonProvider(new JacksonJsonProvider())
|
||||
.mappingProvider(new JacksonMappingProvider())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
public GraphQlResponse log() {
|
||||
logger.debug("GraphQlResponse: " + this.documentContext.jsonString());
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> T toEntity(String path, Class<T> targetClass) {
|
||||
assertNoErrors();
|
||||
return this.documentContext.read(jsonPath(path), targetClass);
|
||||
}
|
||||
|
||||
public <T> T toEntity(String path, ParameterizedTypeReference<T> targetType) {
|
||||
assertNoErrors();
|
||||
return this.documentContext.read(jsonPath(path), new TypeRefAdapter<>(targetType));
|
||||
}
|
||||
|
||||
public <T> List<T> toList(String path, Class<T> elementClass) {
|
||||
assertNoErrors();
|
||||
return this.documentContext.read(jsonPath(path), new TypeRefAdapter<>(List.class, elementClass));
|
||||
}
|
||||
|
||||
public <T> List<T> toList(String path, ParameterizedTypeReference<T> elementType) {
|
||||
assertNoErrors();
|
||||
return this.documentContext.read(jsonPath(path), new TypeRefAdapter<>(List.class, elementType));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> T rawValue(String path) {
|
||||
assertNoErrors();
|
||||
return this.documentContext.read(jsonPath(path));
|
||||
}
|
||||
|
||||
private void assertNoErrors() {
|
||||
if (!this.errorsChecked) {
|
||||
assertThat(this.errors).as("Errors present in GraphQL response").isEmpty();
|
||||
this.errorsChecked = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static JsonPath jsonPath(String path) {
|
||||
if (!StringUtils.hasText(path)) {
|
||||
path = "$.data";
|
||||
}
|
||||
else if (!path.startsWith("$") && !path.startsWith("data.")) {
|
||||
path = "$.data." + path;
|
||||
}
|
||||
return JsonPath.compile(path);
|
||||
}
|
||||
|
||||
public int errorCount() {
|
||||
this.errorsChecked = true;
|
||||
return this.errors.size();
|
||||
}
|
||||
|
||||
public Error error(int index) {
|
||||
this.errorsChecked = true;
|
||||
return new Error(index);
|
||||
}
|
||||
|
||||
|
||||
public static GraphQlResponse from(ExecutionResult result) {
|
||||
return new GraphQlResponse(result);
|
||||
}
|
||||
|
||||
public static GraphQlResponse from(Mono<? extends ExecutionResult> resultMono) {
|
||||
ExecutionResult result = resultMono.block();
|
||||
assertThat(result).isNotNull();
|
||||
return from(result);
|
||||
}
|
||||
|
||||
public static Flux<GraphQlResponse> forSubscription(ExecutionResult result) {
|
||||
assertThat(result.getErrors()).as("Errors present in GraphQL response").isEmpty();
|
||||
Publisher<ExecutionResult> publisher = result.getData();
|
||||
return Flux.from(publisher).map(GraphQlResponse::from);
|
||||
}
|
||||
|
||||
@SuppressWarnings("BlockingMethodInNonBlockingContext")
|
||||
public static Flux<GraphQlResponse> forSubscription(Mono<ExecutionResult> resultMono) {
|
||||
ExecutionResult result = resultMono.block();
|
||||
assertThat(result).isNotNull();
|
||||
return forSubscription(result);
|
||||
}
|
||||
|
||||
|
||||
public class Error {
|
||||
|
||||
private final int index;
|
||||
|
||||
public Error(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public String message() {
|
||||
return GraphQlResponse.this.errors.get(index).getMessage();
|
||||
}
|
||||
|
||||
public String errorType() {
|
||||
return GraphQlResponse.this.errors.get(index).getErrorType().toString();
|
||||
}
|
||||
|
||||
public Map<String, Object> extensions() {
|
||||
return GraphQlResponse.this.errors.get(index).getExtensions();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static final class TypeRefAdapter<T> extends TypeRef<T> {
|
||||
|
||||
private final Type type;
|
||||
|
||||
TypeRefAdapter(ParameterizedTypeReference<T> typeReference) {
|
||||
this.type = typeReference.getType();
|
||||
}
|
||||
|
||||
TypeRefAdapter(Class<?> clazz, Class<?> generic) {
|
||||
this.type = ResolvableType.forClassWithGenerics(clazz, generic).getType();
|
||||
}
|
||||
|
||||
TypeRefAdapter(Class<?> clazz, ParameterizedTypeReference<?> generic) {
|
||||
this.type = ResolvableType.forClassWithGenerics(clazz, ResolvableType.forType(generic)).getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,18 +17,13 @@
|
||||
package org.springframework.graphql;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
import graphql.ExecutionResult;
|
||||
import graphql.schema.DataFetcher;
|
||||
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
import org.springframework.graphql.execution.RuntimeWiringConfigurer;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Utility methods for GraphQL tests.
|
||||
@@ -36,7 +31,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public abstract class GraphQlTestUtils {
|
||||
|
||||
/**
|
||||
* Convenience method for a {@link GraphQlSource.Builder} with a single {@link DataFetcher}.
|
||||
* Initialize a {@link GraphQlSource.Builder} with a single {@link DataFetcher}.
|
||||
*
|
||||
* @param schema either String content or a {@link Resource}.
|
||||
* @param typeName the parent type name (Query, Mutation, or Subscription).
|
||||
@@ -53,8 +48,9 @@ public abstract class GraphQlTestUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for a {@link GraphQlSource.Builder} when multiple
|
||||
* {@link DataFetcher} registrations might be needed.
|
||||
* Initialize a {@link GraphQlSource.Builder} with a {@link RuntimeWiringConfigurer},
|
||||
* which may be useful for multiple {@link DataFetcher} registrations, or for a
|
||||
* built-in implementation (e.g. for annotated handler methods).
|
||||
*
|
||||
* @param schema either String content or a {@link Resource}.
|
||||
* @param configurer the configurer to apply to the RuntimeWiring
|
||||
@@ -71,18 +67,4 @@ public abstract class GraphQlTestUtils {
|
||||
.configureRuntimeWiring(configurer);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getData(@Nullable ExecutionResult result, String key) {
|
||||
Map<String, Object> map = getData(result);
|
||||
return (T) map.get(key);
|
||||
}
|
||||
|
||||
public static <T> T getData(@Nullable ExecutionResult result) {
|
||||
assertThat(result).isNotNull();
|
||||
assertThat(result.getErrors()).as("Errors present in GraphQL response").isEmpty();
|
||||
T data = result.getData();
|
||||
assertThat(data).isNotNull();
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.graphql.data.method.annotation.support;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -26,6 +27,8 @@ import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import graphql.ExecutionResult;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
@@ -35,6 +38,7 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.graphql.GraphQlResponse;
|
||||
import org.springframework.graphql.GraphQlService;
|
||||
import org.springframework.graphql.GraphQlTestUtils;
|
||||
import org.springframework.graphql.RequestInput;
|
||||
@@ -44,6 +48,7 @@ import org.springframework.graphql.execution.BatchLoaderRegistry;
|
||||
import org.springframework.graphql.execution.DefaultBatchLoaderRegistry;
|
||||
import org.springframework.graphql.execution.ExecutionGraphQlService;
|
||||
import org.springframework.graphql.execution.GraphQlSource;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.stereotype.Controller;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -55,7 +60,7 @@ import static org.junit.jupiter.params.provider.Arguments.arguments;
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "unused"})
|
||||
@SuppressWarnings("unused")
|
||||
public class BatchMappingInvocationTests {
|
||||
|
||||
private static final Map<Long, Course> courseMap = new HashMap<>();
|
||||
@@ -107,30 +112,31 @@ public class BatchMappingInvocationTests {
|
||||
void oneToOne(Class<?> controllerClass) {
|
||||
String query = "{ " +
|
||||
" courses { " +
|
||||
" id" +
|
||||
" name" +
|
||||
" instructor {" +
|
||||
" id" +
|
||||
" firstName" +
|
||||
" lastName" +
|
||||
" }" +
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
ExecutionResult result = initGraphQlService(controllerClass, CourseConfig.class)
|
||||
.execute(new RequestInput(query, null, null, null))
|
||||
.block();
|
||||
Mono<ExecutionResult> resultMono = graphQlService(controllerClass, CourseConfig.class)
|
||||
.execute(new RequestInput(query, null, null, null));
|
||||
|
||||
List<Map<String, Object>> actualCourses = GraphQlTestUtils.getData(result, "courses");
|
||||
List<Course> actualCourses = GraphQlResponse.from(resultMono).toList("courses", Course.class);
|
||||
List<Course> courses = Course.allCourses();
|
||||
assertThat(actualCourses).hasSize(courses.size());
|
||||
|
||||
for (int i = 0; i < courses.size(); i++) {
|
||||
Map<String, Object> actualCourse = actualCourses.get(i);
|
||||
Course actualCourse = actualCourses.get(i);
|
||||
Course course = courses.get(i);
|
||||
assertThat(actualCourse.get("name")).isEqualTo(course.name());
|
||||
assertThat(actualCourse).isEqualTo(course);
|
||||
|
||||
Map<String, Object> actualInstructor = (Map<String, Object>) actualCourse.get("instructor");
|
||||
assertThat(actualInstructor.get("firstName")).isEqualTo(course.instructor().firstName());
|
||||
assertThat(actualInstructor.get("lastName")).isEqualTo(course.instructor().lastName());
|
||||
Person actualInstructor = actualCourse.instructor();
|
||||
assertThat(actualInstructor.firstName()).isEqualTo(course.instructor().firstName());
|
||||
assertThat(actualInstructor.lastName()).isEqualTo(course.instructor().lastName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,40 +145,40 @@ public class BatchMappingInvocationTests {
|
||||
void oneToMany(Class<?> controllerClass) {
|
||||
String query = "{ " +
|
||||
" courses { " +
|
||||
" id" +
|
||||
" name" +
|
||||
" students {" +
|
||||
" id" +
|
||||
" firstName" +
|
||||
" lastName" +
|
||||
" }" +
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
ExecutionResult result = initGraphQlService(controllerClass, CourseConfig.class)
|
||||
.execute(new RequestInput(query, null, null, null))
|
||||
.block();
|
||||
|
||||
List<Map<String, Object>> actualCourses = GraphQlTestUtils.getData(result, "courses");
|
||||
Mono<ExecutionResult> resultMono = graphQlService(controllerClass, CourseConfig.class)
|
||||
.execute(new RequestInput(query, null, null, null));
|
||||
|
||||
List<Course> actualCourses = GraphQlResponse.from(resultMono).toList("courses", Course.class);
|
||||
List<Course> courses = Course.allCourses();
|
||||
assertThat(actualCourses).hasSize(courses.size());
|
||||
|
||||
for (int i = 0; i < courses.size(); i++) {
|
||||
Map<String, Object> actualCourse = actualCourses.get(i);
|
||||
Course actualCourse = actualCourses.get(i);
|
||||
Course course = courses.get(i);
|
||||
assertThat(actualCourse.get("name")).isEqualTo(course.name());
|
||||
assertThat(actualCourse.name()).isEqualTo(course.name());
|
||||
|
||||
List<Map<String, Object>> actualStudents = (List<Map<String, Object>>) actualCourse.get("students");
|
||||
List<Person> actualStudents = actualCourse.students();
|
||||
List<Person> students = course.students();
|
||||
assertThat(actualStudents).hasSize(students.size());
|
||||
|
||||
for (int j = 0; j < actualStudents.size(); j++) {
|
||||
assertThat(actualStudents.get(i).get("firstName")).isEqualTo(students.get(i).firstName());
|
||||
assertThat(actualStudents.get(i).get("lastName")).isEqualTo(students.get(i).lastName());
|
||||
assertThat(actualStudents.get(i).firstName()).isEqualTo(students.get(i).firstName());
|
||||
assertThat(actualStudents.get(i).lastName()).isEqualTo(students.get(i).lastName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ExecutionGraphQlService initGraphQlService(Class<?>... configClasses) {
|
||||
private ExecutionGraphQlService graphQlService(Class<?>... configClasses) {
|
||||
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
applicationContext.register(configClasses);
|
||||
applicationContext.refresh();
|
||||
@@ -280,6 +286,20 @@ public class BatchMappingInvocationTests {
|
||||
|
||||
private final List<Long> studentIds;
|
||||
|
||||
@JsonCreator
|
||||
public Course(
|
||||
@JsonProperty("id") Long id, @JsonProperty("name") String name,
|
||||
@JsonProperty("instructor") @Nullable Person instructor,
|
||||
@JsonProperty("students") @Nullable List<Person> students) {
|
||||
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.instructorId = (instructor != null ? instructor.id() : -1);
|
||||
this.studentIds = (students != null ?
|
||||
students.stream().map(Person::id).collect(Collectors.toList()) :
|
||||
Collections.emptyList());
|
||||
}
|
||||
|
||||
public Course(Long id, String name, Long instructorId, List<Long> studentIds) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
@@ -343,7 +363,12 @@ public class BatchMappingInvocationTests {
|
||||
|
||||
private final String lastName;
|
||||
|
||||
public Person(Long id, String firstName, String lastName) {
|
||||
@JsonCreator
|
||||
public Person(
|
||||
@JsonProperty("id") Long id,
|
||||
@JsonProperty("firstName") String firstName,
|
||||
@JsonProperty("lastName") String lastName) {
|
||||
|
||||
this.id = id;
|
||||
this.firstName = firstName;
|
||||
this.lastName = lastName;
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package org.springframework.graphql.data.method.annotation.support;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@@ -25,8 +24,8 @@ import graphql.GraphQLContext;
|
||||
import graphql.schema.DataFetchingEnvironment;
|
||||
import org.dataloader.DataLoader;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
@@ -36,6 +35,7 @@ import org.springframework.graphql.Author;
|
||||
import org.springframework.graphql.Book;
|
||||
import org.springframework.graphql.BookCriteria;
|
||||
import org.springframework.graphql.BookSource;
|
||||
import org.springframework.graphql.GraphQlResponse;
|
||||
import org.springframework.graphql.GraphQlService;
|
||||
import org.springframework.graphql.GraphQlTestUtils;
|
||||
import org.springframework.graphql.RequestInput;
|
||||
@@ -72,17 +72,15 @@ public class SchemaMappingInvocationTests {
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
ExecutionResult result = initGraphQlService()
|
||||
.execute(new RequestInput(query, null, null, null))
|
||||
.block();
|
||||
Mono<ExecutionResult> resultMono = graphQlService().execute(new RequestInput(query, null, null, null));
|
||||
|
||||
Map<String, Object> book = GraphQlTestUtils.getData(result, "bookById");
|
||||
assertThat(book.get("id")).isEqualTo("1");
|
||||
assertThat(book.get("name")).isEqualTo("Nineteen Eighty-Four");
|
||||
Book book = GraphQlResponse.from(resultMono).toEntity("bookById", Book.class);
|
||||
assertThat(book.getId()).isEqualTo(1);
|
||||
assertThat(book.getName()).isEqualTo("Nineteen Eighty-Four");
|
||||
|
||||
Map<String, Object> author = (Map<String, Object>) book.get("author");
|
||||
assertThat(author.get("firstName")).isEqualTo("George");
|
||||
assertThat(author.get("lastName")).isEqualTo("Orwell");
|
||||
Author author = book.getAuthor();
|
||||
assertThat(author.getFirstName()).isEqualTo("George");
|
||||
assertThat(author.getLastName()).isEqualTo("Orwell");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -94,15 +92,12 @@ public class SchemaMappingInvocationTests {
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
ExecutionResult result = initGraphQlService()
|
||||
.execute(new RequestInput(query, null, null, null))
|
||||
.block();
|
||||
|
||||
List<Map<String, Object>> bookList = GraphQlTestUtils.getData(result, "booksByCriteria");
|
||||
Mono<ExecutionResult> resultMono = graphQlService().execute(new RequestInput(query, null, null, null));
|
||||
|
||||
List<Book> bookList = GraphQlResponse.from(resultMono).toList("booksByCriteria", Book.class);
|
||||
assertThat(bookList).hasSize(2);
|
||||
assertThat(bookList.get(0).get("name")).isEqualTo("Nineteen Eighty-Four");
|
||||
assertThat(bookList.get(1).get("name")).isEqualTo("Animal Farm");
|
||||
assertThat(bookList.get(0).getName()).isEqualTo("Nineteen Eighty-Four");
|
||||
assertThat(bookList.get(1).getName()).isEqualTo("Animal Farm");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -122,15 +117,12 @@ public class SchemaMappingInvocationTests {
|
||||
return executionInput;
|
||||
});
|
||||
|
||||
ExecutionResult result = initGraphQlService()
|
||||
.execute(requestInput)
|
||||
.block();
|
||||
Mono<ExecutionResult> resultMono = graphQlService().execute(requestInput);
|
||||
|
||||
Map<String, Object> author = GraphQlTestUtils.getData(result, "authorById");
|
||||
|
||||
assertThat(author.get("id")).isEqualTo("101");
|
||||
assertThat(author.get("firstName")).isEqualTo("George");
|
||||
assertThat(author.get("lastName")).isEqualTo("Orwell");
|
||||
Author author = GraphQlResponse.from(resultMono).toEntity("authorById", Author.class);
|
||||
assertThat(author.getId()).isEqualTo(101);
|
||||
assertThat(author.getFirstName()).isEqualTo("George");
|
||||
assertThat(author.getLastName()).isEqualTo("Orwell");
|
||||
|
||||
assertThat(contextRef.get().<String>get("key")).isEqualTo("value");
|
||||
}
|
||||
@@ -145,14 +137,13 @@ public class SchemaMappingInvocationTests {
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
ExecutionResult result = initGraphQlService()
|
||||
.execute(new RequestInput(operation, null, null, null))
|
||||
.block();
|
||||
Mono<ExecutionResult> resultMono = graphQlService()
|
||||
.execute(new RequestInput(operation, null, null, null));
|
||||
|
||||
Map<String, Object> author = GraphQlTestUtils.getData(result, "addAuthor");
|
||||
assertThat(author.get("id")).isEqualTo("99");
|
||||
assertThat(author.get("firstName")).isEqualTo("James");
|
||||
assertThat(author.get("lastName")).isEqualTo("Joyce");
|
||||
Author author = GraphQlResponse.from(resultMono).toEntity("addAuthor", Author.class);
|
||||
assertThat(author.getId()).isEqualTo(99);
|
||||
assertThat(author.getFirstName()).isEqualTo("James");
|
||||
assertThat(author.getLastName()).isEqualTo("Joyce");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -164,31 +155,26 @@ public class SchemaMappingInvocationTests {
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
ExecutionResult result = initGraphQlService()
|
||||
.execute(new RequestInput(operation, null, null, null))
|
||||
.block();
|
||||
Mono<ExecutionResult> resultMono = graphQlService()
|
||||
.execute(new RequestInput(operation, null, null, null));
|
||||
|
||||
Publisher<ExecutionResult> publisher = GraphQlTestUtils.getData(result);
|
||||
|
||||
Flux<Map<String, Object>> bookFlux = Flux.from(publisher).map(executionResult -> {
|
||||
Map<String, Object> map = executionResult.getData();
|
||||
return (Map<String, Object>) map.get("bookSearch");
|
||||
});
|
||||
Flux<Book> bookFlux = GraphQlResponse.forSubscription(resultMono)
|
||||
.map(response -> response.toEntity("bookSearch", Book.class));
|
||||
|
||||
StepVerifier.create(bookFlux)
|
||||
.consumeNextWith(book -> {
|
||||
assertThat(book.get("id")).isEqualTo("1");
|
||||
assertThat(book.get("name")).isEqualTo("Nineteen Eighty-Four");
|
||||
assertThat(book.getId()).isEqualTo(1);
|
||||
assertThat(book.getName()).isEqualTo("Nineteen Eighty-Four");
|
||||
})
|
||||
.consumeNextWith(book -> {
|
||||
assertThat(book.get("id")).isEqualTo("5");
|
||||
assertThat(book.get("name")).isEqualTo("Animal Farm");
|
||||
assertThat(book.getId()).isEqualTo(5);
|
||||
assertThat(book.getName()).isEqualTo("Animal Farm");
|
||||
})
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
|
||||
private ExecutionGraphQlService initGraphQlService() {
|
||||
private ExecutionGraphQlService graphQlService() {
|
||||
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
applicationContext.register(TestConfig.class);
|
||||
applicationContext.refresh();
|
||||
|
||||
@@ -20,9 +20,9 @@ import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.querydsl.core.types.Predicate;
|
||||
import graphql.schema.DataFetcher;
|
||||
@@ -43,6 +43,7 @@ import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.data.repository.Repository;
|
||||
import org.springframework.graphql.Author;
|
||||
import org.springframework.graphql.BookSource;
|
||||
import org.springframework.graphql.GraphQlResponse;
|
||||
import org.springframework.graphql.GraphQlTestUtils;
|
||||
import org.springframework.graphql.data.GraphQlRepository;
|
||||
import org.springframework.graphql.execution.ExecutionGraphQlService;
|
||||
@@ -77,10 +78,10 @@ class QuerydslDataFetcherTests {
|
||||
mockRepository.save(book);
|
||||
|
||||
Consumer<WebGraphQlHandler> tester = (handler) -> {
|
||||
WebOutput output = handler.handleRequest(input("{ bookById(id: 42) {name}}")).block();
|
||||
Mono<WebOutput> outputMono = handler.handleRequest(input("{ bookById(id: 42) {name}}"));
|
||||
|
||||
Map<String, Object> map = GraphQlTestUtils.getData(output, "bookById");
|
||||
assertThat(map).hasSize(1).containsEntry("name", book.getName());
|
||||
Book actualBook = GraphQlResponse.from(outputMono).toEntity("bookById", Book.class);
|
||||
assertThat(actualBook.getName()).isEqualTo(book.getName());
|
||||
};
|
||||
|
||||
// explicit wiring
|
||||
@@ -97,12 +98,12 @@ class QuerydslDataFetcherTests {
|
||||
mockRepository.saveAll(Arrays.asList(book1, book2));
|
||||
|
||||
Consumer<WebGraphQlHandler> tester = (handler) -> {
|
||||
WebOutput output = handler.handleRequest(input("{ books {name}}")).block();
|
||||
Mono<WebOutput> outputMono = handler.handleRequest(input("{ books {name}}"));
|
||||
|
||||
List<Map<String, Object>> data = GraphQlTestUtils.getData(output, "books");
|
||||
assertThat(data).containsExactlyInAnyOrder(
|
||||
Collections.singletonMap("name", "Breaking Bad"),
|
||||
Collections.singletonMap("name", "Hitchhiker's Guide to the Galaxy"));
|
||||
List<String> names = GraphQlResponse.from(outputMono).toList("books", Book.class)
|
||||
.stream().map(Book::getName).collect(Collectors.toList());
|
||||
|
||||
assertThat(names).containsExactlyInAnyOrder(book1.getName(), book2.getName());
|
||||
};
|
||||
|
||||
// explicit wiring
|
||||
@@ -120,20 +121,20 @@ class QuerydslDataFetcherTests {
|
||||
|
||||
// 1) Automatic registration only
|
||||
WebGraphQlHandler handler = initHandler(builder -> {}, mockRepository, null);
|
||||
WebOutput output = handler.handleRequest(input("{ bookById(id: 1) {name}}")).block();
|
||||
Mono<WebOutput> outputMono = handler.handleRequest(input("{ bookById(id: 1) {name}}"));
|
||||
|
||||
Map<String, Object> map = GraphQlTestUtils.getData(output, "bookById");
|
||||
assertThat(map).hasSize(1).containsEntry("name", "Hitchhiker's Guide to the Galaxy");
|
||||
Book actualBook = GraphQlResponse.from(outputMono).toEntity("bookById", Book.class);
|
||||
assertThat(actualBook.getName()).isEqualTo("Hitchhiker's Guide to the Galaxy");
|
||||
|
||||
// 2) Automatic registration and explicit wiring
|
||||
handler = initHandler(
|
||||
"bookById", env -> new Book(53L, "Breaking Bad", new Author(0L, "", "Heisenberg")),
|
||||
mockRepository);
|
||||
|
||||
output = handler.handleRequest(input("{ bookById(id: 1) {name}}")).block();
|
||||
outputMono = handler.handleRequest(input("{ bookById(id: 1) {name}}"));
|
||||
|
||||
map = GraphQlTestUtils.getData(output, "bookById");
|
||||
assertThat(map).hasSize(1).containsEntry("name", "Breaking Bad");
|
||||
actualBook = GraphQlResponse.from(outputMono).toEntity("bookById", Book.class);
|
||||
assertThat(actualBook.getName()).isEqualTo("Breaking Bad");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -144,10 +145,10 @@ class QuerydslDataFetcherTests {
|
||||
WebGraphQlHandler handler = initHandler("bookById",
|
||||
QuerydslDataFetcher.builder(mockRepository).projectAs(BookProjection.class).single());
|
||||
|
||||
WebOutput output = handler.handleRequest(input("{ bookById(id: 42) {name}}")).block();
|
||||
Mono<WebOutput> outputMono = handler.handleRequest(input("{ bookById(id: 42) {name}}"));
|
||||
|
||||
Map<String, Object> map = GraphQlTestUtils.getData(output, "bookById");
|
||||
assertThat(map).hasSize(1).containsEntry("name", "Hitchhiker's Guide to the Galaxy by Douglas Adams");
|
||||
Book actualBook = GraphQlResponse.from(outputMono).toEntity("bookById", Book.class);
|
||||
assertThat(actualBook.getName()).isEqualTo("Hitchhiker's Guide to the Galaxy by Douglas Adams");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -158,10 +159,10 @@ class QuerydslDataFetcherTests {
|
||||
WebGraphQlHandler handler = initHandler("bookById",
|
||||
QuerydslDataFetcher.builder(mockRepository).projectAs(BookDto.class).single());
|
||||
|
||||
WebOutput output = handler.handleRequest(input("{ bookById(id: 42) {name}}")).block();
|
||||
Mono<WebOutput> outputMono = handler.handleRequest(input("{ bookById(id: 42) {name}}"));
|
||||
|
||||
Map<String, Object> map = GraphQlTestUtils.getData(output, "bookById");
|
||||
assertThat(map).hasSize(1).containsEntry("name", "The book is: Hitchhiker's Guide to the Galaxy");
|
||||
Book actualBook = GraphQlResponse.from(outputMono).toEntity("bookById", Book.class);
|
||||
assertThat(actualBook.getName()).isEqualTo("The book is: Hitchhiker's Guide to the Galaxy");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -190,10 +191,10 @@ class QuerydslDataFetcherTests {
|
||||
when(mockRepository.findBy(any(), any())).thenReturn(Mono.just(book));
|
||||
|
||||
Consumer<WebGraphQlHandler> tester = (handler) -> {
|
||||
WebOutput output = handler.handleRequest(input("{ bookById(id: 1) {name}}")).block();
|
||||
Mono<WebOutput> outputMono = handler.handleRequest(input("{ bookById(id: 1) {name}}"));
|
||||
|
||||
Map<String, Object> map = GraphQlTestUtils.getData(output, "bookById");
|
||||
assertThat(map).hasSize(1).containsEntry("name", book.getName());
|
||||
Book actualBook = GraphQlResponse.from(outputMono).toEntity("bookById", Book.class);
|
||||
assertThat(actualBook.getName()).isEqualTo(book.getName());
|
||||
};
|
||||
|
||||
// explicit wiring
|
||||
@@ -211,12 +212,12 @@ class QuerydslDataFetcherTests {
|
||||
when(mockRepository.findBy(any(), any())).thenReturn(Flux.just(book1, book2));
|
||||
|
||||
Consumer<WebGraphQlHandler> tester = (handler) -> {
|
||||
WebOutput output = handler.handleRequest(input("{ books {name}}")).block();
|
||||
Mono<WebOutput> outputMono = handler.handleRequest(input("{ books {name}}"));
|
||||
|
||||
List<Map<String, Object>> data = GraphQlTestUtils.getData(output, "books");
|
||||
assertThat(data).containsExactlyInAnyOrder(
|
||||
Collections.singletonMap("name", "Breaking Bad"),
|
||||
Collections.singletonMap("name", "Hitchhiker's Guide to the Galaxy"));
|
||||
List<String> names = GraphQlResponse.from(outputMono).toList("books", Book.class)
|
||||
.stream().map(Book::getName).collect(Collectors.toList());
|
||||
|
||||
assertThat(names).containsExactlyInAnyOrder("Breaking Bad", "Hitchhiker's Guide to the Galaxy");
|
||||
};
|
||||
|
||||
// explicit wiring
|
||||
|
||||
@@ -23,10 +23,12 @@ import graphql.ExecutionResult;
|
||||
import org.dataloader.DataLoader;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.graphql.Author;
|
||||
import org.springframework.graphql.Book;
|
||||
import org.springframework.graphql.BookSource;
|
||||
import org.springframework.graphql.GraphQlResponse;
|
||||
import org.springframework.graphql.GraphQlTestUtils;
|
||||
import org.springframework.graphql.RequestInput;
|
||||
|
||||
@@ -72,18 +74,15 @@ public class BatchLoadingTests {
|
||||
}));
|
||||
});
|
||||
|
||||
ExecutionResult result = service.execute(new RequestInput(query, null, null, null)).block();
|
||||
Mono<ExecutionResult> resultMono = service.execute(new RequestInput(query, null, null, null));
|
||||
|
||||
assertThat(result.getErrors()).isEmpty();
|
||||
Map<String, Object> data = result.getData();
|
||||
assertThat(data).isNotNull();
|
||||
List<Book> books = GraphQlResponse.from(resultMono).toList("booksByCriteria", Book.class);
|
||||
assertThat(books).hasSize(2);
|
||||
|
||||
List<Map<String, Object>> bookList = getValue(data, "booksByCriteria");
|
||||
assertThat(bookList).hasSize(2);
|
||||
Map<String, Object> authorMap = (Map<String, Object>) bookList.get(0).get("author");
|
||||
assertThat(authorMap).isNotNull();
|
||||
assertThat(authorMap).containsEntry("firstName", "George");
|
||||
assertThat(authorMap).containsEntry("lastName", "Orwell");
|
||||
Author author = books.get(0).getAuthor();
|
||||
assertThat(author).isNotNull();
|
||||
assertThat(author.getFirstName()).isEqualTo("George");
|
||||
assertThat(author.getLastName()).isEqualTo("Orwell");
|
||||
}
|
||||
|
||||
private ExecutionGraphQlService initExecutionGraphQlService(RuntimeWiringConfigurer configurer) {
|
||||
@@ -93,9 +92,4 @@ public class BatchLoadingTests {
|
||||
return service;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T getValue(Map<String, Object> data, String key) {
|
||||
return (T) data.get(key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,11 +17,13 @@ package org.springframework.graphql.execution;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import graphql.ExecutionResult;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.graphql.GraphQlResponse;
|
||||
import org.springframework.graphql.GraphQlTestUtils;
|
||||
import org.springframework.graphql.RequestInput;
|
||||
|
||||
@@ -83,22 +85,19 @@ public class ClassNameTypeResolverTests {
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
ExecutionResult result = new ExecutionGraphQlService(graphQlSource)
|
||||
.execute(new RequestInput(query, null, null, null))
|
||||
.block();
|
||||
|
||||
List<Map<String, Object>> actualAnimals = GraphQlTestUtils.getData(result, "animals");
|
||||
Mono<ExecutionResult> resultMono = new ExecutionGraphQlService(graphQlSource)
|
||||
.execute(new RequestInput(query, null, null, null));
|
||||
|
||||
GraphQlResponse response = GraphQlResponse.from(resultMono);
|
||||
for (int i = 0; i < animalList.size(); i++) {
|
||||
Map<String, Object> actualAnimal = actualAnimals.get(i);
|
||||
Animal animal = animalList.get(i);
|
||||
assertThat(actualAnimal.get("name")).isEqualTo(animal.getName());
|
||||
|
||||
if (animal instanceof Bird) {
|
||||
assertThat(actualAnimal.get("flightless")).isEqualTo(((Bird) animal).isFlightless());
|
||||
Bird bird = (Bird) response.toEntity("animals[" + i + "]", animal.getClass());
|
||||
assertThat(bird.isFlightless()).isEqualTo(((Bird) animal).isFlightless());
|
||||
}
|
||||
else if (animal instanceof Mammal) {
|
||||
assertThat(actualAnimal.get("herbivore")).isEqualTo(((Mammal) animal).isHerbivore());
|
||||
Mammal mammal = (Mammal) response.toEntity("animals[" + i + "]", animal.getClass());
|
||||
assertThat(mammal.isHerbivore()).isEqualTo(((Mammal) animal).isHerbivore());
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException();
|
||||
@@ -133,21 +132,19 @@ public class ClassNameTypeResolverTests {
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
ExecutionResult result = new ExecutionGraphQlService(graphQlSource)
|
||||
.execute(new RequestInput(query, null, null, null))
|
||||
.block();
|
||||
|
||||
List<Map<String, Object>> actualSightings = GraphQlTestUtils.getData(result, "sightings");
|
||||
Mono<ExecutionResult> resultMono = new ExecutionGraphQlService(graphQlSource)
|
||||
.execute(new RequestInput(query, null, null, null));
|
||||
|
||||
GraphQlResponse response = GraphQlResponse.from(resultMono);
|
||||
for (int i = 0; i < animalAndPlantList.size(); i++) {
|
||||
Map<String, Object> actualSighting = actualSightings.get(i);
|
||||
Object sighting = animalAndPlantList.get(i);
|
||||
|
||||
if (sighting instanceof Animal) {
|
||||
assertThat(actualSighting.get("name")).isEqualTo(((Animal) sighting).getName());
|
||||
Animal animal = (Animal) response.toEntity("sightings[" + i + "]", sighting.getClass());
|
||||
assertThat(animal.getName()).isEqualTo(((Animal) sighting).getName());
|
||||
}
|
||||
else if (sighting instanceof Tree) {
|
||||
assertThat(actualSighting.get("family")).isEqualTo(((Tree) sighting).getFamily());
|
||||
Tree tree = (Tree) response.toEntity("sightings[" + i + "]", sighting.getClass());
|
||||
assertThat(tree.getFamily()).isEqualTo(((Tree) sighting).getFamily());
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException();
|
||||
@@ -227,6 +224,7 @@ public class ClassNameTypeResolverTests {
|
||||
}
|
||||
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
static class Penguin extends BaseBird {
|
||||
|
||||
Penguin() {
|
||||
@@ -236,6 +234,7 @@ public class ClassNameTypeResolverTests {
|
||||
}
|
||||
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
static class Dog extends BaseMammal {
|
||||
|
||||
Dog() {
|
||||
@@ -245,6 +244,7 @@ public class ClassNameTypeResolverTests {
|
||||
}
|
||||
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
static class GrayWolf extends BaseMammal {
|
||||
|
||||
GrayWolf() {
|
||||
@@ -268,6 +268,7 @@ public class ClassNameTypeResolverTests {
|
||||
}
|
||||
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
static class GiantRedwood extends Tree {
|
||||
|
||||
GiantRedwood() {
|
||||
|
||||
@@ -18,19 +18,19 @@ package org.springframework.graphql.execution;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import graphql.ExecutionInput;
|
||||
import graphql.ExecutionResult;
|
||||
import graphql.GraphQL;
|
||||
import graphql.schema.DataFetcher;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
import reactor.util.context.Context;
|
||||
import reactor.util.context.ContextView;
|
||||
|
||||
import org.springframework.graphql.GraphQlResponse;
|
||||
import org.springframework.graphql.GraphQlTestUtils;
|
||||
import org.springframework.graphql.TestThreadLocalAccessor;
|
||||
|
||||
@@ -54,9 +54,10 @@ public class ContextDataFetcherDecoratorTests {
|
||||
ExecutionInput input = ExecutionInput.newExecutionInput().query("{ greeting }").build();
|
||||
ReactorContextManager.setReactorContext(Context.of("name", "007"), input);
|
||||
|
||||
Map<String, Object> data = graphQl.executeAsync(input).get().getData();
|
||||
ExecutionResult executionResult = graphQl.executeAsync(input).get();
|
||||
|
||||
assertThat(data).hasSize(1).containsEntry("greeting", "Hello 007");
|
||||
String greeting = GraphQlResponse.from(executionResult).toEntity("greeting", String.class);
|
||||
assertThat(greeting).isEqualTo("Hello 007");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -75,7 +76,7 @@ public class ContextDataFetcherDecoratorTests {
|
||||
|
||||
ExecutionResult result = graphQl.executeAsync(input).get();
|
||||
|
||||
List<String> data = GraphQlTestUtils.getData(result, "greetings");
|
||||
List<String> data = GraphQlResponse.from(result).toList("greetings", String.class);;
|
||||
assertThat(data).containsExactly("Hi 007", "Bonjour 007", "Hola 007");
|
||||
}
|
||||
|
||||
@@ -92,14 +93,14 @@ public class ContextDataFetcherDecoratorTests {
|
||||
ExecutionInput input = ExecutionInput.newExecutionInput().query("subscription { greetings }").build();
|
||||
ReactorContextManager.setReactorContext(Context.of("name", "007"), input);
|
||||
|
||||
Publisher<String> publisher = graphQl.executeAsync(input).get().getData();
|
||||
ExecutionResult executionResult = graphQl.executeAsync(input).get();
|
||||
|
||||
List<String> actual = Flux.from(publisher).cast(ExecutionResult.class)
|
||||
.map((result) -> GraphQlTestUtils.<String>getData(result, "greetings"))
|
||||
.collectList()
|
||||
.block();
|
||||
Flux<String> greetingsFlux = GraphQlResponse.forSubscription(executionResult)
|
||||
.map(response -> response.toEntity("greetings", String.class));
|
||||
|
||||
assertThat(actual).containsExactly("Hi 007", "Bonjour 007", "Hola 007");
|
||||
StepVerifier.create(greetingsFlux)
|
||||
.expectNext("Hi 007", "Bonjour 007", "Hola 007")
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -116,12 +117,11 @@ public class ContextDataFetcherDecoratorTests {
|
||||
ContextView view = ReactorContextManager.extractThreadLocalValues(accessor, Context.empty());
|
||||
ReactorContextManager.setReactorContext(view, input);
|
||||
|
||||
ExecutionResult result = Mono.delay(Duration.ofMillis(10))
|
||||
.flatMap((aLong) -> Mono.fromFuture(graphQl.executeAsync(input)))
|
||||
.block();
|
||||
Mono<ExecutionResult> resultMono = Mono.delay(Duration.ofMillis(10))
|
||||
.flatMap((aLong) -> Mono.fromFuture(graphQl.executeAsync(input)));
|
||||
|
||||
Map<String, Object> data = GraphQlTestUtils.getData(result);
|
||||
assertThat(data).hasSize(1).containsEntry("greeting", "Hello 007");
|
||||
String greeting = GraphQlResponse.from(resultMono).toEntity("greeting", String.class);
|
||||
assertThat(greeting).isEqualTo("Hello 007");
|
||||
}
|
||||
finally {
|
||||
nameThreadLocal.remove();
|
||||
|
||||
@@ -18,8 +18,6 @@ package org.springframework.graphql.execution;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import graphql.ExecutionInput;
|
||||
@@ -33,6 +31,7 @@ import reactor.core.publisher.Mono;
|
||||
import reactor.util.context.Context;
|
||||
import reactor.util.context.ContextView;
|
||||
|
||||
import org.springframework.graphql.GraphQlResponse;
|
||||
import org.springframework.graphql.GraphQlTestUtils;
|
||||
import org.springframework.graphql.TestThreadLocalAccessor;
|
||||
|
||||
@@ -55,13 +54,13 @@ public class ExceptionResolversExceptionHandlerTests {
|
||||
ExecutionInput input = ExecutionInput.newExecutionInput().query("{ greeting }").build();
|
||||
ExecutionResult result = graphQl.executeAsync(input).get();
|
||||
|
||||
Map<String, Object> data = result.getData();
|
||||
assertThat(data).hasSize(1).containsEntry("greeting", null);
|
||||
GraphQlResponse response = GraphQlResponse.from(result);
|
||||
assertThat(response.errorCount()).isEqualTo(1);
|
||||
assertThat(response.error(0).message()).isEqualTo("Resolved error: Invalid greeting");
|
||||
assertThat(response.error(0).errorType()).isEqualTo("BAD_REQUEST");
|
||||
|
||||
List<GraphQLError> errors = result.getErrors();
|
||||
assertThat(errors).hasSize(1);
|
||||
assertThat(errors.get(0).getMessage()).isEqualTo("Resolved error: Invalid greeting");
|
||||
assertThat(errors.get(0).getErrorType().toString()).isEqualTo("BAD_REQUEST");
|
||||
String greeting = response.rawValue("greeting");
|
||||
assertThat(greeting).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -77,8 +76,9 @@ public class ExceptionResolversExceptionHandlerTests {
|
||||
|
||||
ExecutionResult result = graphQl.executeAsync(input).get();
|
||||
|
||||
List<GraphQLError> errors = result.getErrors();
|
||||
assertThat(errors.get(0).getMessage()).isEqualTo("Resolved error: Invalid greeting, name=007");
|
||||
GraphQlResponse response = GraphQlResponse.from(result);
|
||||
assertThat(response.errorCount()).isEqualTo(1);
|
||||
assertThat(response.error(0).message()).isEqualTo("Resolved error: Invalid greeting, name=007");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -97,12 +97,12 @@ public class ExceptionResolversExceptionHandlerTests {
|
||||
ContextView view = ReactorContextManager.extractThreadLocalValues(accessor, Context.empty());
|
||||
ReactorContextManager.setReactorContext(view, input);
|
||||
|
||||
ExecutionResult result = Mono.delay(Duration.ofMillis(10))
|
||||
.flatMap((aLong) -> Mono.fromFuture(graphQl.executeAsync(input)))
|
||||
.block();
|
||||
Mono<ExecutionResult> result = Mono.delay(Duration.ofMillis(10))
|
||||
.flatMap((aLong) -> Mono.fromFuture(graphQl.executeAsync(input)));
|
||||
|
||||
List<GraphQLError> errors = result.getErrors();
|
||||
assertThat(errors.get(0).getMessage()).isEqualTo("Resolved error: Invalid greeting, name=007");
|
||||
GraphQlResponse response = GraphQlResponse.from(result);
|
||||
assertThat(response.errorCount()).isEqualTo(1);
|
||||
assertThat(response.error(0).message()).isEqualTo("Resolved error: Invalid greeting, name=007");
|
||||
}
|
||||
finally {
|
||||
nameThreadLocal.remove();
|
||||
@@ -116,14 +116,13 @@ public class ExceptionResolversExceptionHandlerTests {
|
||||
ExecutionInput input = ExecutionInput.newExecutionInput().query("{ greeting }").build();
|
||||
ExecutionResult result = graphQl.executeAsync(input).get();
|
||||
|
||||
Map<String, Object> data = result.getData();
|
||||
assertThat(data).hasSize(1).containsEntry("greeting", null);
|
||||
GraphQlResponse response = GraphQlResponse.from(result);
|
||||
assertThat(response.errorCount()).isEqualTo(1);
|
||||
assertThat(response.error(0).message()).isEqualTo("Invalid greeting");
|
||||
assertThat(response.error(0).errorType()).isEqualTo("INTERNAL_ERROR");
|
||||
|
||||
List<GraphQLError> errors = result.getErrors();
|
||||
assertThat(errors).hasSize(1);
|
||||
GraphQLError error = errors.get(0);
|
||||
assertThat(error.getMessage()).isEqualTo("Invalid greeting");
|
||||
assertThat(error.getErrorType().toString()).isEqualTo("INTERNAL_ERROR");
|
||||
String greeting = response.rawValue("greeting");
|
||||
assertThat(greeting).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -133,9 +132,8 @@ public class ExceptionResolversExceptionHandlerTests {
|
||||
ExecutionInput input = ExecutionInput.newExecutionInput().query("{ greeting }").build();
|
||||
ExecutionResult result = graphQl.executeAsync(input).get();
|
||||
|
||||
Map<String, Object> data = result.getData();
|
||||
assertThat(data).hasSize(1).containsEntry("greeting", null);
|
||||
assertThat(result.getErrors()).hasSize(0);
|
||||
String greeting = GraphQlResponse.from(result).rawValue("greeting");
|
||||
assertThat(greeting).isNull();
|
||||
}
|
||||
|
||||
private static GraphQL initGraphQl(DataFetcherExceptionResolver exceptionResolver) {
|
||||
|
||||
@@ -20,16 +20,15 @@ import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class ConsumeOneAndNeverCompleteInterceptor implements WebInterceptor {
|
||||
|
||||
@Override
|
||||
public Mono<WebOutput> intercept(WebInput webInput, WebInterceptorChain chain) {
|
||||
return chain.next(webInput).map((output) -> output.transform((builder) -> {
|
||||
Publisher<?> publisher = output.getData();
|
||||
assertThat(publisher).isNotNull();
|
||||
builder.data(Flux.from(publisher).take(1).concatWith(Flux.never()));
|
||||
return chain.next(webInput).map((output) -> output.transform(builder -> {
|
||||
if (output.getData() instanceof Publisher) {
|
||||
Flux<?> flux = Flux.from((Publisher<?>) output.getData()).take(1).concatWith(Flux.never());
|
||||
builder.data(flux);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,6 @@ package org.springframework.graphql.web;
|
||||
import java.net.URI;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import graphql.GraphQLError;
|
||||
@@ -29,6 +27,7 @@ import graphql.schema.DataFetchingEnvironment;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.graphql.GraphQlResponse;
|
||||
import org.springframework.graphql.GraphQlService;
|
||||
import org.springframework.graphql.GraphQlTestUtils;
|
||||
import org.springframework.graphql.TestThreadLocalAccessor;
|
||||
@@ -47,8 +46,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
public class WebGraphQlHandlerTests {
|
||||
|
||||
private static final WebInput webInput = new WebInput(
|
||||
URI.create("http://abc.org"), new HttpHeaders(), Collections.singletonMap("query", "{ greeting }"),
|
||||
null, "1");
|
||||
URI.create("https://abc.org"), new HttpHeaders(), Collections.singletonMap("query", "{ greeting }"), null, "1");
|
||||
|
||||
@Test
|
||||
void reactorContextPropagation() {
|
||||
@@ -62,11 +60,11 @@ public class WebGraphQlHandlerTests {
|
||||
GraphQlService service = new ExecutionGraphQlService(graphQlSource);
|
||||
WebGraphQlHandler handler = WebGraphQlHandler.builder(service).build();
|
||||
|
||||
WebOutput webOutput = handler.handleRequest(webInput)
|
||||
.contextWrite((context) -> context.put("name", "007")).block();
|
||||
Mono<WebOutput> outputMono = handler.handleRequest(webInput)
|
||||
.contextWrite((context) -> context.put("name", "007"));
|
||||
|
||||
Map<String, Object> data = webOutput.getData();
|
||||
assertThat(data).hasSize(1).containsEntry("greeting", "Hello 007");
|
||||
String greeting = GraphQlResponse.from(outputMono).toEntity("greeting", String.class);
|
||||
assertThat(greeting).isEqualTo("Hello 007");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -88,15 +86,15 @@ public class WebGraphQlHandlerTests {
|
||||
GraphQlService service = new ExecutionGraphQlService(graphQlSource);
|
||||
WebGraphQlHandler handler = WebGraphQlHandler.builder(service).build();
|
||||
|
||||
WebOutput webOutput = handler.handleRequest(webInput)
|
||||
.contextWrite((context) -> context.put("name", "007")).block();
|
||||
Mono<WebOutput> outputMono = handler.handleRequest(webInput)
|
||||
.contextWrite((context) -> context.put("name", "007"));
|
||||
|
||||
Map<String, Object> data = webOutput.getData();
|
||||
assertThat(data).hasSize(1).containsEntry("greeting", null);
|
||||
GraphQlResponse response = GraphQlResponse.from(outputMono);
|
||||
assertThat(response.errorCount()).isEqualTo(1);
|
||||
assertThat(response.error(0).message()).isEqualTo("Resolved error: Invalid greeting, name=007");
|
||||
|
||||
List<GraphQLError> errors = webOutput.getErrors();
|
||||
assertThat(errors).hasSize(1);
|
||||
assertThat(errors.get(0).getMessage()).isEqualTo("Resolved error: Invalid greeting, name=007");
|
||||
String greeting = response.rawValue("greeting");
|
||||
assertThat(greeting).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -117,9 +115,10 @@ public class WebGraphQlHandlerTests {
|
||||
.threadLocalAccessor(threadLocalAccessor)
|
||||
.build();
|
||||
|
||||
Map<String, Object> data = handler.handleRequest(webInput).block().getData();
|
||||
Mono<WebOutput> outputMono = handler.handleRequest(webInput);
|
||||
|
||||
assertThat(data).hasSize(1).containsEntry("greeting", "Hello 007");
|
||||
String greeting = GraphQlResponse.from(outputMono).toEntity("greeting", String.class);
|
||||
assertThat(greeting).isEqualTo("Hello 007");
|
||||
}
|
||||
finally {
|
||||
nameThreadLocal.remove();
|
||||
@@ -152,10 +151,11 @@ public class WebGraphQlHandlerTests {
|
||||
.threadLocalAccessor(threadLocalAccessor)
|
||||
.build();
|
||||
|
||||
WebOutput webOutput = handler.handleRequest(webInput).block();
|
||||
Mono<WebOutput> outputMono = handler.handleRequest(webInput);
|
||||
|
||||
List<GraphQLError> errors = webOutput.getErrors();
|
||||
assertThat(errors.get(0).getMessage()).isEqualTo("Resolved error: Invalid greeting, name=007");
|
||||
GraphQlResponse response = GraphQlResponse.from(outputMono);
|
||||
assertThat(response.errorCount()).isEqualTo(1);
|
||||
assertThat(response.error(0).message()).isEqualTo("Resolved error: Invalid greeting, name=007");
|
||||
}
|
||||
finally {
|
||||
nameThreadLocal.remove();
|
||||
|
||||
Reference in New Issue
Block a user