WebFlux support for "request handled" in controller

Issue: SPR-16087
This commit is contained in:
Rossen Stoyanchev
2017-10-18 19:08:22 -04:00
parent a3eeda99e0
commit d8a7b96b46
5 changed files with 205 additions and 13 deletions

View File

@@ -16,26 +16,40 @@
package org.springframework.web.reactive.result.method;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import org.junit.Test;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.lang.Nullable;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.web.test.server.MockServerWebExchange;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.*;
import static org.springframework.web.method.ResolvableMethod.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.springframework.mock.http.server.reactive.test.MockServerHttpRequest.get;
import static org.springframework.web.method.ResolvableMethod.on;
/**
* Unit tests for {@link InvocableHandlerMethod}.
@@ -45,10 +59,72 @@ import static org.springframework.web.method.ResolvableMethod.*;
*/
public class InvocableHandlerMethodTests {
private final MockServerWebExchange exchange =
MockServerWebExchange.from(MockServerHttpRequest.get("http://localhost:8080/path"));
private final MockServerWebExchange exchange = MockServerWebExchange.from(get("http://localhost:8080/path"));
@Test
public void invokeAndHandle_VoidWithResponseStatus() throws Exception {
Method method = on(VoidController.class).mockCall(VoidController::responseStatus).method();
HandlerResult result = invoke(new VoidController(), method).block(Duration.ZERO);
assertNull("Expected no result (i.e. fully handled)", result);
assertEquals(HttpStatus.BAD_REQUEST, this.exchange.getResponse().getStatusCode());
}
@Test
public void invokeAndHandle_withResponse() throws Exception {
ServerHttpResponse response = this.exchange.getResponse();
Method method = on(VoidController.class).mockCall(c -> c.response(response)).method();
HandlerResult result = invoke(new VoidController(), method, resolverFor(Mono.just(response)))
.block(Duration.ZERO);
assertNull("Expected no result (i.e. fully handled)", result);
assertEquals("bar", this.exchange.getResponse().getHeaders().getFirst("foo"));
}
@Test
public void invokeAndHandle_withResponseAndMonoVoid() throws Exception {
ServerHttpResponse response = this.exchange.getResponse();
Method method = on(VoidController.class).mockCall(c -> c.responseMonoVoid(response)).method();
HandlerResult result = invoke(new VoidController(), method, resolverFor(Mono.just(response)))
.block(Duration.ZERO);
assertNull("Expected no result (i.e. fully handled)", result);
assertEquals("body", this.exchange.getResponse().getBodyAsString().block(Duration.ZERO));
}
@Test
public void invokeAndHandle_withExchange() throws Exception {
Method method = on(VoidController.class).mockCall(c -> c.exchange(exchange)).method();
HandlerResult result = invoke(new VoidController(), method, resolverFor(Mono.just(this.exchange)))
.block(Duration.ZERO);
assertNull("Expected no result (i.e. fully handled)", result);
assertEquals("bar", this.exchange.getResponse().getHeaders().getFirst("foo"));
}
@Test
public void invokeAndHandle_withExchangeAndMonoVoid() throws Exception {
Method method = on(VoidController.class).mockCall(c -> c.exchangeMonoVoid(exchange)).method();
HandlerResult result = invoke(new VoidController(), method, resolverFor(Mono.just(this.exchange)))
.block(Duration.ZERO);
assertNull("Expected no result (i.e. fully handled)", result);
assertEquals("body", this.exchange.getResponse().getBodyAsString().block(Duration.ZERO));
}
@Test
public void invokeAndHandle_withNotModified() throws Exception {
ServerWebExchange exchange = MockServerWebExchange.from(
MockServerHttpRequest.get("/").ifModifiedSince(10 * 1000 * 1000));
Method method = on(VoidController.class).mockCall(c -> c.notModified(exchange)).method();
HandlerResult result = invoke(new VoidController(), method, resolverFor(Mono.just(exchange)))
.block(Duration.ZERO);
assertNull("Expected no result (i.e. fully handled)", result);
}
@Test
public void invokeMethodWithNoArguments() throws Exception {
Method method = on(TestController.class).mockCall(TestController::noArgs).method();
@@ -146,7 +222,7 @@ public class InvocableHandlerMethodTests {
private Mono<HandlerResult> invoke(Object handler, Method method) {
return this.invoke(handler, method, new HandlerMethodArgumentResolver[0]);
return invoke(handler, method, new HandlerMethodArgumentResolver[0]);
}
private Mono<HandlerResult> invoke(Object handler, Method method,
@@ -195,4 +271,45 @@ public class InvocableHandlerMethodTests {
}
}
@SuppressWarnings("unused")
private static class VoidController {
@ResponseStatus(HttpStatus.BAD_REQUEST)
public void responseStatus() {
}
public void response(ServerHttpResponse response) {
response.getHeaders().add("foo", "bar");
}
public Mono<Void> responseMonoVoid(ServerHttpResponse response) {
return response.writeWith(getBody("body"));
}
public void exchange(ServerWebExchange exchange) {
exchange.getResponse().getHeaders().add("foo", "bar");
}
public Mono<Void> exchangeMonoVoid(ServerWebExchange exchange) {
return exchange.getResponse().writeWith(getBody("body"));
}
@Nullable
public String notModified(ServerWebExchange exchange) {
if (exchange.checkNotModified(Instant.ofEpochMilli(1000 * 1000))) {
return null;
}
return "body";
}
private Flux<DataBuffer> getBody(String body) {
try {
return Flux.just(new DefaultDataBufferFactory().wrap(body.getBytes("UTF-8")));
}
catch (UnsupportedEncodingException ex) {
throw new IllegalStateException(ex);
}
}
}
}