Merge branch '1.3.x'
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2025 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.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.graphql.test.tester;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
@@ -34,6 +35,7 @@ import org.springframework.graphql.GraphQlRequest;
|
||||
import org.springframework.graphql.GraphQlResponse;
|
||||
import org.springframework.graphql.ResponseError;
|
||||
import org.springframework.graphql.client.AbstractGraphQlClientBuilder;
|
||||
import org.springframework.graphql.client.ClientGraphQlRequest;
|
||||
import org.springframework.graphql.client.GraphQlClient;
|
||||
import org.springframework.graphql.client.GraphQlTransport;
|
||||
import org.springframework.graphql.support.DocumentSource;
|
||||
@@ -167,6 +169,8 @@ public abstract class AbstractGraphQlTesterBuilder<B extends AbstractGraphQlTest
|
||||
.document(request.getDocument())
|
||||
.operationName(request.getOperationName())
|
||||
.variables(request.getVariables())
|
||||
.extensions(request.getExtensions())
|
||||
.attributes((map) -> copyAttributes(map, request))
|
||||
.execute()
|
||||
.cast(GraphQlResponse.class);
|
||||
}
|
||||
@@ -177,9 +181,17 @@ public abstract class AbstractGraphQlTesterBuilder<B extends AbstractGraphQlTest
|
||||
.document(request.getDocument())
|
||||
.operationName(request.getOperationName())
|
||||
.variables(request.getVariables())
|
||||
.extensions(request.getExtensions())
|
||||
.attributes((map) -> copyAttributes(map, request))
|
||||
.executeSubscription()
|
||||
.cast(GraphQlResponse.class);
|
||||
}
|
||||
|
||||
private static void copyAttributes(Map<String, Object> map, GraphQlRequest request) {
|
||||
if (request instanceof ClientGraphQlRequest clientGraphQlRequest) {
|
||||
map.putAll(clientGraphQlRequest.getAttributes());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -309,12 +309,15 @@ final class DefaultGraphQlTester implements GraphQlTester {
|
||||
*/
|
||||
private static final class DefaultResponse implements Response, Errors {
|
||||
|
||||
private final GraphQlResponse response;
|
||||
|
||||
private final ResponseDelegate delegate;
|
||||
|
||||
private DefaultResponse(
|
||||
GraphQlResponse response, @Nullable Predicate<ResponseError> errorFilter,
|
||||
Consumer<Runnable> assertDecorator, Configuration jsonPathConfig) {
|
||||
|
||||
this.response = response;
|
||||
this.delegate = new ResponseDelegate(response, errorFilter, assertDecorator, jsonPathConfig);
|
||||
}
|
||||
|
||||
@@ -335,6 +338,11 @@ final class DefaultGraphQlTester implements GraphQlTester {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphQlResponse returnResponse() {
|
||||
return this.response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Errors filter(Predicate<ResponseError> predicate) {
|
||||
this.delegate.filterErrors(predicate);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 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.
|
||||
@@ -25,6 +25,7 @@ import java.util.function.Predicate;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.graphql.GraphQlResponse;
|
||||
import org.springframework.graphql.ResponseError;
|
||||
import org.springframework.graphql.client.GraphQlTransport;
|
||||
import org.springframework.graphql.support.DocumentSource;
|
||||
@@ -262,6 +263,13 @@ public interface GraphQlTester {
|
||||
*/
|
||||
Errors errors();
|
||||
|
||||
|
||||
/**
|
||||
* Return the underlying {@link GraphQlResponse} for direct access.
|
||||
* @since 1.3.5
|
||||
*/
|
||||
GraphQlResponse returnResponse();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 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.
|
||||
@@ -30,6 +30,7 @@ import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.graphql.ExecutionGraphQlRequest;
|
||||
import org.springframework.graphql.ExecutionGraphQlService;
|
||||
import org.springframework.graphql.GraphQlRequest;
|
||||
import org.springframework.graphql.GraphQlResponse;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
@@ -500,4 +501,14 @@ public class GraphQlTesterTests extends GraphQlTesterTestSupport {
|
||||
assertThat(getActualRequestDocument()).contains(document);
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnGraphQlResponse() {
|
||||
String document = "{me {name, friends}}";
|
||||
getGraphQlService().setDataAsJson(document, "{\"me\": {\"name\":\"Luke Skywalker\", \"friends\":[]}}");
|
||||
|
||||
GraphQlResponse response = graphQlTester().documentName("me").execute().returnResponse();
|
||||
String value = response.field("me.name").getValue();
|
||||
assertThat(value).isEqualTo("Luke Skywalker");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.List;
|
||||
import graphql.ExecutionInput;
|
||||
import graphql.GraphQLContext;
|
||||
import graphql.TrivialDataFetcher;
|
||||
import graphql.execution.DataFetcherResult;
|
||||
import graphql.schema.DataFetcher;
|
||||
import graphql.schema.DataFetchingEnvironment;
|
||||
import graphql.schema.FieldCoordinates;
|
||||
@@ -39,6 +40,7 @@ import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.graphql.ExecutionGraphQlRequest;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -74,7 +76,6 @@ final class ContextDataFetcherDecorator implements DataFetcher<Object> {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("ReactiveStreamsUnusedPublisher")
|
||||
@Override
|
||||
public Object get(DataFetchingEnvironment env) throws Exception {
|
||||
|
||||
@@ -83,10 +84,33 @@ final class ContextDataFetcherDecorator implements DataFetcher<Object> {
|
||||
ContextSnapshot snapshot = (env.getLocalContext() instanceof GraphQLContext localContext) ?
|
||||
snapshotFactory.captureFrom(graphQlContext, localContext) :
|
||||
snapshotFactory.captureFrom(graphQlContext);
|
||||
|
||||
Mono<Void> cancelledRequest = graphQlContext.get(ExecutionGraphQlRequest.CANCEL_PUBLISHER_CONTEXT_KEY);
|
||||
|
||||
Object value = snapshot.wrap(() -> this.delegate.get(env)).call();
|
||||
|
||||
if (value instanceof DataFetcherResult<?> dataFetcherResult) {
|
||||
Object adapted = updateValue(dataFetcherResult.getData(), snapshot, cancelledRequest);
|
||||
value = DataFetcherResult.newResult()
|
||||
.data(adapted)
|
||||
.errors(dataFetcherResult.getErrors())
|
||||
.localContext(dataFetcherResult.getLocalContext()).build();
|
||||
}
|
||||
else {
|
||||
value = updateValue(value, snapshot, cancelledRequest);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ReactiveStreamsUnusedPublisher")
|
||||
private @Nullable Object updateValue(
|
||||
@Nullable Object value, ContextSnapshot snapshot, @Nullable Mono<Void> cancelledRequest) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.subscription) {
|
||||
Flux<?> subscriptionResult = ReactiveAdapterRegistryHelper.toSubscriptionFlux(value)
|
||||
.onErrorResume((exception) -> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
* Copyright 2020-2025 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.
|
||||
@@ -31,6 +31,7 @@ import org.springframework.graphql.server.WebGraphQlRequest;
|
||||
import org.springframework.graphql.server.WebGraphQlResponse;
|
||||
import org.springframework.graphql.server.support.SerializableGraphQlRequest;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.InvalidMediaTypeException;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.CodecConfigurer;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -102,7 +103,15 @@ public abstract class AbstractGraphQlHttpHandler {
|
||||
|
||||
private Mono<SerializableGraphQlRequest> readRequest(ServerRequest serverRequest) {
|
||||
if (this.codecDelegate != null) {
|
||||
MediaType contentType = serverRequest.headers().contentType().orElse(MediaType.APPLICATION_JSON);
|
||||
ServerRequest.Headers headers = serverRequest.headers();
|
||||
MediaType contentType;
|
||||
try {
|
||||
contentType = headers.contentType().orElse(MediaType.APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
catch (InvalidMediaTypeException ex) {
|
||||
throw new UnsupportedMediaTypeStatusException("Could not parse " +
|
||||
"Content-Type [" + headers.firstHeader(HttpHeaders.CONTENT_TYPE) + "]: " + ex.getMessage());
|
||||
}
|
||||
return this.codecDelegate.decode(serverRequest.bodyToFlux(DataBuffer.class), contentType);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -23,11 +23,14 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.graphql.MediaTypes;
|
||||
import org.springframework.graphql.server.WebGraphQlHandler;
|
||||
import org.springframework.graphql.server.WebGraphQlResponse;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.InvalidMediaTypeException;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.CodecConfigurer;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||
import org.springframework.web.server.NotAcceptableStatusException;
|
||||
|
||||
/**
|
||||
* WebFlux.fn Handler for GraphQL over HTTP requests.
|
||||
@@ -111,7 +114,16 @@ public class GraphQlHttpHandler extends AbstractGraphQlHttpHandler {
|
||||
}
|
||||
|
||||
private static MediaType selectResponseMediaType(ServerRequest serverRequest) {
|
||||
for (MediaType accepted : serverRequest.headers().accept()) {
|
||||
ServerRequest.Headers headers = serverRequest.headers();
|
||||
List<MediaType> acceptedMediaTypes;
|
||||
try {
|
||||
acceptedMediaTypes = headers.accept();
|
||||
}
|
||||
catch (InvalidMediaTypeException ex) {
|
||||
throw new NotAcceptableStatusException("Could not parse " +
|
||||
"Accept header [" + headers.firstHeader(HttpHeaders.ACCEPT) + "]: " + ex.getMessage());
|
||||
}
|
||||
for (MediaType accepted : acceptedMediaTypes) {
|
||||
if (SUPPORTED_MEDIA_TYPES.contains(accepted)) {
|
||||
return accepted;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.graphql.MediaTypes;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.InvalidMediaTypeException;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.PathContainer;
|
||||
import org.springframework.lang.Nullable;
|
||||
@@ -34,6 +35,8 @@ import org.springframework.web.cors.reactive.CorsUtils;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicate;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.server.NotAcceptableStatusException;
|
||||
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
|
||||
@@ -122,7 +125,14 @@ public final class GraphQlRequestPredicates {
|
||||
return true;
|
||||
}
|
||||
ServerRequest.Headers headers = request.headers();
|
||||
MediaType actual = headers.contentType().orElse(MediaType.APPLICATION_OCTET_STREAM);
|
||||
MediaType actual;
|
||||
try {
|
||||
actual = headers.contentType().orElse(MediaType.APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
catch (InvalidMediaTypeException ex) {
|
||||
throw new UnsupportedMediaTypeStatusException("Could not parse " +
|
||||
"Content-Type [" + headers.firstHeader(HttpHeaders.CONTENT_TYPE) + "]: " + ex.getMessage());
|
||||
}
|
||||
boolean contentTypeMatch = false;
|
||||
for (MediaType contentType : contentTypes) {
|
||||
contentTypeMatch = contentType.includes(actual);
|
||||
@@ -139,7 +149,14 @@ public final class GraphQlRequestPredicates {
|
||||
return true;
|
||||
}
|
||||
ServerRequest.Headers headers = request.headers();
|
||||
List<MediaType> acceptedMediaTypes = acceptedMediaTypes(headers);
|
||||
List<MediaType> acceptedMediaTypes;
|
||||
try {
|
||||
acceptedMediaTypes = acceptedMediaTypes(headers);
|
||||
}
|
||||
catch (InvalidMediaTypeException ex) {
|
||||
throw new NotAcceptableStatusException("Could not parse " +
|
||||
"Accept header [" + headers.firstHeader(HttpHeaders.ACCEPT) + "]: " + ex.getMessage());
|
||||
}
|
||||
boolean match = false;
|
||||
outer:
|
||||
for (MediaType acceptedMediaType : acceptedMediaTypes) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020-2024 the original author or authors.
|
||||
* Copyright 2020-2025 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.
|
||||
@@ -37,6 +37,7 @@ import org.springframework.graphql.server.WebGraphQlResponse;
|
||||
import org.springframework.graphql.server.support.SerializableGraphQlRequest;
|
||||
import org.springframework.http.HttpCookie;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.InvalidMediaTypeException;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.server.ServerHttpRequest;
|
||||
@@ -52,6 +53,7 @@ import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.HttpMediaTypeNotSupportedException;
|
||||
import org.springframework.web.server.ServerWebInputException;
|
||||
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.function.ServerRequest;
|
||||
import org.springframework.web.servlet.function.ServerResponse;
|
||||
@@ -148,7 +150,15 @@ public abstract class AbstractGraphQlHttpHandler {
|
||||
private GraphQlRequest readBody(ServerRequest request) throws ServletException {
|
||||
try {
|
||||
if (this.messageConverter != null) {
|
||||
MediaType contentType = request.headers().contentType().orElse(MediaType.APPLICATION_JSON);
|
||||
ServerRequest.Headers headers = request.headers();
|
||||
MediaType contentType;
|
||||
try {
|
||||
contentType = headers.contentType().orElse(MediaType.APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
catch (InvalidMediaTypeException ex) {
|
||||
throw new UnsupportedMediaTypeStatusException("Could not parse " +
|
||||
"Content-Type [" + headers.firstHeader(HttpHeaders.CONTENT_TYPE) + "]: " + ex.getMessage());
|
||||
}
|
||||
if (this.messageConverter.canRead(SerializableGraphQlRequest.class, contentType)) {
|
||||
ServerHttpRequest httpRequest = new ServletServerHttpRequest(request.servletRequest());
|
||||
return (GraphQlRequest) this.messageConverter.read(SerializableGraphQlRequest.class, httpRequest);
|
||||
|
||||
@@ -26,10 +26,13 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.graphql.MediaTypes;
|
||||
import org.springframework.graphql.server.WebGraphQlHandler;
|
||||
import org.springframework.graphql.server.WebGraphQlResponse;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.InvalidMediaTypeException;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.server.NotAcceptableStatusException;
|
||||
import org.springframework.web.servlet.function.ServerRequest;
|
||||
import org.springframework.web.servlet.function.ServerResponse;
|
||||
|
||||
@@ -140,7 +143,16 @@ public class GraphQlHttpHandler extends AbstractGraphQlHttpHandler {
|
||||
}
|
||||
|
||||
private static MediaType selectResponseMediaType(ServerRequest request) {
|
||||
for (MediaType mediaType : request.headers().accept()) {
|
||||
ServerRequest.Headers headers = request.headers();
|
||||
List<MediaType> acceptedMediaTypes;
|
||||
try {
|
||||
acceptedMediaTypes = headers.accept();
|
||||
}
|
||||
catch (InvalidMediaTypeException ex) {
|
||||
throw new NotAcceptableStatusException("Could not parse " +
|
||||
"Accept header [" + headers.firstHeader(HttpHeaders.ACCEPT) + "]: " + ex.getMessage());
|
||||
}
|
||||
for (MediaType mediaType : acceptedMediaTypes) {
|
||||
if (SUPPORTED_MEDIA_TYPES.contains(mediaType)) {
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
@@ -25,12 +25,15 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.graphql.MediaTypes;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.InvalidMediaTypeException;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.PathContainer;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.web.cors.CorsUtils;
|
||||
import org.springframework.web.server.NotAcceptableStatusException;
|
||||
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
|
||||
import org.springframework.web.servlet.function.RequestPredicate;
|
||||
import org.springframework.web.servlet.function.RouterFunctions;
|
||||
import org.springframework.web.servlet.function.ServerRequest;
|
||||
@@ -122,7 +125,14 @@ public final class GraphQlRequestPredicates {
|
||||
return true;
|
||||
}
|
||||
ServerRequest.Headers headers = request.headers();
|
||||
MediaType actual = headers.contentType().orElse(MediaType.APPLICATION_OCTET_STREAM);
|
||||
MediaType actual;
|
||||
try {
|
||||
actual = headers.contentType().orElse(MediaType.APPLICATION_OCTET_STREAM);
|
||||
}
|
||||
catch (InvalidMediaTypeException ex) {
|
||||
throw new UnsupportedMediaTypeStatusException("Could not parse " +
|
||||
"Content-Type [" + headers.firstHeader(HttpHeaders.CONTENT_TYPE) + "]: " + ex.getMessage());
|
||||
}
|
||||
boolean contentTypeMatch = false;
|
||||
for (MediaType contentType : contentTypes) {
|
||||
contentTypeMatch = contentType.includes(actual);
|
||||
@@ -139,7 +149,14 @@ public final class GraphQlRequestPredicates {
|
||||
return true;
|
||||
}
|
||||
ServerRequest.Headers headers = request.headers();
|
||||
List<MediaType> acceptedMediaTypes = acceptedMediaTypes(headers);
|
||||
List<MediaType> acceptedMediaTypes;
|
||||
try {
|
||||
acceptedMediaTypes = acceptedMediaTypes(headers);
|
||||
}
|
||||
catch (InvalidMediaTypeException ex) {
|
||||
throw new NotAcceptableStatusException("Could not parse " +
|
||||
"Accept header [" + headers.firstHeader(HttpHeaders.ACCEPT) + "]: " + ex.getMessage());
|
||||
}
|
||||
boolean match = false;
|
||||
outer:
|
||||
for (MediaType acceptedMediaType : acceptedMediaTypes) {
|
||||
|
||||
@@ -30,6 +30,7 @@ import graphql.GraphQL;
|
||||
import graphql.GraphQLError;
|
||||
import graphql.GraphqlErrorBuilder;
|
||||
import graphql.TrivialDataFetcher;
|
||||
import graphql.execution.DataFetcherResult;
|
||||
import graphql.schema.DataFetcher;
|
||||
import graphql.schema.DataFetcherFactories;
|
||||
import graphql.schema.FieldCoordinates;
|
||||
@@ -135,6 +136,32 @@ public class ContextDataFetcherDecoratorTests {
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
void fluxDataFetcherSubscriptionWithDataFetcherResult() throws Exception {
|
||||
GraphQL graphQl = GraphQlSetup.schemaContent(SCHEMA_CONTENT)
|
||||
.subscriptionFetcher("greetings", (env) -> {
|
||||
Flux<String> flux = Mono.delay(Duration.ofMillis(50))
|
||||
.flatMapMany((aLong) -> Flux.deferContextual((context) -> {
|
||||
String name = context.get("name");
|
||||
return Flux.just("Hi", "Bonjour", "Hola").map((s) -> s + " " + name);
|
||||
}));
|
||||
return DataFetcherResult.newResult().data(flux).build();
|
||||
})
|
||||
.toGraphQl();
|
||||
|
||||
ExecutionInput input = ExecutionInput.newExecutionInput().query("subscription { greetings }").build();
|
||||
input.getGraphQLContext().put("name", "007");
|
||||
|
||||
ExecutionResult executionResult = graphQl.executeAsync(input).get();
|
||||
|
||||
Flux<String> greetingsFlux = ResponseHelper.forSubscription(executionResult)
|
||||
.map(response -> response.toEntity("greetings", String.class));
|
||||
|
||||
StepVerifier.create(greetingsFlux)
|
||||
.expectNext("Hi 007", "Bonjour 007", "Hola 007")
|
||||
.verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
void fluxDataFetcherSubscriptionThrowingException() throws Exception {
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.graphql.server.webflux;
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -31,10 +32,13 @@ import org.springframework.mock.web.server.MockServerWebExchange;
|
||||
import org.springframework.web.reactive.function.server.RequestPredicate;
|
||||
import org.springframework.web.reactive.function.server.RouterFunctions;
|
||||
import org.springframework.web.reactive.function.server.ServerRequest;
|
||||
import org.springframework.web.server.NotAcceptableStatusException;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* Tests for {@link GraphQlRequestPredicates}.
|
||||
@@ -93,23 +97,41 @@ class GraphQlRequestPredicatesTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectRequestWithDifferentContentType() {
|
||||
void shouldRejectRequestWithIncompatibleContentType() {
|
||||
ServerWebExchange exchange = createMatchingHttpExchange()
|
||||
.mutate().request(req -> req.headers(headers -> headers.setContentType(MediaType.TEXT_HTML)))
|
||||
.mutate().request(request -> request.headers(h -> h.setContentType(MediaType.TEXT_HTML)))
|
||||
.build();
|
||||
ServerRequest serverRequest = ServerRequest.create(exchange, Collections.emptyList());
|
||||
assertThat(httpPredicate.test(serverRequest)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectRequestWithInvalidContentType() {
|
||||
ServerWebExchange exchange = createMatchingHttpExchange()
|
||||
.mutate().request(request -> request.headers(h -> h.set("Content-Type", "bogus")))
|
||||
.build();
|
||||
ServerRequest request = ServerRequest.create(exchange, Collections.emptyList());
|
||||
assertThatThrownBy(() -> httpPredicate.test(request)).isInstanceOf(UnsupportedMediaTypeStatusException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectRequestWithIncompatibleAccept() {
|
||||
ServerWebExchange exchange = createMatchingHttpExchange()
|
||||
.mutate().request(req -> req.headers(headers -> headers.setAccept(Collections.singletonList(MediaType.TEXT_HTML))))
|
||||
.mutate().request(request -> request.headers(h -> h.setAccept(List.of(MediaType.TEXT_HTML))))
|
||||
.build();
|
||||
ServerRequest serverRequest = ServerRequest.create(exchange, Collections.emptyList());
|
||||
assertThat(httpPredicate.test(serverRequest)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectRequestWithInvalidAccept() {
|
||||
ServerWebExchange exchange = createMatchingHttpExchange()
|
||||
.mutate().request(request -> request.headers(h -> h.set("Accept", "bogus")))
|
||||
.build();
|
||||
ServerRequest request = ServerRequest.create(exchange, Collections.emptyList());
|
||||
assertThatThrownBy(() -> httpPredicate.test(request)).isInstanceOf(NotAcceptableStatusException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSetMatchingPatternAttribute() {
|
||||
ServerWebExchange exchange = createMatchingHttpExchange();
|
||||
|
||||
@@ -18,18 +18,22 @@ package org.springframework.graphql.server.webmvc;
|
||||
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.web.server.NotAcceptableStatusException;
|
||||
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
|
||||
import org.springframework.web.servlet.function.RequestPredicate;
|
||||
import org.springframework.web.servlet.function.RouterFunctions;
|
||||
import org.springframework.web.servlet.function.ServerRequest;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
/**
|
||||
* Tests for {@link GraphQlRequestPredicates}.
|
||||
@@ -85,13 +89,21 @@ class GraphQlRequestPredicatesTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectRequestWithDifferentContentType() {
|
||||
void shouldRejectRequestWithIncompatibleContentType() {
|
||||
MockHttpServletRequest request = createMatchingHttpRequest();
|
||||
request.setContentType("text/xml");
|
||||
ServerRequest serverRequest = ServerRequest.create(request, Collections.emptyList());
|
||||
assertThat(httpPredicate.test(serverRequest)).isFalse();
|
||||
}
|
||||
|
||||
@Test // gh-1145
|
||||
void shouldRejectRequestWithInvalidContentType() {
|
||||
MockHttpServletRequest servletRequest = createMatchingHttpRequest();
|
||||
servletRequest.setContentType("bogus");
|
||||
ServerRequest request = ServerRequest.create(servletRequest, List.of());
|
||||
assertThatThrownBy(() -> httpPredicate.test(request)).isInstanceOf(UnsupportedMediaTypeStatusException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectRequestWithIncompatibleAccept() {
|
||||
MockHttpServletRequest request = createMatchingHttpRequest();
|
||||
@@ -101,6 +113,15 @@ class GraphQlRequestPredicatesTests {
|
||||
assertThat(httpPredicate.test(serverRequest)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectRequestWithInvalidAccept() {
|
||||
MockHttpServletRequest servletRequest = createMatchingHttpRequest();
|
||||
servletRequest.removeHeader("Accept");
|
||||
servletRequest.addHeader("Accept", "bogus");
|
||||
ServerRequest request = ServerRequest.create(servletRequest, Collections.emptyList());
|
||||
assertThatThrownBy(() -> httpPredicate.test(request)).isInstanceOf(NotAcceptableStatusException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSetMatchingPatternAttribute() {
|
||||
MockHttpServletRequest request = createMatchingHttpRequest();
|
||||
@@ -168,7 +189,7 @@ class GraphQlRequestPredicatesTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectRequestWithDifferentContentType() {
|
||||
void shouldRejectRequestWithIncmopatibleContentType() {
|
||||
MockHttpServletRequest request = createMatchingSseRequest();
|
||||
request.setContentType("text/xml");
|
||||
ServerRequest serverRequest = ServerRequest.create(request, Collections.emptyList());
|
||||
|
||||
Reference in New Issue
Block a user