Extract base class for BatchMapping tests

See gh-119
This commit is contained in:
Rossen Stoyanchev
2021-11-10 13:53:31 +00:00
parent 2d5f9ce2a0
commit 3669d29c5f
3 changed files with 242 additions and 206 deletions

View File

@@ -54,15 +54,16 @@ public class BatchMappingDetectionTests {
@Test
void registerWithDefaultCoordinates() {
Map<String, Map<String, DataFetcher>> map =
Map<String, Map<String, DataFetcher>> dataFetcherMap =
initRuntimeWiringBuilder(BookController.class).build().getDataFetchers();
assertThat(map).containsOnlyKeys("Book");
assertThat(map.get("Book")).containsOnlyKeys(
assertThat(dataFetcherMap).containsOnlyKeys("Book");
assertThat(dataFetcherMap.get("Book")).containsOnlyKeys(
"authorFlux", "authorList", "authorMonoMap", "authorMap", "authorEnvironment");
DataLoaderRegistry registry = new DataLoaderRegistry();
this.batchLoaderRegistry.registerDataLoaders(registry, GraphQLContext.newContext().build());
assertThat(registry.getDataLoadersMap()).containsOnlyKeys(
"Book.authorFlux", "Book.authorList", "Book.authorMonoMap", "Book.authorMap", "Book.authorEnvironment");
}

View File

@@ -15,11 +15,6 @@
*/
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;
import java.util.Set;
@@ -27,8 +22,6 @@ 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;
@@ -37,17 +30,10 @@ import reactor.core.publisher.Flux;
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.GraphQlSetup;
import org.springframework.graphql.RequestInput;
import org.springframework.graphql.data.method.annotation.BatchMapping;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.graphql.execution.BatchLoaderRegistry;
import org.springframework.graphql.execution.DefaultBatchLoaderRegistry;
import org.springframework.graphql.execution.ExecutionGraphQlService;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Controller;
import static org.assertj.core.api.Assertions.assertThat;
@@ -60,42 +46,7 @@ import static org.junit.jupiter.params.provider.Arguments.arguments;
* @author Rossen Stoyanchev
*/
@SuppressWarnings("unused")
public class BatchMappingInvocationTests {
private static final Map<Long, Course> courseMap = new HashMap<>();
private static final Map<Long, Person> personMap = new HashMap<>();
static {
Course.save(11L, "Ethical Hacking", 15L, Arrays.asList(22L, 26L, 31L));
Course.save(19L, "Docker and Kubernetes", 17L, Arrays.asList(31L, 39L, 44L, 45L));
Person.save(15L, "Josh", "Kelly");
Person.save(17L, "Albert", "Murray");
Person.save(22L, "Bonnie", "Gray");
Person.save(26L, "John", "Perry");
Person.save(31L, "Alaine", "Baily");
Person.save(39L, "Jeff", "Peterson");
Person.save(44L, "Jared", "Mccarthy");
Person.save(45L, "Benjamin", "Brown");
}
private static final String schema = "" +
"type Query {" +
" courses: [Course]" +
"}" +
"type Course {" +
" id: ID" +
" name: String" +
" instructor: Person" +
" students: [Person]" +
"}" +
"type Person {" +
" id: ID" +
" firstName: String" +
" lastName: String" +
"}";
public class BatchMappingInvocationTests extends BatchMappingTestSupport {
private static Stream<Arguments> controllerClasses() {
return Stream.of(
@@ -106,6 +57,7 @@ public class BatchMappingInvocationTests {
);
}
@ParameterizedTest
@MethodSource("controllerClasses")
void oneToOne(Class<?> controllerClass) {
@@ -121,7 +73,7 @@ public class BatchMappingInvocationTests {
" }" +
"}";
Mono<ExecutionResult> resultMono = graphQlService(controllerClass, CourseConfig.class)
Mono<ExecutionResult> resultMono = graphQlService(controllerClass)
.execute(new RequestInput(query, null, null, null));
List<Course> actualCourses = GraphQlResponse.from(resultMono).toList("courses", Course.class);
@@ -154,7 +106,7 @@ public class BatchMappingInvocationTests {
" }" +
"}";
Mono<ExecutionResult> resultMono = graphQlService(controllerClass, CourseConfig.class)
Mono<ExecutionResult> resultMono = graphQlService(controllerClass)
.execute(new RequestInput(query, null, null, null));
List<Course> actualCourses = GraphQlResponse.from(resultMono).toList("courses", Course.class);
@@ -180,27 +132,19 @@ public class BatchMappingInvocationTests {
private ExecutionGraphQlService graphQlService(Class<?>... configClasses) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(configClasses);
applicationContext.register(BatchMappingTestSupport.CourseConfig.class);
applicationContext.refresh();
return applicationContext.getBean(ExecutionGraphQlService.class);
}
private static class CourseController {
@QueryMapping
public Collection<Course> courses() {
return courseMap.values();
}
}
@Controller
private static class BatchMonoMapController extends CourseController {
@BatchMapping
public Mono<Map<Course, Person>> instructor(List<Course> courses) {
return Flux.fromIterable(Course.allCourses())
.collect(Collectors.toMap(Function.identity(), Course::instructor));
return Flux.fromIterable(courses).collect(Collectors.toMap(Function.identity(), Course::instructor));
}
@BatchMapping
@@ -214,8 +158,7 @@ public class BatchMappingInvocationTests {
@BatchMapping
public Map<Course, Person> instructor(List<Course> courses) {
return Course.allCourses().stream().collect(
Collectors.toMap(Function.identity(), Course::instructor));
return courses.stream().collect(Collectors.toMap(Function.identity(), Course::instructor));
}
@BatchMapping
@@ -252,143 +195,4 @@ public class BatchMappingInvocationTests {
}
}
private static class CourseConfig {
@Bean
public GraphQlService graphQlService(AnnotatedControllerConfigurer configurer, BatchLoaderRegistry registry) {
return GraphQlSetup.schemaContent(schema)
.runtimeWiring(configurer)
.dataLoaders(registry)
.toGraphQlService();
}
@Bean
public AnnotatedControllerConfigurer annotatedDataFetcherConfigurer() {
return new AnnotatedControllerConfigurer();
}
@Bean
public BatchLoaderRegistry batchLoaderRegistry() {
return new DefaultBatchLoaderRegistry();
}
}
private static class Course {
private final Long id;
private final String name;
private final Long instructorId;
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;
this.instructorId = instructorId;
this.studentIds = studentIds;
}
public String name() {
return this.name;
}
public Long instructorId() {
return this.instructorId;
}
public List<Long> studentIds() {
return this.studentIds;
}
public List<Person> students() {
return this.studentIds.stream().map(personMap::get).collect(Collectors.toList());
}
public Person instructor() {
return personMap.get(this.instructorId);
}
public static void save(Long id, String name, Long instructorId, List<Long> studentIds) {
Course course = new Course(id, name, instructorId, studentIds);
courseMap.put(id, course);
}
public static List<Course> allCourses() {
return new ArrayList<>(courseMap.values());
}
// Course is a key in the DataLoader map
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
return this.id.equals(((Course) other).id);
}
@Override
public int hashCode() {
return this.id.hashCode();
}
}
private static class Person {
private final Long id;
private final String firstName;
private final 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;
}
public Long id() {
return this.id;
}
public String firstName() {
return this.firstName;
}
public String lastName() {
return this.lastName;
}
public static void save(Long id, String firstName, String lastName) {
Person person = new Person(id, firstName, lastName);
personMap.put(id, person);
}
}
}

View File

@@ -0,0 +1,231 @@
/*
* 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.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;
import java.util.stream.Collectors;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.graphql.GraphQlService;
import org.springframework.graphql.GraphQlSetup;
import org.springframework.graphql.data.method.annotation.QueryMapping;
import org.springframework.graphql.execution.BatchLoaderRegistry;
import org.springframework.graphql.execution.DefaultBatchLoaderRegistry;
import org.springframework.lang.Nullable;
/**
* Support class for {@code @BatchMapping}, and other batch loading tests, that
* provides a suitable schema, domain types, mock data, and configuration.
*
* @author Rossen Stoyanchev
*/
@SuppressWarnings("unused")
public class BatchMappingTestSupport {
static final Map<Long, Course> courseMap = new HashMap<>();
static final Map<Long, Person> personMap = new HashMap<>();
static {
Course.save(11L, "Ethical Hacking", 15L, Arrays.asList(22L, 26L, 31L));
Course.save(19L, "Docker and Kubernetes", 17L, Arrays.asList(31L, 39L, 44L, 45L));
Person.save(15L, "Josh", "Kelly");
Person.save(17L, "Albert", "Murray");
Person.save(22L, "Bonnie", "Gray");
Person.save(26L, "John", "Perry");
Person.save(31L, "Alaine", "Baily");
Person.save(39L, "Jeff", "Peterson");
Person.save(44L, "Jared", "Mccarthy");
Person.save(45L, "Benjamin", "Brown");
}
static final String schema = "" +
"type Query {" +
" courses: [Course]" +
"}" +
"type Course {" +
" id: ID" +
" name: String" +
" instructor: Person" +
" students: [Person]" +
"}" +
"type Person {" +
" id: ID" +
" firstName: String" +
" lastName: String" +
"}";
static class Course {
private final Long id;
private final String name;
private final Long instructorId;
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;
this.instructorId = instructorId;
this.studentIds = studentIds;
}
public String name() {
return this.name;
}
public Long instructorId() {
return this.instructorId;
}
public List<Long> studentIds() {
return this.studentIds;
}
public List<Person> students() {
return this.studentIds.stream().map(personMap::get).collect(Collectors.toList());
}
public Person instructor() {
return personMap.get(this.instructorId);
}
public static void save(Long id, String name, Long instructorId, List<Long> studentIds) {
Course course = new Course(id, name, instructorId, studentIds);
courseMap.put(id, course);
}
public static List<Course> allCourses() {
return new ArrayList<>(courseMap.values());
}
// Course is a key in the DataLoader map
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || getClass() != other.getClass()) {
return false;
}
return this.id.equals(((Course) other).id);
}
@Override
public int hashCode() {
return this.id.hashCode();
}
}
static class Person {
private final Long id;
private final String firstName;
private final 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;
}
public Long id() {
return this.id;
}
public String firstName() {
return this.firstName;
}
public String lastName() {
return this.lastName;
}
public static void save(Long id, String firstName, String lastName) {
Person person = new Person(id, firstName, lastName);
personMap.put(id, person);
}
}
static class CourseController {
@QueryMapping
public Collection<Course> courses() {
return courseMap.values();
}
}
static class CourseConfig {
@Bean
public GraphQlService graphQlService(AnnotatedControllerConfigurer configurer, BatchLoaderRegistry registry) {
return GraphQlSetup.schemaContent(schema)
.runtimeWiring(configurer)
.dataLoaders(registry)
.toGraphQlService();
}
@Bean
public AnnotatedControllerConfigurer annotatedDataFetcherConfigurer() {
return new AnnotatedControllerConfigurer();
}
@Bean
public BatchLoaderRegistry batchLoaderRegistry() {
return new DefaultBatchLoaderRegistry();
}
}
}