|
|
|
@ -16,26 +16,40 @@ |
|
|
|
|
|
|
|
|
|
|
|
package org.springframework.web.reactive.result.method; |
|
|
|
package org.springframework.web.reactive.result.method; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import java.io.UnsupportedEncodingException; |
|
|
|
import java.lang.reflect.Method; |
|
|
|
import java.lang.reflect.Method; |
|
|
|
|
|
|
|
import java.time.Duration; |
|
|
|
|
|
|
|
import java.time.Instant; |
|
|
|
import java.util.Arrays; |
|
|
|
import java.util.Arrays; |
|
|
|
|
|
|
|
|
|
|
|
import org.junit.Test; |
|
|
|
import org.junit.Test; |
|
|
|
|
|
|
|
import reactor.core.publisher.Flux; |
|
|
|
import reactor.core.publisher.Mono; |
|
|
|
import reactor.core.publisher.Mono; |
|
|
|
import reactor.test.StepVerifier; |
|
|
|
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.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.http.server.reactive.test.MockServerHttpRequest; |
|
|
|
import org.springframework.mock.web.test.server.MockServerWebExchange; |
|
|
|
import org.springframework.mock.web.test.server.MockServerWebExchange; |
|
|
|
import org.springframework.web.bind.annotation.ResponseStatus; |
|
|
|
import org.springframework.web.bind.annotation.ResponseStatus; |
|
|
|
import org.springframework.web.reactive.BindingContext; |
|
|
|
import org.springframework.web.reactive.BindingContext; |
|
|
|
import org.springframework.web.reactive.HandlerResult; |
|
|
|
import org.springframework.web.reactive.HandlerResult; |
|
|
|
|
|
|
|
import org.springframework.web.server.ServerWebExchange; |
|
|
|
import org.springframework.web.server.UnsupportedMediaTypeStatusException; |
|
|
|
import org.springframework.web.server.UnsupportedMediaTypeStatusException; |
|
|
|
|
|
|
|
|
|
|
|
import static org.hamcrest.Matchers.*; |
|
|
|
import static org.hamcrest.Matchers.is; |
|
|
|
import static org.junit.Assert.*; |
|
|
|
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.any; |
|
|
|
import static org.mockito.Mockito.*; |
|
|
|
import static org.mockito.Mockito.mock; |
|
|
|
import static org.springframework.web.method.ResolvableMethod.*; |
|
|
|
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}. |
|
|
|
* Unit tests for {@link InvocableHandlerMethod}. |
|
|
|
@ -45,10 +59,72 @@ import static org.springframework.web.method.ResolvableMethod.*; |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class InvocableHandlerMethodTests { |
|
|
|
public class InvocableHandlerMethodTests { |
|
|
|
|
|
|
|
|
|
|
|
private final MockServerWebExchange exchange = |
|
|
|
private final MockServerWebExchange exchange = MockServerWebExchange.from(get("http://localhost:8080/path")); |
|
|
|
MockServerWebExchange.from(MockServerHttpRequest.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 |
|
|
|
@Test |
|
|
|
public void invokeMethodWithNoArguments() throws Exception { |
|
|
|
public void invokeMethodWithNoArguments() throws Exception { |
|
|
|
Method method = on(TestController.class).mockCall(TestController::noArgs).method(); |
|
|
|
Method method = on(TestController.class).mockCall(TestController::noArgs).method(); |
|
|
|
@ -146,7 +222,7 @@ public class InvocableHandlerMethodTests { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Mono<HandlerResult> invoke(Object handler, Method method) { |
|
|
|
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, |
|
|
|
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); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|