/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.reactive.function.server;
import java.nio.ByteBuffer;
import java.time.ZonedDateTime;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.function.BiFunction;
import org.junit.Test;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.core.ResolvableType;
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.EncoderHttpMessageWriter;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;
import org.springframework.web.reactive.function.BodyInserter;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.*;
/**
* @author Arjen Poutsma
*/
public class DefaultEntityResponseBuilderTests {
@Test
public void fromObject() throws Exception {
String body = "foo";
EntityResponse<String> response = EntityResponse.fromObject(body).build().block();
assertSame(body, response.entity());
}
@Test
public void fromPublisherClass() throws Exception {
Flux<String> body = Flux.just("foo", "bar");
EntityResponse<Flux<String>> response = EntityResponse.fromPublisher(body, String.class).build().block();
assertSame(body, response.entity());
}
@Test
public void fromPublisherResolvableType() throws Exception {
Flux<String> body = Flux.just("foo", "bar");
ResolvableType type = ResolvableType.forClass(String.class);
EntityResponse<Flux<String>> response = EntityResponse.fromPublisher(body, type).build().block();
assertSame(body, response.entity());
}
@Test
public void status() throws Exception {
String body = "foo";
Mono<EntityResponse<String>> result = EntityResponse.fromObject(body).status(HttpStatus.CREATED).build();
StepVerifier.create(result)
.expectNextMatches(response -> HttpStatus.CREATED.equals(response.statusCode()))
.expectComplete()
.verify();
}
@Test
public void allow() throws Exception {
String body = "foo";
Mono<EntityResponse<String>> result = EntityResponse.fromObject(body).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 {
String body = "foo";
Mono<EntityResponse<String>> result = EntityResponse.fromObject(body).contentLength(42).build();
StepVerifier.create(result)
.expectNextMatches(response -> Long.valueOf(42).equals(response.headers().getContentLength()))
.expectComplete()
.verify();
}
@Test
public void contentType() throws Exception {
String body = "foo";
Mono<EntityResponse<String>>
result = EntityResponse.fromObject(body).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 {
String body = "foo";
Mono<EntityResponse<String>> result = EntityResponse.fromObject(body).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();
String body = "foo";
Mono<EntityResponse<String>> result = EntityResponse.fromObject(body).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 {
String body = "foo";
Mono<EntityResponse<String>>
result = EntityResponse.fromObject(body).cacheControl(CacheControl.noCache()).build();
StepVerifier.create(result)
.expectNextMatches(response -> "no-cache".equals(response.headers().getCacheControl()))
.expectComplete()
.verify();
}
@Test
public void varyBy() throws Exception {
String body = "foo";
Mono<EntityResponse<String>> result = EntityResponse.fromObject(body).varyBy("foo").build();
List<String> expected = Collections.singletonList("foo");
StepVerifier.create(result)
.expectNextMatches(response -> expected.equals(response.headers().getVary()))
.expectComplete()
.verify();
}
@Test
public void headers() throws Exception {
String body = "foo";
HttpHeaders headers = new HttpHeaders();
Mono<EntityResponse<String>> result = EntityResponse.fromObject(body).headers(headers).build();
StepVerifier.create(result)
.expectNextMatches(response -> headers.equals(response.headers()))
.expectComplete()
.verify();
}
@Test
public void bodyInserter() throws Exception {
String body = "foo";
Publisher<String> publisher = Mono.just(body);
BiFunction<ServerHttpResponse, BodyInserter.Context, Mono<Void>> writer =
(response, strategies) -> {
byte[] bodyBytes = body.getBytes(UTF_8);
ByteBuffer byteBuffer = ByteBuffer.wrap(bodyBytes);
DataBuffer buffer = new DefaultDataBufferFactory().wrap(byteBuffer);
return response.writeWith(Mono.just(buffer));
};
Mono<EntityResponse<Publisher<String>>> result = EntityResponse.fromPublisher(publisher, String.class).build();
MockServerWebExchange exchange = MockServerHttpRequest.get("http://localhost").toExchange();
HandlerStrategies strategies = HandlerStrategies.empty()
.customCodecs(configurer -> configurer.writer(new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes())))
.build();
StepVerifier.create(result)
.consumeNextWith(response -> {
StepVerifier.create(response.entity())
.expectNext(body)
.expectComplete()
.verify();
response.writeTo(exchange, strategies);
})
.expectComplete()
.verify();
assertNotNull(exchange.getResponse().getBody());
}
}