Browse Source
Introduce separate test classes for each base class in the hierarchy above @ResponseBody and ResponseEntity result handlers. Also start porting existing unit test cases for @ResponseBody and ResponseEntity return value handlers.pull/1111/head
7 changed files with 464 additions and 149 deletions
@ -0,0 +1,137 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2016 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.result; |
||||||
|
|
||||||
|
import java.net.URI; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
import org.springframework.core.convert.support.GenericConversionService; |
||||||
|
import org.springframework.http.HttpMethod; |
||||||
|
import org.springframework.http.MediaType; |
||||||
|
import org.springframework.http.server.reactive.MockServerHttpRequest; |
||||||
|
import org.springframework.http.server.reactive.MockServerHttpResponse; |
||||||
|
import org.springframework.web.reactive.accept.FixedContentTypeResolver; |
||||||
|
import org.springframework.web.reactive.accept.HeaderContentTypeResolver; |
||||||
|
import org.springframework.web.reactive.accept.RequestedContentTypeResolver; |
||||||
|
import org.springframework.web.server.ServerWebExchange; |
||||||
|
import org.springframework.web.server.adapter.DefaultServerWebExchange; |
||||||
|
import org.springframework.web.server.session.WebSessionManager; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
import static org.mockito.Mockito.mock; |
||||||
|
import static org.springframework.http.MediaType.ALL; |
||||||
|
import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8; |
||||||
|
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM; |
||||||
|
import static org.springframework.http.MediaType.IMAGE_GIF; |
||||||
|
import static org.springframework.http.MediaType.IMAGE_JPEG; |
||||||
|
import static org.springframework.http.MediaType.IMAGE_PNG; |
||||||
|
import static org.springframework.http.MediaType.TEXT_PLAIN; |
||||||
|
import static org.springframework.web.reactive.HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE; |
||||||
|
|
||||||
|
/** |
||||||
|
* Unit tests for {@link ContentNegotiatingResultHandlerSupport}. |
||||||
|
* @author Rossen Stoyanchev |
||||||
|
*/ |
||||||
|
public class ContentNegotiatingResultHandlerSupportTests { |
||||||
|
|
||||||
|
private TestHandlerSupport handlerSupport; |
||||||
|
|
||||||
|
private MockServerHttpRequest request; |
||||||
|
|
||||||
|
private ServerWebExchange exchange; |
||||||
|
|
||||||
|
|
||||||
|
@Before |
||||||
|
public void setUp() throws Exception { |
||||||
|
this.handlerSupport = new TestHandlerSupport(); |
||||||
|
this.request = new MockServerHttpRequest(HttpMethod.GET, new URI("/path")); |
||||||
|
this.exchange = new DefaultServerWebExchange( |
||||||
|
this.request, new MockServerHttpResponse(), mock(WebSessionManager.class)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Test |
||||||
|
public void usesContentTypeResolver() throws Exception { |
||||||
|
RequestedContentTypeResolver resolver = new FixedContentTypeResolver(IMAGE_GIF); |
||||||
|
TestHandlerSupport handlerSupport = new TestHandlerSupport(resolver); |
||||||
|
|
||||||
|
List<MediaType> mediaTypes = Arrays.asList(IMAGE_JPEG, IMAGE_GIF, IMAGE_PNG); |
||||||
|
MediaType actual = handlerSupport.selectMediaType(this.exchange, mediaTypes); |
||||||
|
|
||||||
|
assertEquals(IMAGE_GIF, actual); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void producibleMediaTypesRequestAttribute() throws Exception { |
||||||
|
Set<MediaType> producible = Collections.singleton(IMAGE_GIF); |
||||||
|
this.exchange.getAttributes().put(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, producible); |
||||||
|
|
||||||
|
List<MediaType> mediaTypes = Arrays.asList(IMAGE_JPEG, IMAGE_GIF, IMAGE_PNG); |
||||||
|
MediaType actual = handlerSupport.selectMediaType(this.exchange, mediaTypes); |
||||||
|
|
||||||
|
assertEquals(IMAGE_GIF, actual); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // SPR-9160
|
||||||
|
public void sortsByQuality() throws Exception { |
||||||
|
this.request.getHeaders().add("Accept", "text/plain; q=0.5, application/json"); |
||||||
|
|
||||||
|
List<MediaType> mediaTypes = Arrays.asList(TEXT_PLAIN, APPLICATION_JSON_UTF8); |
||||||
|
MediaType actual = this.handlerSupport.selectMediaType(this.exchange, mediaTypes); |
||||||
|
|
||||||
|
assertEquals(APPLICATION_JSON_UTF8, actual); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void charsetFromAcceptHeader() throws Exception { |
||||||
|
MediaType text8859 = MediaType.parseMediaType("text/plain;charset=ISO-8859-1"); |
||||||
|
MediaType textUtf8 = MediaType.parseMediaType("text/plain;charset=UTF-8"); |
||||||
|
|
||||||
|
this.request.getHeaders().setAccept(Collections.singletonList(text8859)); |
||||||
|
MediaType actual = this.handlerSupport.selectMediaType(this.exchange, Collections.singletonList(textUtf8)); |
||||||
|
|
||||||
|
assertEquals(text8859, actual); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // SPR-12894
|
||||||
|
public void noConcreteMediaType() throws Exception { |
||||||
|
List<MediaType> producible = Collections.singletonList(ALL); |
||||||
|
MediaType actual = this.handlerSupport.selectMediaType(this.exchange, producible); |
||||||
|
|
||||||
|
assertEquals(APPLICATION_OCTET_STREAM, actual); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static class TestHandlerSupport extends ContentNegotiatingResultHandlerSupport { |
||||||
|
|
||||||
|
protected TestHandlerSupport() { |
||||||
|
this(new HeaderContentTypeResolver()); |
||||||
|
} |
||||||
|
|
||||||
|
public TestHandlerSupport(RequestedContentTypeResolver contentTypeResolver) { |
||||||
|
super(new GenericConversionService(), contentTypeResolver); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,155 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2016 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.result.method.annotation; |
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream; |
||||||
|
import java.io.OutputStream; |
||||||
|
import java.net.URI; |
||||||
|
import java.nio.charset.Charset; |
||||||
|
import java.time.Duration; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Ignore; |
||||||
|
import org.junit.Test; |
||||||
|
import reactor.core.publisher.Flux; |
||||||
|
import reactor.core.publisher.Mono; |
||||||
|
import reactor.core.test.TestSubscriber; |
||||||
|
import rx.Observable; |
||||||
|
|
||||||
|
import org.springframework.core.ResolvableType; |
||||||
|
import org.springframework.core.codec.Decoder; |
||||||
|
import org.springframework.core.codec.Encoder; |
||||||
|
import org.springframework.core.codec.support.ByteBufferDecoder; |
||||||
|
import org.springframework.core.codec.support.ByteBufferEncoder; |
||||||
|
import org.springframework.core.codec.support.JacksonJsonDecoder; |
||||||
|
import org.springframework.core.codec.support.JacksonJsonEncoder; |
||||||
|
import org.springframework.core.codec.support.Jaxb2Decoder; |
||||||
|
import org.springframework.core.codec.support.Jaxb2Encoder; |
||||||
|
import org.springframework.core.codec.support.JsonObjectDecoder; |
||||||
|
import org.springframework.core.codec.support.StringDecoder; |
||||||
|
import org.springframework.core.codec.support.StringEncoder; |
||||||
|
import org.springframework.core.convert.support.GenericConversionService; |
||||||
|
import org.springframework.core.convert.support.ReactiveStreamsToCompletableFutureConverter; |
||||||
|
import org.springframework.core.convert.support.ReactiveStreamsToRxJava1Converter; |
||||||
|
import org.springframework.core.io.ByteArrayResource; |
||||||
|
import org.springframework.core.io.Resource; |
||||||
|
import org.springframework.core.io.buffer.support.DataBufferTestUtils; |
||||||
|
import org.springframework.http.HttpMethod; |
||||||
|
import org.springframework.http.converter.reactive.CodecHttpMessageConverter; |
||||||
|
import org.springframework.http.converter.reactive.HttpMessageConverter; |
||||||
|
import org.springframework.http.converter.reactive.ResourceHttpMessageConverter; |
||||||
|
import org.springframework.http.server.reactive.MockServerHttpRequest; |
||||||
|
import org.springframework.http.server.reactive.MockServerHttpResponse; |
||||||
|
import org.springframework.http.server.reactive.ServerHttpRequest; |
||||||
|
import org.springframework.util.ObjectUtils; |
||||||
|
import org.springframework.web.reactive.accept.RequestedContentTypeResolver; |
||||||
|
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder; |
||||||
|
import org.springframework.web.server.ServerWebExchange; |
||||||
|
import org.springframework.web.server.adapter.DefaultServerWebExchange; |
||||||
|
import org.springframework.web.server.session.WebSessionManager; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
import static org.junit.Assert.assertNull; |
||||||
|
import static org.mockito.Mockito.mock; |
||||||
|
|
||||||
|
/** |
||||||
|
* Unit tests for {@link AbstractMessageConverterResultHandler}. |
||||||
|
* @author Rossen Stoyanchev |
||||||
|
*/ |
||||||
|
public class MessageConverterResultHandlerTests { |
||||||
|
|
||||||
|
private AbstractMessageConverterResultHandler resultHandler; |
||||||
|
|
||||||
|
private MockServerHttpResponse response = new MockServerHttpResponse(); |
||||||
|
|
||||||
|
private ServerWebExchange exchange; |
||||||
|
|
||||||
|
|
||||||
|
@Before |
||||||
|
public void setUp() throws Exception { |
||||||
|
this.resultHandler = createResultHandler(); |
||||||
|
ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, new URI("/path")); |
||||||
|
this.exchange = new DefaultServerWebExchange(request, this.response, mock(WebSessionManager.class)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Test // SPR-12894
|
||||||
|
@Ignore // GH # 121
|
||||||
|
public void useDefaultContentType() throws Exception { |
||||||
|
Object body = new ByteArrayResource("body".getBytes("UTF-8")); |
||||||
|
ResolvableType bodyType = ResolvableType.forType(Resource.class); |
||||||
|
this.resultHandler.writeBody(this.exchange, body, bodyType).block(Duration.ofSeconds(5)); |
||||||
|
|
||||||
|
assertEquals("image/jpeg", this.response.getHeaders().getFirst("Content-Type")); |
||||||
|
TestSubscriber.subscribe(this.response.getBody()) |
||||||
|
.assertValuesWith(buf -> assertEquals("body", |
||||||
|
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8")))); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void voidReturnType() throws Exception { |
||||||
|
testVoidReturnType(null, ResolvableType.forType(Void.class)); |
||||||
|
testVoidReturnType(Mono.empty(), ResolvableType.forClassWithGenerics(Mono.class, Void.class)); |
||||||
|
testVoidReturnType(Flux.empty(), ResolvableType.forClassWithGenerics(Flux.class, Void.class)); |
||||||
|
testVoidReturnType(Observable.empty(), ResolvableType.forClassWithGenerics(Observable.class, Void.class)); |
||||||
|
} |
||||||
|
|
||||||
|
private void testVoidReturnType(Object body, ResolvableType bodyType) { |
||||||
|
this.resultHandler.writeBody(this.exchange, body, bodyType).block(Duration.ofSeconds(5)); |
||||||
|
|
||||||
|
assertNull(this.response.getHeaders().get("Content-Type")); |
||||||
|
assertNull(this.response.getBody()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test // SPR-13135
|
||||||
|
public void unsupportedReturnType() throws Exception { |
||||||
|
ByteArrayOutputStream body = new ByteArrayOutputStream(); |
||||||
|
ResolvableType bodyType = ResolvableType.forType(OutputStream.class); |
||||||
|
|
||||||
|
HttpMessageConverter<?> converter = new CodecHttpMessageConverter<>(new ByteBufferEncoder()); |
||||||
|
Mono<Void> mono = createResultHandler(converter).writeBody(this.exchange, body, bodyType); |
||||||
|
|
||||||
|
TestSubscriber.subscribe(mono).assertError(IllegalStateException.class); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private AbstractMessageConverterResultHandler createResultHandler(HttpMessageConverter<?>... converters) { |
||||||
|
List<HttpMessageConverter<?>> converterList; |
||||||
|
if (ObjectUtils.isEmpty(converters)) { |
||||||
|
converterList = new ArrayList<>(); |
||||||
|
converterList.add(new CodecHttpMessageConverter<>(new ByteBufferEncoder())); |
||||||
|
converterList.add(new CodecHttpMessageConverter<>(new StringEncoder())); |
||||||
|
converterList.add(new ResourceHttpMessageConverter()); |
||||||
|
converterList.add(new CodecHttpMessageConverter<>(new Jaxb2Encoder())); |
||||||
|
converterList.add(new CodecHttpMessageConverter<>(new JacksonJsonEncoder())); |
||||||
|
} |
||||||
|
else { |
||||||
|
converterList = Arrays.asList(converters); |
||||||
|
} |
||||||
|
|
||||||
|
GenericConversionService service = new GenericConversionService(); |
||||||
|
service.addConverter(new ReactiveStreamsToCompletableFutureConverter()); |
||||||
|
service.addConverter(new ReactiveStreamsToRxJava1Converter()); |
||||||
|
|
||||||
|
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build(); |
||||||
|
|
||||||
|
return new AbstractMessageConverterResultHandler(converterList, service, resolver) {}; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue