This commit is contained in:
Rossen Stoyanchev
2018-11-01 14:20:43 -04:00
parent 47aec50917
commit 48654c6483
5 changed files with 132 additions and 142 deletions

View File

@@ -16,11 +16,12 @@
package org.springframework.web.reactive.result.method;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import reactor.core.publisher.Flux;
@@ -57,94 +58,36 @@ public class InvocableHandlerMethodTests {
private final MockServerWebExchange exchange = MockServerWebExchange.from(get("http://localhost:8080/path"));
private final List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
@Test
public void invokeAndHandle_VoidWithResponseStatus() {
Method method = ResolvableMethod.on(VoidController.class).mockCall(VoidController::responseStatus).method();
HandlerResult result = invokeForResult(new VoidController(), method);
public void resolveArg() {
this.resolvers.add(stubResolver("value1"));
Method method = ResolvableMethod.on(TestController.class).mockCall(o -> o.singleArg(null)).method();
Mono<HandlerResult> mono = invoke(new TestController(), method);
assertNull("Expected no result (i.e. fully handled)", result);
assertEquals(HttpStatus.BAD_REQUEST, this.exchange.getResponse().getStatusCode());
assertHandlerResultValue(mono, "success:value1");
}
@Test
public void invokeAndHandle_withResponse() {
ServerHttpResponse response = this.exchange.getResponse();
Method method = ResolvableMethod.on(VoidController.class).mockCall(c -> c.response(response)).method();
HandlerResult result = invokeForResult(new VoidController(), method, stubResolver(response));
public void resolveNoArgValue() {
this.resolvers.add(stubResolver(Mono.empty()));
Method method = ResolvableMethod.on(TestController.class).mockCall(o -> o.singleArg(null)).method();
Mono<HandlerResult> mono = invoke(new TestController(), method);
assertNull("Expected no result (i.e. fully handled)", result);
assertEquals("bar", this.exchange.getResponse().getHeaders().getFirst("foo"));
assertHandlerResultValue(mono, "success:null");
}
@Test
public void invokeAndHandle_withResponseAndMonoVoid() {
ServerHttpResponse response = this.exchange.getResponse();
Method method = ResolvableMethod.on(VoidController.class).mockCall(c -> c.responseMonoVoid(response)).method();
HandlerResult result = invokeForResult(new VoidController(), method, stubResolver(response));
assertNull("Expected no result (i.e. fully handled)", result);
assertEquals("body", this.exchange.getResponse().getBodyAsString().block(Duration.ZERO));
}
@Test
public void invokeAndHandle_withExchange() {
Method method = ResolvableMethod.on(VoidController.class).mockCall(c -> c.exchange(exchange)).method();
HandlerResult result = invokeForResult(new VoidController(), method, stubResolver(this.exchange));
assertNull("Expected no result (i.e. fully handled)", result);
assertEquals("bar", this.exchange.getResponse().getHeaders().getFirst("foo"));
}
@Test
public void invokeAndHandle_withExchangeAndMonoVoid() {
Method method = ResolvableMethod.on(VoidController.class).mockCall(c -> c.exchangeMonoVoid(exchange)).method();
HandlerResult result = invokeForResult(new VoidController(), method, stubResolver(this.exchange));
assertNull("Expected no result (i.e. fully handled)", result);
assertEquals("body", this.exchange.getResponse().getBodyAsString().block(Duration.ZERO));
}
@Test
public void invokeAndHandle_withNotModified() {
ServerWebExchange exchange = MockServerWebExchange.from(
MockServerHttpRequest.get("/").ifModifiedSince(10 * 1000 * 1000));
Method method = ResolvableMethod.on(VoidController.class).mockCall(c -> c.notModified(exchange)).method();
HandlerResult result = invokeForResult(new VoidController(), method, stubResolver(exchange));
assertNull("Expected no result (i.e. fully handled)", result);
}
@Test
public void invokeMethodWithNoArguments() {
public void resolveNoArgs() {
Method method = ResolvableMethod.on(TestController.class).mockCall(TestController::noArgs).method();
Mono<HandlerResult> mono = invoke(new TestController(), method);
assertHandlerResultValue(mono, "success");
}
@Test
public void invokeMethodWithNoValue() {
Method method = resolveOn().mockCall(o -> o.singleArg(null)).method();
Mono<HandlerResult> mono = invoke(new TestController(), method, stubResolver(Mono.empty()));
assertHandlerResultValue(mono, "success:null");
}
private ResolvableMethod.Builder<TestController> resolveOn() {
return ResolvableMethod.on(TestController.class);
}
@Test
public void invokeMethodWithValue() {
Method method = ResolvableMethod.on(TestController.class).mockCall(o -> o.singleArg(null)).method();
Mono<HandlerResult> mono = invoke(new TestController(), method, stubResolver("value1"));
assertHandlerResultValue(mono, "success:value1");
}
@Test
public void noMatchingResolver() {
public void cannotResolveArg() {
Method method = ResolvableMethod.on(TestController.class).mockCall(o -> o.singleArg(null)).method();
Mono<HandlerResult> mono = invoke(new TestController(), method);
@@ -159,10 +102,27 @@ public class InvocableHandlerMethodTests {
}
@Test
public void resolverThrowsException() {
public void resolveProvidedArg() {
Method method = ResolvableMethod.on(TestController.class).mockCall(o -> o.singleArg(null)).method();
Mono<HandlerResult> mono = invoke(new TestController(), method,
stubResolver(Mono.error(new UnsupportedMediaTypeStatusException("boo"))));
Mono<HandlerResult> mono = invoke(new TestController(), method, "value1");
assertHandlerResultValue(mono, "success:value1");
}
@Test
public void resolveProvidedArgFirst() {
this.resolvers.add(stubResolver("value1"));
Method method = ResolvableMethod.on(TestController.class).mockCall(o -> o.singleArg(null)).method();
Mono<HandlerResult> mono = invoke(new TestController(), method, "value2");
assertHandlerResultValue(mono, "success:value2");
}
@Test
public void exceptionInResolvingArg() {
this.resolvers.add(stubResolver(Mono.error(new UnsupportedMediaTypeStatusException("boo"))));
Method method = ResolvableMethod.on(TestController.class).mockCall(o -> o.singleArg(null)).method();
Mono<HandlerResult> mono = invoke(new TestController(), method);
try {
mono.block();
@@ -175,8 +135,9 @@ public class InvocableHandlerMethodTests {
@Test
public void illegalArgumentException() {
this.resolvers.add(stubResolver(1));
Method method = ResolvableMethod.on(TestController.class).mockCall(o -> o.singleArg(null)).method();
Mono<HandlerResult> mono = invoke(new TestController(), method, stubResolver(1));
Mono<HandlerResult> mono = invoke(new TestController(), method);
try {
mono.block();
@@ -193,7 +154,7 @@ public class InvocableHandlerMethodTests {
}
@Test
public void invocationTargetExceptionIsUnwrapped() {
public void invocationTargetException() {
Method method = ResolvableMethod.on(TestController.class).mockCall(TestController::exceptionMethod).method();
Mono<HandlerResult> mono = invoke(new TestController(), method);
@@ -207,24 +168,77 @@ public class InvocableHandlerMethodTests {
}
@Test
public void invokeMethodWithResponseStatus() {
Method method = ResolvableMethod.on(TestController.class).annotPresent(ResponseStatus.class).resolveMethod();
public void responseStatusAnnotation() {
Method method = ResolvableMethod.on(TestController.class).mockCall(TestController::created).method();
Mono<HandlerResult> mono = invoke(new TestController(), method);
assertHandlerResultValue(mono, "created");
assertThat(this.exchange.getResponse().getStatusCode(), is(HttpStatus.CREATED));
}
@Test
public void voidMethodWithResponseArg() {
ServerHttpResponse response = this.exchange.getResponse();
this.resolvers.add(stubResolver(response));
Method method = ResolvableMethod.on(TestController.class).mockCall(c -> c.response(response)).method();
HandlerResult result = invokeForResult(new TestController(), method);
@Nullable
private HandlerResult invokeForResult(Object handler, Method method, HandlerMethodArgumentResolver... resolvers) {
return invoke(handler, method, resolvers).block(Duration.ZERO);
assertNull("Expected no result (i.e. fully handled)", result);
assertEquals("bar", this.exchange.getResponse().getHeaders().getFirst("foo"));
}
private Mono<HandlerResult> invoke(Object handler, Method method, HandlerMethodArgumentResolver... resolvers) {
@Test
public void voidMonoMethodWithResponseArg() {
ServerHttpResponse response = this.exchange.getResponse();
this.resolvers.add(stubResolver(response));
Method method = ResolvableMethod.on(TestController.class).mockCall(c -> c.responseMonoVoid(response)).method();
HandlerResult result = invokeForResult(new TestController(), method);
assertNull("Expected no result (i.e. fully handled)", result);
assertEquals("body", this.exchange.getResponse().getBodyAsString().block(Duration.ZERO));
}
@Test
public void voidMethodWithExchangeArg() {
this.resolvers.add(stubResolver(this.exchange));
Method method = ResolvableMethod.on(TestController.class).mockCall(c -> c.exchange(exchange)).method();
HandlerResult result = invokeForResult(new TestController(), method);
assertNull("Expected no result (i.e. fully handled)", result);
assertEquals("bar", this.exchange.getResponse().getHeaders().getFirst("foo"));
}
@Test
public void voidMonoMethodWithExchangeArg() {
this.resolvers.add(stubResolver(this.exchange));
Method method = ResolvableMethod.on(TestController.class).mockCall(c -> c.exchangeMonoVoid(exchange)).method();
HandlerResult result = invokeForResult(new TestController(), method);
assertNull("Expected no result (i.e. fully handled)", result);
assertEquals("body", this.exchange.getResponse().getBodyAsString().block(Duration.ZERO));
}
@Test
public void checkNotModified() {
MockServerHttpRequest request = MockServerHttpRequest.get("/").ifModifiedSince(10 * 1000 * 1000).build();
ServerWebExchange exchange = MockServerWebExchange.from(request);
this.resolvers.add(stubResolver(exchange));
Method method = ResolvableMethod.on(TestController.class).mockCall(c -> c.notModified(exchange)).method();
HandlerResult result = invokeForResult(new TestController(), method);
assertNull("Expected no result (i.e. fully handled)", result);
}
@Nullable
private HandlerResult invokeForResult(Object handler, Method method, Object... providedArgs) {
return invoke(handler, method, providedArgs).block(Duration.ofSeconds(5));
}
private Mono<HandlerResult> invoke(Object handler, Method method, Object... providedArgs) {
InvocableHandlerMethod invocable = new InvocableHandlerMethod(handler, method);
invocable.setArgumentResolvers(Arrays.asList(resolvers));
return invocable.invoke(this.exchange, new BindingContext());
invocable.setArgumentResolvers(this.resolvers);
return invocable.invoke(this.exchange, new BindingContext(), providedArgs);
}
private <T> HandlerMethodArgumentResolver stubResolver(Object stubValue) {
@@ -246,53 +260,46 @@ public class InvocableHandlerMethodTests {
}
@SuppressWarnings("unused")
@SuppressWarnings({"unused", "UnusedReturnValue", "SameParameterValue"})
static class TestController {
public String noArgs() {
return "success";
}
public String singleArg(String q) {
String singleArg(String q) {
return "success:" + q;
}
public void exceptionMethod() {
String noArgs() {
return "success";
}
void exceptionMethod() {
throw new IllegalStateException("boo");
}
@ResponseStatus(HttpStatus.CREATED)
public String responseStatus() {
String created() {
return "created";
}
}
@SuppressWarnings("unused")
static class VoidController {
@ResponseStatus(HttpStatus.BAD_REQUEST)
public void responseStatus() {
}
public void response(ServerHttpResponse response) {
void response(ServerHttpResponse response) {
response.getHeaders().add("foo", "bar");
}
public Mono<Void> responseMonoVoid(ServerHttpResponse response) {
return response.writeWith(getBody("body"));
Mono<Void> responseMonoVoid(ServerHttpResponse response) {
return Mono.delay(Duration.ofMillis(100))
.thenEmpty(Mono.defer(() -> response.writeWith(getBody("body"))));
}
public void exchange(ServerWebExchange exchange) {
void exchange(ServerWebExchange exchange) {
exchange.getResponse().getHeaders().add("foo", "bar");
}
public Mono<Void> exchangeMonoVoid(ServerWebExchange exchange) {
return exchange.getResponse().writeWith(getBody("body"));
Mono<Void> exchangeMonoVoid(ServerWebExchange exchange) {
return Mono.delay(Duration.ofMillis(100))
.thenEmpty(Mono.defer(() -> exchange.getResponse().writeWith(getBody("body"))));
}
@Nullable
public String notModified(ServerWebExchange exchange) {
String notModified(ServerWebExchange exchange) {
if (exchange.checkNotModified(Instant.ofEpochMilli(1000 * 1000))) {
return null;
}
@@ -300,12 +307,7 @@ public class InvocableHandlerMethodTests {
}
private Flux<DataBuffer> getBody(String body) {
try {
return Flux.just(new DefaultDataBufferFactory().wrap(body.getBytes("UTF-8")));
}
catch (UnsupportedEncodingException ex) {
throw new IllegalStateException(ex);
}
return Flux.just(new DefaultDataBufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8)));
}
}