Allow HandlerFunction to return Mono<ServerResponse>
This commit makes it possible for handler functions to return asynchronous status codes and headers, by making HandlerFunction.handle return a Mono<ServerResponse> instead of a ServerResponse. As a consequence, all other types that deal with HandlerFunctions (RouterFunction, HandlerFilterFunction, etc.) had to change as well. However, when combining the above change with method references (a very typical use case), resulting signatures would have been something like: ``` public Mono<ServerResponse<Mono<Person>>> getPerson(ServerRequest request) ``` which was too ugly to consider, especially the two uses of Mono. It was considered to merge ServerResponse with the last Mono, essentialy making ServerResponse always contain a Publisher, but this had unfortunate consequences in view rendering. It was therefore decided to drop the parameterization of ServerResponse, as the only usage of the extra type information was to manipulate the response objects in a filter. Even before the above change this was suggested; it just made the change even more necessary. As a consequence, `BodyInserter` could be turned into a real `FunctionalInterface`, which resulted in changes in ClientRequest. We did, however, make HandlerFunction.handle return a `Mono<? extends ServerResponse>`, adding little complexity, but allowing for future `ServerResponse` subtypes that do expose type information, if it's needed. For instance, a RenderingResponse could expose the view name and model. Issue: SPR-14870
This commit is contained in:
@@ -17,44 +17,26 @@
|
||||
package org.springframework.web.reactive.function;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.core.codec.CharSequenceEncoder;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
||||
import org.springframework.http.CacheControl;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.BodyInserter;
|
||||
import org.springframework.http.codec.EncoderHttpMessageWriter;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
|
||||
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
|
||||
import org.springframework.web.reactive.result.view.View;
|
||||
import org.springframework.web.reactive.result.view.ViewResolver;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
||||
import org.springframework.web.server.session.MockWebSessionManager;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@@ -65,130 +47,203 @@ public class DefaultServerResponseBuilderTests {
|
||||
|
||||
@Test
|
||||
public void from() throws Exception {
|
||||
ServerResponse<Void> other = ServerResponse.ok().header("foo", "bar").build();
|
||||
ServerResponse<Void> result = ServerResponse.from(other).build();
|
||||
assertEquals(HttpStatus.OK, result.statusCode());
|
||||
assertEquals("bar", result.headers().getFirst("foo"));
|
||||
ServerResponse other = ServerResponse.ok().header("foo", "bar").build().block();
|
||||
Mono<ServerResponse> result = ServerResponse.from(other).build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> HttpStatus.OK.equals(response.statusCode()) &&
|
||||
"bar".equals(response.headers().getFirst("foo")))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void status() throws Exception {
|
||||
ServerResponse<Void> result = ServerResponse.status(HttpStatus.CREATED).build();
|
||||
assertEquals(HttpStatus.CREATED, result.statusCode());
|
||||
Mono<ServerResponse> result = ServerResponse.status(HttpStatus.CREATED).build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> HttpStatus.CREATED.equals(response.statusCode()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ok() throws Exception {
|
||||
ServerResponse<Void> result = ServerResponse.ok().build();
|
||||
assertEquals(HttpStatus.OK, result.statusCode());
|
||||
Mono<ServerResponse> result = ServerResponse.ok().build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> HttpStatus.OK.equals(response.statusCode()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void created() throws Exception {
|
||||
URI location = URI.create("http://example.com");
|
||||
ServerResponse<Void> result = ServerResponse.created(location).build();
|
||||
assertEquals(HttpStatus.CREATED, result.statusCode());
|
||||
assertEquals(location, result.headers().getLocation());
|
||||
Mono<ServerResponse> result = ServerResponse.created(location).build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> HttpStatus.CREATED.equals(response.statusCode()) &&
|
||||
location.equals(response.headers().getLocation()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void accepted() throws Exception {
|
||||
ServerResponse<Void> result = ServerResponse.accepted().build();
|
||||
assertEquals(HttpStatus.ACCEPTED, result.statusCode());
|
||||
Mono<ServerResponse> result = ServerResponse.accepted().build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> HttpStatus.ACCEPTED.equals(response.statusCode()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noContent() throws Exception {
|
||||
ServerResponse<Void> result = ServerResponse.noContent().build();
|
||||
assertEquals(HttpStatus.NO_CONTENT, result.statusCode());
|
||||
Mono<ServerResponse> result = ServerResponse.noContent().build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> HttpStatus.NO_CONTENT.equals(response.statusCode()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void badRequest() throws Exception {
|
||||
ServerResponse<Void> result = ServerResponse.badRequest().build();
|
||||
assertEquals(HttpStatus.BAD_REQUEST, result.statusCode());
|
||||
Mono<ServerResponse> result = ServerResponse.badRequest().build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> HttpStatus.BAD_REQUEST.equals(response.statusCode()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notFound() throws Exception {
|
||||
ServerResponse<Void> result = ServerResponse.notFound().build();
|
||||
assertEquals(HttpStatus.NOT_FOUND, result.statusCode());
|
||||
Mono<ServerResponse> result = ServerResponse.notFound().build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> HttpStatus.NOT_FOUND.equals(response.statusCode()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unprocessableEntity() throws Exception {
|
||||
ServerResponse<Void> result = ServerResponse.unprocessableEntity().build();
|
||||
assertEquals(HttpStatus.UNPROCESSABLE_ENTITY, result.statusCode());
|
||||
Mono<ServerResponse> result = ServerResponse.unprocessableEntity().build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> HttpStatus.UNPROCESSABLE_ENTITY.equals(response.statusCode()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allow() throws Exception {
|
||||
ServerResponse<Void> result = ServerResponse.ok().allow(HttpMethod.GET).build();
|
||||
assertEquals(Collections.singleton(HttpMethod.GET), result.headers().getAllow());
|
||||
Mono<ServerResponse> result = ServerResponse.ok().allow(HttpMethod.GET).build();
|
||||
Set<HttpMethod> expected = EnumSet.of(HttpMethod.GET);
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> expected.equals(response.headers().getAllow()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contentLength() throws Exception {
|
||||
ServerResponse<Void> result = ServerResponse.ok().contentLength(42).build();
|
||||
assertEquals(42, result.headers().getContentLength());
|
||||
Mono<ServerResponse> result = ServerResponse.ok().contentLength(42).build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> Long.valueOf(42).equals(response.headers().getContentLength()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contentType() throws Exception {
|
||||
ServerResponse<Void> result = ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).build();
|
||||
assertEquals(MediaType.APPLICATION_JSON, result.headers().getContentType());
|
||||
Mono<ServerResponse>
|
||||
result = ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> MediaType.APPLICATION_JSON.equals(response.headers().getContentType()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void eTag() throws Exception {
|
||||
ServerResponse<Void> result = ServerResponse.ok().eTag("foo").build();
|
||||
assertEquals("\"foo\"", result.headers().getETag());
|
||||
Mono<ServerResponse> result = ServerResponse.ok().eTag("foo").build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> "\"foo\"".equals(response.headers().getETag()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lastModified() throws Exception {
|
||||
ZonedDateTime now = ZonedDateTime.now();
|
||||
ServerResponse<Void> result = ServerResponse.ok().lastModified(now).build();
|
||||
assertEquals(now.toInstant().toEpochMilli()/1000, result.headers().getLastModified()/1000);
|
||||
Mono<ServerResponse> result = ServerResponse.ok().lastModified(now).build();
|
||||
Long expected = now.toInstant().toEpochMilli() / 1000;
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> expected.equals(response.headers().getLastModified() / 1000))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheControlTag() throws Exception {
|
||||
ServerResponse<Void> result = ServerResponse.ok().cacheControl(CacheControl.noCache()).build();
|
||||
assertEquals("no-cache", result.headers().getCacheControl());
|
||||
Mono<ServerResponse>
|
||||
result = ServerResponse.ok().cacheControl(CacheControl.noCache()).build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> "no-cache".equals(response.headers().getCacheControl()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void varyBy() throws Exception {
|
||||
ServerResponse<Void> result = ServerResponse.ok().varyBy("foo").build();
|
||||
assertEquals(Collections.singletonList("foo"), result.headers().getVary());
|
||||
Mono<ServerResponse> result = ServerResponse.ok().varyBy("foo").build();
|
||||
List<String> expected = Collections.singletonList("foo");
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> expected.equals(response.headers().getVary()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void statusCode() throws Exception {
|
||||
HttpStatus statusCode = HttpStatus.ACCEPTED;
|
||||
ServerResponse<Void> result = ServerResponse.status(statusCode).build();
|
||||
assertSame(statusCode, result.statusCode());
|
||||
Mono<ServerResponse> result = ServerResponse.status(statusCode).build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> statusCode.equals(response.statusCode()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headers() throws Exception {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
ServerResponse<Void> result = ServerResponse.ok().headers(headers).build();
|
||||
assertEquals(headers, result.headers());
|
||||
Mono<ServerResponse> result = ServerResponse.ok().headers(headers).build();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(response -> headers.equals(response.headers()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void build() throws Exception {
|
||||
ServerResponse<Void> result = ServerResponse.status(HttpStatus.CREATED).header("MyKey", "MyValue").build();
|
||||
Mono<ServerResponse>
|
||||
result = ServerResponse.status(HttpStatus.CREATED).header("MyKey", "MyValue").build();
|
||||
|
||||
ServerWebExchange exchange = mock(ServerWebExchange.class);
|
||||
MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
when(exchange.getResponse()).thenReturn(response);
|
||||
HandlerStrategies strategies = mock(HandlerStrategies.class);
|
||||
|
||||
result.writeTo(exchange, strategies).block();
|
||||
assertEquals(201, response.getStatusCode().value());
|
||||
result.then(res -> res.writeTo(exchange, strategies)).block();
|
||||
|
||||
assertEquals(HttpStatus.CREATED, response.getStatusCode());
|
||||
assertEquals("MyValue", response.getHeaders().getFirst("MyKey"));
|
||||
assertNull(response.getBody());
|
||||
|
||||
@@ -197,21 +252,25 @@ public class DefaultServerResponseBuilderTests {
|
||||
@Test
|
||||
public void buildVoidPublisher() throws Exception {
|
||||
Mono<Void> mono = Mono.empty();
|
||||
ServerResponse<Mono<Void>> result = ServerResponse.ok().build(mono);
|
||||
Mono<ServerResponse> result = ServerResponse.ok().build(mono);
|
||||
|
||||
ServerWebExchange exchange = mock(ServerWebExchange.class);
|
||||
MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
when(exchange.getResponse()).thenReturn(response);
|
||||
HandlerStrategies strategies = mock(HandlerStrategies.class);
|
||||
|
||||
result.writeTo(exchange, strategies).block();
|
||||
result.then(res -> res.writeTo(exchange, strategies)).block();
|
||||
|
||||
assertNull(response.getBody());
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: enable when ServerEntityResponse is reintroduced
|
||||
|
||||
@Test
|
||||
public void bodyInserter() throws Exception {
|
||||
String body = "foo";
|
||||
Supplier<String> supplier = () -> body;
|
||||
Publisher<String> publisher = Mono.just(body);
|
||||
BiFunction<ServerHttpResponse, BodyInserter.Context, Mono<Void>> writer =
|
||||
(response, strategies) -> {
|
||||
byte[] bodyBytes = body.getBytes(UTF_8);
|
||||
@@ -221,14 +280,13 @@ public class DefaultServerResponseBuilderTests {
|
||||
return response.writeWith(Mono.just(buffer));
|
||||
};
|
||||
|
||||
ServerResponse<String> result = ServerResponse.ok().body(BodyInserter.of(writer, supplier));
|
||||
assertEquals(body, result.body());
|
||||
Mono<ServerResponse> result = ServerResponse.ok().body(BodyInserter.of(writer, publisher));
|
||||
|
||||
MockServerHttpRequest request =
|
||||
new MockServerHttpRequest(HttpMethod.GET, "http://localhost");
|
||||
MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
MockServerHttpResponse mockResponse = new MockServerHttpResponse();
|
||||
ServerWebExchange exchange =
|
||||
new DefaultServerWebExchange(request, response, new MockWebSessionManager());
|
||||
new DefaultServerWebExchange(request, mockResponse, new MockWebSessionManager());
|
||||
|
||||
List<HttpMessageWriter<?>> messageWriters = new ArrayList<>();
|
||||
messageWriters.add(new EncoderHttpMessageWriter<CharSequence>(new CharSequenceEncoder()));
|
||||
@@ -236,21 +294,32 @@ public class DefaultServerResponseBuilderTests {
|
||||
HandlerStrategies strategies = mock(HandlerStrategies.class);
|
||||
when(strategies.messageWriters()).thenReturn(messageWriters::stream);
|
||||
|
||||
result.writeTo(exchange, strategies).block();
|
||||
assertNotNull(response.getBody());
|
||||
}
|
||||
StepVerifier.create(result)
|
||||
.consumeNextWith(response -> {
|
||||
StepVerifier.create(response.body())
|
||||
.expectNext(body)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
response.writeTo(exchange, strategies);
|
||||
})
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
assertNotNull(mockResponse.getBody());
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
TODO: enable when ServerEntityResponse is reintroduced
|
||||
@Test
|
||||
public void render() throws Exception {
|
||||
Map<String, Object> model = Collections.singletonMap("foo", "bar");
|
||||
ServerResponse<Rendering> result = ServerResponse.ok().render("view", model);
|
||||
Mono<ServerResponse> result = ServerResponse.ok().render("view", model);
|
||||
|
||||
assertEquals("view", result.body().name());
|
||||
assertEquals(model, result.body().model());
|
||||
|
||||
MockServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, URI.create("http://localhost"));
|
||||
MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
ServerWebExchange exchange = new DefaultServerWebExchange(request, response, new MockWebSessionManager());
|
||||
MockServerHttpResponse mockResponse = new MockServerHttpResponse();
|
||||
ServerWebExchange exchange = new DefaultServerWebExchange(request, mockResponse, new MockWebSessionManager());
|
||||
ViewResolver viewResolver = mock(ViewResolver.class);
|
||||
View view = mock(View.class);
|
||||
when(viewResolver.resolveViewName("view", Locale.ENGLISH)).thenReturn(Mono.just(view));
|
||||
@@ -262,17 +331,37 @@ public class DefaultServerResponseBuilderTests {
|
||||
HandlerStrategies mockConfig = mock(HandlerStrategies.class);
|
||||
when(mockConfig.viewResolvers()).thenReturn(viewResolvers::stream);
|
||||
|
||||
result.writeTo(exchange, mockConfig).block();
|
||||
StepVerifier.create(result)
|
||||
.consumeNextWith(response -> {
|
||||
StepVerifier.create(response.body())
|
||||
.expectNextMatches(rendering -> "view".equals(rendering.name())
|
||||
&& model.equals(rendering.model()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
})
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
TODO: enable when ServerEntityResponse is reintroduced
|
||||
|
||||
@Test
|
||||
public void renderObjectArray() throws Exception {
|
||||
ServerResponse<Rendering> result =
|
||||
Mono<ServerResponse> result =
|
||||
ServerResponse.ok().render("name", this, Collections.emptyList(), "foo");
|
||||
Map<String, Object> model = result.body().model();
|
||||
assertEquals(2, model.size());
|
||||
assertEquals(this, model.get("defaultServerResponseBuilderTests"));
|
||||
assertEquals("foo", model.get("string"));
|
||||
Flux<Rendering> map = result.flatMap(ServerResponse::body);
|
||||
|
||||
Map<String, Object> expected = new HashMap<>(2);
|
||||
expected.put("defaultServerResponseBuilderTests", this);
|
||||
expected.put("string", "foo");
|
||||
|
||||
StepVerifier.create(map)
|
||||
.expectNextMatches(rendering -> expected.equals(rendering.model()))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
@@ -16,14 +16,12 @@
|
||||
|
||||
package org.springframework.web.reactive.function;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -50,6 +48,7 @@ import org.springframework.web.reactive.result.view.ViewResolver;
|
||||
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.springframework.http.codec.BodyInserters.fromObject;
|
||||
import static org.springframework.http.codec.BodyInserters.fromPublisher;
|
||||
import static org.springframework.web.reactive.function.RouterFunctions.route;
|
||||
|
||||
@@ -84,7 +83,7 @@ public class DispatcherHandlerIntegrationTests extends AbstractHttpHandlerIntegr
|
||||
@Test
|
||||
public void mono() throws Exception {
|
||||
ResponseEntity<Person> result =
|
||||
restTemplate.getForEntity("http://localhost:" + port + "/mono", Person.class);
|
||||
this.restTemplate.getForEntity("http://localhost:" + this.port + "/mono", Person.class);
|
||||
|
||||
assertEquals(HttpStatus.OK, result.getStatusCode());
|
||||
assertEquals("John", result.getBody().getName());
|
||||
@@ -94,7 +93,8 @@ public class DispatcherHandlerIntegrationTests extends AbstractHttpHandlerIntegr
|
||||
public void flux() throws Exception {
|
||||
ParameterizedTypeReference<List<Person>> reference = new ParameterizedTypeReference<List<Person>>() {};
|
||||
ResponseEntity<List<Person>> result =
|
||||
restTemplate.exchange("http://localhost:" + port + "/flux", HttpMethod.GET, null, reference);
|
||||
this.restTemplate
|
||||
.exchange("http://localhost:" + this.port + "/flux", HttpMethod.GET, null, reference);
|
||||
|
||||
assertEquals(HttpStatus.OK, result.getStatusCode());
|
||||
List<Person> body = result.getBody();
|
||||
@@ -134,7 +134,7 @@ public class DispatcherHandlerIntegrationTests extends AbstractHttpHandlerIntegr
|
||||
|
||||
@Override
|
||||
public Supplier<Stream<ViewResolver>> viewResolvers() {
|
||||
return () -> Collections.<ViewResolver>emptySet().stream();
|
||||
return Stream::empty;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -154,18 +154,22 @@ public class DispatcherHandlerIntegrationTests extends AbstractHttpHandlerIntegr
|
||||
|
||||
private static class PersonHandler {
|
||||
|
||||
public ServerResponse<Publisher<Person>> mono(ServerRequest request) {
|
||||
public Mono<ServerResponse> mono(ServerRequest request) {
|
||||
Person person = new Person("John");
|
||||
return ServerResponse.ok().body(fromPublisher(Mono.just(person), Person.class));
|
||||
return ServerResponse.ok().body(fromObject(person));
|
||||
}
|
||||
|
||||
public ServerResponse<Publisher<Person>> flux(ServerRequest request) {
|
||||
public Mono<ServerResponse> flux(ServerRequest request) {
|
||||
Person person1 = new Person("John");
|
||||
Person person2 = new Person("Jane");
|
||||
return ServerResponse.ok().body(
|
||||
fromPublisher(Flux.just(person1, person2), Person.class));
|
||||
}
|
||||
|
||||
public Mono<ServerResponse> view() {
|
||||
return ServerResponse.ok().render("foo", "bar");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class Person {
|
||||
@@ -181,7 +185,7 @@ public class DispatcherHandlerIntegrationTests extends AbstractHttpHandlerIntegr
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
@@ -209,7 +213,7 @@ public class DispatcherHandlerIntegrationTests extends AbstractHttpHandlerIntegr
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Person{" +
|
||||
"name='" + name + '\'' +
|
||||
"name='" + this.name + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ import org.springframework.util.MultiValueMap;
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class MockServerRequest<T> implements ServerRequest {
|
||||
public class MockServerRequest implements ServerRequest {
|
||||
|
||||
private final HttpMethod method;
|
||||
|
||||
@@ -53,7 +53,7 @@ public class MockServerRequest<T> implements ServerRequest {
|
||||
|
||||
private final MockHeaders headers;
|
||||
|
||||
private final T body;
|
||||
private final Object body;
|
||||
|
||||
private final Map<String, Object> attributes;
|
||||
|
||||
@@ -62,7 +62,7 @@ public class MockServerRequest<T> implements ServerRequest {
|
||||
private final Map<String, String> pathVariables;
|
||||
|
||||
private MockServerRequest(HttpMethod method, URI uri,
|
||||
MockHeaders headers, T body, Map<String, Object> attributes,
|
||||
MockHeaders headers, Object body, Map<String, Object> attributes,
|
||||
MultiValueMap<String, String> queryParams,
|
||||
Map<String, String> pathVariables) {
|
||||
this.method = method;
|
||||
@@ -74,8 +74,8 @@ public class MockServerRequest<T> implements ServerRequest {
|
||||
this.pathVariables = pathVariables;
|
||||
}
|
||||
|
||||
public static <T> Builder<T> builder() {
|
||||
return new BuilderImpl<T>();
|
||||
public static Builder builder() {
|
||||
return new BuilderImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -127,35 +127,35 @@ public class MockServerRequest<T> implements ServerRequest {
|
||||
return Collections.unmodifiableMap(this.pathVariables);
|
||||
}
|
||||
|
||||
public interface Builder<T> {
|
||||
public interface Builder {
|
||||
|
||||
Builder<T> method(HttpMethod method);
|
||||
Builder method(HttpMethod method);
|
||||
|
||||
Builder<T> uri(URI uri);
|
||||
Builder uri(URI uri);
|
||||
|
||||
Builder<T> header(String key, String value);
|
||||
Builder header(String key, String value);
|
||||
|
||||
Builder<T> headers(HttpHeaders headers);
|
||||
Builder headers(HttpHeaders headers);
|
||||
|
||||
Builder<T> attribute(String name, Object value);
|
||||
Builder attribute(String name, Object value);
|
||||
|
||||
Builder<T> attributes(Map<String, Object> attributes);
|
||||
Builder attributes(Map<String, Object> attributes);
|
||||
|
||||
Builder<T> queryParam(String key, String value);
|
||||
Builder queryParam(String key, String value);
|
||||
|
||||
Builder<T> queryParams(MultiValueMap<String, String> queryParams);
|
||||
Builder queryParams(MultiValueMap<String, String> queryParams);
|
||||
|
||||
Builder<T> pathVariable(String key, String value);
|
||||
Builder pathVariable(String key, String value);
|
||||
|
||||
Builder<T> pathVariables(Map<String, String> pathVariables);
|
||||
Builder pathVariables(Map<String, String> pathVariables);
|
||||
|
||||
MockServerRequest<T> body(T body);
|
||||
MockServerRequest body(Object body);
|
||||
|
||||
MockServerRequest<Void> build();
|
||||
MockServerRequest build();
|
||||
|
||||
}
|
||||
|
||||
private static class BuilderImpl<T> implements Builder<T> {
|
||||
private static class BuilderImpl implements Builder {
|
||||
|
||||
private HttpMethod method = HttpMethod.GET;
|
||||
|
||||
@@ -163,7 +163,7 @@ public class MockServerRequest<T> implements ServerRequest {
|
||||
|
||||
private MockHeaders headers = new MockHeaders(new HttpHeaders());
|
||||
|
||||
private T body;
|
||||
private Object body;
|
||||
|
||||
private Map<String, Object> attributes = new LinkedHashMap<>();
|
||||
|
||||
@@ -172,21 +172,21 @@ public class MockServerRequest<T> implements ServerRequest {
|
||||
private Map<String, String> pathVariables = new LinkedHashMap<>();
|
||||
|
||||
@Override
|
||||
public Builder<T> method(HttpMethod method) {
|
||||
public Builder method(HttpMethod method) {
|
||||
Assert.notNull(method, "'method' must not be null");
|
||||
this.method = method;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> uri(URI uri) {
|
||||
public Builder uri(URI uri) {
|
||||
Assert.notNull(uri, "'uri' must not be null");
|
||||
this.uri = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> header(String key, String value) {
|
||||
public Builder header(String key, String value) {
|
||||
Assert.notNull(key, "'key' must not be null");
|
||||
Assert.notNull(value, "'value' must not be null");
|
||||
this.headers.header(key, value);
|
||||
@@ -194,14 +194,14 @@ public class MockServerRequest<T> implements ServerRequest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> headers(HttpHeaders headers) {
|
||||
public Builder headers(HttpHeaders headers) {
|
||||
Assert.notNull(headers, "'headers' must not be null");
|
||||
this.headers = new MockHeaders(headers);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> attribute(String name, Object value) {
|
||||
public Builder attribute(String name, Object value) {
|
||||
Assert.notNull(name, "'name' must not be null");
|
||||
Assert.notNull(value, "'value' must not be null");
|
||||
this.attributes.put(name, value);
|
||||
@@ -209,14 +209,14 @@ public class MockServerRequest<T> implements ServerRequest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> attributes(Map<String, Object> attributes) {
|
||||
public Builder attributes(Map<String, Object> attributes) {
|
||||
Assert.notNull(attributes, "'attributes' must not be null");
|
||||
this.attributes = attributes;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> queryParam(String key, String value) {
|
||||
public Builder queryParam(String key, String value) {
|
||||
Assert.notNull(key, "'key' must not be null");
|
||||
Assert.notNull(value, "'value' must not be null");
|
||||
this.queryParams.add(key, value);
|
||||
@@ -224,14 +224,14 @@ public class MockServerRequest<T> implements ServerRequest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> queryParams(MultiValueMap<String, String> queryParams) {
|
||||
public Builder queryParams(MultiValueMap<String, String> queryParams) {
|
||||
Assert.notNull(queryParams, "'queryParams' must not be null");
|
||||
this.queryParams = queryParams;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> pathVariable(String key, String value) {
|
||||
public Builder pathVariable(String key, String value) {
|
||||
Assert.notNull(key, "'key' must not be null");
|
||||
Assert.notNull(value, "'value' must not be null");
|
||||
this.pathVariables.put(key, value);
|
||||
@@ -239,22 +239,22 @@ public class MockServerRequest<T> implements ServerRequest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder<T> pathVariables(Map<String, String> pathVariables) {
|
||||
public Builder pathVariables(Map<String, String> pathVariables) {
|
||||
Assert.notNull(pathVariables, "'pathVariables' must not be null");
|
||||
this.pathVariables = pathVariables;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockServerRequest<T> body(T body) {
|
||||
public MockServerRequest body(Object body) {
|
||||
this.body = body;
|
||||
return new MockServerRequest<T>(this.method, this.uri, this.headers, this.body,
|
||||
return new MockServerRequest(this.method, this.uri, this.headers, this.body,
|
||||
this.attributes, this.queryParams, this.pathVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MockServerRequest<Void> build() {
|
||||
return new MockServerRequest<Void>(this.method, this.uri, this.headers, null,
|
||||
public MockServerRequest build() {
|
||||
return new MockServerRequest(this.method, this.uri, this.headers, null,
|
||||
this.attributes, this.queryParams, this.pathVariables);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,18 +16,17 @@
|
||||
|
||||
package org.springframework.web.reactive.function;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
@@ -38,14 +37,23 @@ public class PathResourceLookupFunctionTests {
|
||||
ClassPathResource location = new ClassPathResource("org/springframework/web/reactive/function/");
|
||||
|
||||
PathResourceLookupFunction function = new PathResourceLookupFunction("/resources/**", location);
|
||||
MockServerRequest<Void> request = MockServerRequest.builder()
|
||||
MockServerRequest request = MockServerRequest.builder()
|
||||
.uri(new URI("http://localhost/resources/response.txt"))
|
||||
.build();
|
||||
Optional<Resource> result = function.apply(request);
|
||||
assertTrue(result.isPresent());
|
||||
Mono<Resource> result = function.apply(request);
|
||||
|
||||
ClassPathResource expected = new ClassPathResource("response.txt", getClass());
|
||||
assertEquals(expected.getFile(), result.get().getFile());
|
||||
File expected = new ClassPathResource("response.txt", getClass()).getFile();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(resource -> {
|
||||
try {
|
||||
return expected.equals(resource.getFile());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -53,14 +61,22 @@ public class PathResourceLookupFunctionTests {
|
||||
ClassPathResource location = new ClassPathResource("org/springframework/web/reactive/function/");
|
||||
|
||||
PathResourceLookupFunction function = new PathResourceLookupFunction("/resources/**", location);
|
||||
MockServerRequest<Void> request = MockServerRequest.builder()
|
||||
MockServerRequest request = MockServerRequest.builder()
|
||||
.uri(new URI("http://localhost/resources/child/response.txt"))
|
||||
.build();
|
||||
Optional<Resource> result = function.apply(request);
|
||||
assertTrue(result.isPresent());
|
||||
|
||||
ClassPathResource expected = new ClassPathResource("org/springframework/web/reactive/function/child/response.txt");
|
||||
assertEquals(expected.getFile(), result.get().getFile());
|
||||
Mono<Resource> result = function.apply(request);
|
||||
File expected = new ClassPathResource("org/springframework/web/reactive/function/child/response.txt").getFile();
|
||||
StepVerifier.create(result)
|
||||
.expectNextMatches(resource -> {
|
||||
try {
|
||||
return expected.equals(resource.getFile());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -68,11 +84,13 @@ public class PathResourceLookupFunctionTests {
|
||||
ClassPathResource location = new ClassPathResource("org/springframework/web/reactive/function/");
|
||||
|
||||
PathResourceLookupFunction function = new PathResourceLookupFunction("/resources/**", location);
|
||||
MockServerRequest<Void> request = MockServerRequest.builder()
|
||||
MockServerRequest request = MockServerRequest.builder()
|
||||
.uri(new URI("http://localhost/resources/foo"))
|
||||
.build();
|
||||
Optional<Resource> result = function.apply(request);
|
||||
assertFalse(result.isPresent());
|
||||
Mono<Resource> result = function.apply(request);
|
||||
StepVerifier.create(result)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,7 +21,6 @@ import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
@@ -97,17 +96,17 @@ public class PublisherHandlerFunctionIntegrationTests
|
||||
|
||||
private static class PersonHandler {
|
||||
|
||||
public ServerResponse<Publisher<Person>> mono(ServerRequest request) {
|
||||
public Mono<ServerResponse> mono(ServerRequest request) {
|
||||
Person person = new Person("John");
|
||||
return ServerResponse.ok().body(fromPublisher(Mono.just(person), Person.class));
|
||||
}
|
||||
|
||||
public ServerResponse<Publisher<Person>> postMono(ServerRequest request) {
|
||||
public Mono<ServerResponse> postMono(ServerRequest request) {
|
||||
Mono<Person> personMono = request.body(toMono(Person.class));
|
||||
return ServerResponse.ok().body(fromPublisher(personMono, Person.class));
|
||||
}
|
||||
|
||||
public ServerResponse<Publisher<Person>> flux(ServerRequest request) {
|
||||
public Mono<ServerResponse> flux(ServerRequest request) {
|
||||
Person person1 = new Person("John");
|
||||
Person person2 = new Person("Jane");
|
||||
return ServerResponse.ok().body(
|
||||
|
||||
@@ -57,18 +57,24 @@ public class ResourceHandlerFunctionTests {
|
||||
|
||||
ServerRequest request = new DefaultServerRequest(exchange, HandlerStrategies.withDefaults());
|
||||
|
||||
ServerResponse<Resource> response = this.handlerFunction.handle(request);
|
||||
assertEquals(HttpStatus.OK, response.statusCode());
|
||||
assertEquals(this.resource, response.body());
|
||||
Mono<ServerResponse> responseMono = this.handlerFunction.handle(request);
|
||||
|
||||
Mono<Void> result = response.writeTo(exchange, HandlerStrategies.withDefaults());
|
||||
Mono<Void> result = responseMono.then(response -> {
|
||||
assertEquals(HttpStatus.OK, response.statusCode());
|
||||
/*
|
||||
TODO: enable when ServerEntityResponse is reintroduced
|
||||
StepVerifier.create(response.body())
|
||||
.expectNext(this.resource)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
*/
|
||||
return response.writeTo(exchange, HandlerStrategies.withDefaults());
|
||||
});
|
||||
|
||||
StepVerifier.create(result)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
StepVerifier.create(result).expectComplete().verify();
|
||||
|
||||
byte[] expectedBytes = Files.readAllBytes(this.resource.getFile().toPath());
|
||||
|
||||
StepVerifier.create(mockResponse.getBody())
|
||||
@@ -93,10 +99,12 @@ public class ResourceHandlerFunctionTests {
|
||||
|
||||
ServerRequest request = new DefaultServerRequest(exchange, HandlerStrategies.withDefaults());
|
||||
|
||||
ServerResponse<Resource> response = this.handlerFunction.handle(request);
|
||||
assertEquals(HttpStatus.OK, response.statusCode());
|
||||
Mono<ServerResponse> response = this.handlerFunction.handle(request);
|
||||
|
||||
Mono<Void> result = response.writeTo(exchange, HandlerStrategies.withDefaults());
|
||||
Mono<Void> result = response.then(res -> {
|
||||
assertEquals(HttpStatus.OK, res.statusCode());
|
||||
return res.writeTo(exchange, HandlerStrategies.withDefaults());
|
||||
});
|
||||
|
||||
StepVerifier.create(result)
|
||||
.expectComplete()
|
||||
@@ -121,14 +129,20 @@ public class ResourceHandlerFunctionTests {
|
||||
|
||||
ServerRequest request = new DefaultServerRequest(exchange, HandlerStrategies.withDefaults());
|
||||
|
||||
ServerResponse<Resource> response = this.handlerFunction.handle(request);
|
||||
Mono<ServerResponse> responseMono = this.handlerFunction.handle(request);
|
||||
Mono<Void> result = responseMono.then(response -> {
|
||||
assertEquals(HttpStatus.OK, response.statusCode());
|
||||
assertEquals(EnumSet.of(HttpMethod.GET, HttpMethod.HEAD, HttpMethod.OPTIONS),
|
||||
response.headers().getAllow());
|
||||
/*
|
||||
TODO: enable when ServerEntityResponse is reintroduced
|
||||
StepVerifier.create(response.body())
|
||||
.expectComplete()
|
||||
.verify();
|
||||
*/
|
||||
return response.writeTo(exchange, HandlerStrategies.withDefaults());
|
||||
});
|
||||
|
||||
assertEquals(HttpStatus.OK, response.statusCode());
|
||||
assertEquals(EnumSet.of(HttpMethod.GET, HttpMethod.HEAD, HttpMethod.OPTIONS),
|
||||
response.headers().getAllow());
|
||||
assertNull(response.body());
|
||||
|
||||
Mono<Void> result = response.writeTo(exchange, HandlerStrategies.withDefaults());
|
||||
|
||||
StepVerifier.create(result)
|
||||
.expectComplete()
|
||||
|
||||
@@ -16,13 +16,11 @@
|
||||
|
||||
package org.springframework.web.reactive.function;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.springframework.http.codec.BodyInserters.fromObject;
|
||||
|
||||
/**
|
||||
@@ -33,69 +31,96 @@ public class RouterFunctionTests {
|
||||
|
||||
@Test
|
||||
public void andSame() throws Exception {
|
||||
HandlerFunction<Void> handlerFunction = request -> ServerResponse.ok().build();
|
||||
RouterFunction<Void> routerFunction1 = request -> Optional.empty();
|
||||
RouterFunction<Void> routerFunction2 = request -> Optional.of(handlerFunction);
|
||||
HandlerFunction<ServerResponse> handlerFunction = request -> ServerResponse.ok().build();
|
||||
RouterFunction<ServerResponse> routerFunction1 = request -> Mono.empty();
|
||||
RouterFunction<ServerResponse> routerFunction2 = request -> Mono.just(handlerFunction);
|
||||
|
||||
RouterFunction<Void> result = routerFunction1.andSame(routerFunction2);
|
||||
RouterFunction<ServerResponse> result = routerFunction1.andSame(routerFunction2);
|
||||
assertNotNull(result);
|
||||
|
||||
MockServerRequest request = MockServerRequest.builder().build();
|
||||
Optional<HandlerFunction<Void>> resultHandlerFunction = result.route(request);
|
||||
assertTrue(resultHandlerFunction.isPresent());
|
||||
assertEquals(handlerFunction, resultHandlerFunction.get());
|
||||
Mono<HandlerFunction<ServerResponse>> resultHandlerFunction = result.route(request);
|
||||
|
||||
StepVerifier.create(resultHandlerFunction)
|
||||
.expectNext(handlerFunction)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void and() throws Exception {
|
||||
HandlerFunction<String> handlerFunction = request -> ServerResponse.ok().body(fromObject("42"));
|
||||
RouterFunction<Void> routerFunction1 = request -> Optional.empty();
|
||||
RouterFunction<String> routerFunction2 = request -> Optional.of(handlerFunction);
|
||||
HandlerFunction<ServerResponse> handlerFunction =
|
||||
request -> ServerResponse.ok().body(fromObject("42"));
|
||||
RouterFunction<?> routerFunction1 = request -> Mono.empty();
|
||||
RouterFunction<ServerResponse> routerFunction2 =
|
||||
request -> Mono.just(handlerFunction);
|
||||
|
||||
RouterFunction<?> result = routerFunction1.and(routerFunction2);
|
||||
assertNotNull(result);
|
||||
|
||||
MockServerRequest request = MockServerRequest.builder().build();
|
||||
Optional<? extends HandlerFunction<?>> resultHandlerFunction = result.route(request);
|
||||
assertTrue(resultHandlerFunction.isPresent());
|
||||
assertEquals(handlerFunction, resultHandlerFunction.get());
|
||||
Mono<? extends HandlerFunction<?>> resultHandlerFunction = result.route(request);
|
||||
|
||||
StepVerifier.create(resultHandlerFunction)
|
||||
.expectNextMatches(o -> o.equals(handlerFunction))
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void andRoute() throws Exception {
|
||||
RouterFunction<Integer> routerFunction1 = request -> Optional.empty();
|
||||
RouterFunction<?> routerFunction1 = request -> Mono.empty();
|
||||
RequestPredicate requestPredicate = request -> true;
|
||||
|
||||
RouterFunction<?> result = routerFunction1.andRoute(requestPredicate, this::handlerMethod);
|
||||
assertNotNull(result);
|
||||
|
||||
MockServerRequest request = MockServerRequest.builder().build();
|
||||
Optional<? extends HandlerFunction<?>> resultHandlerFunction = result.route(request);
|
||||
assertTrue(resultHandlerFunction.isPresent());
|
||||
Mono<? extends HandlerFunction<?>> resultHandlerFunction = result.route(request);
|
||||
|
||||
StepVerifier.create(resultHandlerFunction)
|
||||
.expectNextCount(1)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
private ServerResponse<String> handlerMethod(ServerRequest request) {
|
||||
private Mono<ServerResponse> handlerMethod(ServerRequest request) {
|
||||
return ServerResponse.ok().body(fromObject("42"));
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: enable when ServerEntityResponse is reintroduced
|
||||
|
||||
@Test
|
||||
public void filter() throws Exception {
|
||||
HandlerFunction<String> handlerFunction = request -> ServerResponse.ok().body(fromObject("42"));
|
||||
RouterFunction<String> routerFunction = request -> Optional.of(handlerFunction);
|
||||
HandlerFunction<ServerResponse> handlerFunction = request -> ServerResponse.ok().body(fromObject("42"));
|
||||
RouterFunction<ServerResponse> routerFunction = request -> Mono.just(handlerFunction);
|
||||
|
||||
HandlerFilterFunction<String, Integer> filterFunction = (request, next) -> {
|
||||
ServerResponse<String> response = next.handle(request);
|
||||
int i = Integer.parseInt(response.body());
|
||||
return ServerResponse.ok().body(fromObject(i));
|
||||
};
|
||||
HandlerFilterFunction<String, Integer> filterFunction =
|
||||
(request, next) -> next.handle(request).then(
|
||||
response -> {
|
||||
Flux<Integer> body = Flux.from(response.body())
|
||||
.map(Integer::parseInt);
|
||||
return ServerResponse.ok().body(body, Integer.class);
|
||||
});
|
||||
RouterFunction<Integer> result = routerFunction.filter(filterFunction);
|
||||
assertNotNull(result);
|
||||
|
||||
MockServerRequest request = MockServerRequest.builder().build();
|
||||
Optional<? extends HandlerFunction<?>> resultHandlerFunction = result.route(request);
|
||||
assertTrue(resultHandlerFunction.isPresent());
|
||||
ServerResponse<?> resultResponse = resultHandlerFunction.get().handle(request);
|
||||
assertEquals(42, resultResponse.body());
|
||||
Mono<? extends ServerResponse<Integer>> responseMono =
|
||||
result.route(request).then(hf -> hf.handle(request));
|
||||
|
||||
StepVerifier.create(responseMono)
|
||||
.consumeNextWith(
|
||||
serverResponse -> {
|
||||
StepVerifier.create(serverResponse.body())
|
||||
.expectNext(42)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
})
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
package org.springframework.web.reactive.function;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
@@ -31,8 +31,11 @@ import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse
|
||||
import org.springframework.web.reactive.result.view.ViewResolver;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
@@ -42,87 +45,97 @@ public class RouterFunctionsTests {
|
||||
|
||||
@Test
|
||||
public void routeMatch() throws Exception {
|
||||
HandlerFunction<Void> handlerFunction = request -> ServerResponse.ok().build();
|
||||
HandlerFunction<ServerResponse> handlerFunction = request -> ServerResponse.ok().build();
|
||||
|
||||
MockServerRequest request = MockServerRequest.builder().build();
|
||||
RequestPredicate requestPredicate = mock(RequestPredicate.class);
|
||||
when(requestPredicate.test(request)).thenReturn(true);
|
||||
|
||||
RouterFunction<Void> result = RouterFunctions.route(requestPredicate, handlerFunction);
|
||||
RouterFunction<ServerResponse> result = RouterFunctions.route(requestPredicate, handlerFunction);
|
||||
assertNotNull(result);
|
||||
|
||||
Optional<HandlerFunction<Void>> resultHandlerFunction = result.route(request);
|
||||
assertTrue(resultHandlerFunction.isPresent());
|
||||
assertEquals(handlerFunction, resultHandlerFunction.get());
|
||||
Mono<HandlerFunction<ServerResponse>> resultHandlerFunction = result.route(request);
|
||||
|
||||
StepVerifier.create(resultHandlerFunction)
|
||||
.expectNext(handlerFunction)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void routeNoMatch() throws Exception {
|
||||
HandlerFunction<Void> handlerFunction = request -> ServerResponse.ok().build();
|
||||
HandlerFunction<ServerResponse> handlerFunction = request -> ServerResponse.ok().build();
|
||||
|
||||
MockServerRequest request = MockServerRequest.builder().build();
|
||||
RequestPredicate requestPredicate = mock(RequestPredicate.class);
|
||||
when(requestPredicate.test(request)).thenReturn(false);
|
||||
|
||||
RouterFunction<Void> result = RouterFunctions.route(requestPredicate, handlerFunction);
|
||||
RouterFunction<ServerResponse> result = RouterFunctions.route(requestPredicate, handlerFunction);
|
||||
assertNotNull(result);
|
||||
|
||||
Optional<HandlerFunction<Void>> resultHandlerFunction = result.route(request);
|
||||
assertFalse(resultHandlerFunction.isPresent());
|
||||
Mono<HandlerFunction<ServerResponse>> resultHandlerFunction = result.route(request);
|
||||
StepVerifier.create(resultHandlerFunction)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subrouteMatch() throws Exception {
|
||||
HandlerFunction<Void> handlerFunction = request -> ServerResponse.ok().build();
|
||||
RouterFunction<Void> routerFunction = request -> Optional.of(handlerFunction);
|
||||
HandlerFunction<ServerResponse> handlerFunction = request -> ServerResponse.ok().build();
|
||||
RouterFunction<ServerResponse> routerFunction = request -> Mono.just(handlerFunction);
|
||||
|
||||
MockServerRequest request = MockServerRequest.builder().build();
|
||||
RequestPredicate requestPredicate = mock(RequestPredicate.class);
|
||||
when(requestPredicate.test(request)).thenReturn(true);
|
||||
|
||||
RouterFunction<Void> result = RouterFunctions.subroute(requestPredicate, routerFunction);
|
||||
RouterFunction<ServerResponse> result = RouterFunctions.subroute(requestPredicate, routerFunction);
|
||||
assertNotNull(result);
|
||||
|
||||
Optional<HandlerFunction<Void>> resultHandlerFunction = result.route(request);
|
||||
assertTrue(resultHandlerFunction.isPresent());
|
||||
assertEquals(handlerFunction, resultHandlerFunction.get());
|
||||
Mono<HandlerFunction<ServerResponse>> resultHandlerFunction = result.route(request);
|
||||
StepVerifier.create(resultHandlerFunction)
|
||||
.expectNext(handlerFunction)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subrouteNoMatch() throws Exception {
|
||||
HandlerFunction<Void> handlerFunction = request -> ServerResponse.ok().build();
|
||||
RouterFunction<Void> routerFunction = request -> Optional.of(handlerFunction);
|
||||
HandlerFunction<ServerResponse> handlerFunction = request -> ServerResponse.ok().build();
|
||||
RouterFunction<ServerResponse> routerFunction = request -> Mono.just(handlerFunction);
|
||||
|
||||
MockServerRequest request = MockServerRequest.builder().build();
|
||||
RequestPredicate requestPredicate = mock(RequestPredicate.class);
|
||||
when(requestPredicate.test(request)).thenReturn(false);
|
||||
|
||||
RouterFunction<Void> result = RouterFunctions.subroute(requestPredicate, routerFunction);
|
||||
RouterFunction<ServerResponse> result = RouterFunctions.subroute(requestPredicate, routerFunction);
|
||||
assertNotNull(result);
|
||||
|
||||
Optional<HandlerFunction<Void>> resultHandlerFunction = result.route(request);
|
||||
assertFalse(resultHandlerFunction.isPresent());
|
||||
Mono<HandlerFunction<ServerResponse>> resultHandlerFunction = result.route(request);
|
||||
StepVerifier.create(resultHandlerFunction)
|
||||
.expectComplete()
|
||||
.verify();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toHttpHandler() throws Exception {
|
||||
HandlerStrategies strategies = mock(HandlerStrategies.class);
|
||||
when(strategies.messageReaders()).thenReturn(
|
||||
() -> Collections.<HttpMessageReader<?>>emptyList().stream());
|
||||
Stream::<HttpMessageReader<?>>empty);
|
||||
when(strategies.messageWriters()).thenReturn(
|
||||
() -> Collections.<HttpMessageWriter<?>>emptyList().stream());
|
||||
Stream::<HttpMessageWriter<?>>empty);
|
||||
when(strategies.viewResolvers()).thenReturn(
|
||||
() -> Collections.<ViewResolver>emptyList().stream());
|
||||
Stream::<ViewResolver>empty);
|
||||
|
||||
ServerRequest request = mock(ServerRequest.class);
|
||||
ServerResponse response = mock(ServerResponse.class);
|
||||
when(response.writeTo(any(ServerWebExchange.class), eq(strategies))).thenReturn(Mono.empty());
|
||||
|
||||
HandlerFunction handlerFunction = mock(HandlerFunction.class);
|
||||
when(handlerFunction.handle(any(ServerRequest.class))).thenReturn(response);
|
||||
HandlerFunction<ServerResponse> handlerFunction = mock(HandlerFunction.class);
|
||||
when(handlerFunction.handle(any(ServerRequest.class))).thenReturn(Mono.just(response));
|
||||
|
||||
RouterFunction routerFunction = mock(RouterFunction.class);
|
||||
when(routerFunction.route(any(ServerRequest.class))).thenReturn(Optional.of(handlerFunction));
|
||||
RouterFunction<ServerResponse> routerFunction = mock(RouterFunction.class);
|
||||
when(routerFunction.route(any(ServerRequest.class))).thenReturn(Mono.just(handlerFunction));
|
||||
|
||||
RequestPredicate requestPredicate = mock(RequestPredicate.class);
|
||||
when(requestPredicate.test(request)).thenReturn(false);
|
||||
|
||||
@@ -20,7 +20,6 @@ import java.time.Duration;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
@@ -127,18 +126,18 @@ public class SseHandlerFunctionIntegrationTests
|
||||
|
||||
private static class SseHandler {
|
||||
|
||||
public ServerResponse<Publisher<String>> string(ServerRequest request) {
|
||||
public Mono<ServerResponse> string(ServerRequest request) {
|
||||
Flux<String> flux = Flux.interval(Duration.ofMillis(100)).map(l -> "foo " + l).take(2);
|
||||
return ServerResponse.ok().body(fromServerSentEvents(flux, String.class));
|
||||
}
|
||||
|
||||
public ServerResponse<Publisher<Person>> person(ServerRequest request) {
|
||||
public Mono<ServerResponse> person(ServerRequest request) {
|
||||
Flux<Person> flux = Flux.interval(Duration.ofMillis(100))
|
||||
.map(l -> new Person("foo " + l)).take(2);
|
||||
return ServerResponse.ok().body(fromServerSentEvents(flux, Person.class));
|
||||
}
|
||||
|
||||
public ServerResponse<Publisher<ServerSentEvent<String>>> sse(ServerRequest request) {
|
||||
public Mono<ServerResponse> sse(ServerRequest request) {
|
||||
Flux<ServerSentEvent<String>> flux = Flux.interval(Duration.ofMillis(100))
|
||||
.map(l -> ServerSentEvent.<String>builder().data("foo")
|
||||
.id(Long.toString(l))
|
||||
|
||||
Reference in New Issue
Block a user