提交 55193194 编写于 作者: R Rossen Stoyanchev

Polish tests

上级 9c438a8f
......@@ -52,7 +52,7 @@ import static org.springframework.web.reactive.HandlerMapping.PRODUCIBLE_MEDIA_T
*/
public class ContentNegotiatingResultHandlerSupportTests {
private TestHandlerSupport handlerSupport;
private TestResultHandler resultHandler;
private MockServerHttpRequest request;
......@@ -61,7 +61,7 @@ public class ContentNegotiatingResultHandlerSupportTests {
@Before
public void setUp() throws Exception {
this.handlerSupport = new TestHandlerSupport();
this.resultHandler = new TestResultHandler();
this.request = new MockServerHttpRequest(HttpMethod.GET, new URI("/path"));
this.exchange = new DefaultServerWebExchange(
this.request, new MockServerHttpResponse(), new MockWebSessionManager());
......@@ -70,11 +70,9 @@ public class ContentNegotiatingResultHandlerSupportTests {
@Test
public void usesContentTypeResolver() throws Exception {
RequestedContentTypeResolver resolver = new FixedContentTypeResolver(IMAGE_GIF);
TestHandlerSupport handlerSupport = new TestHandlerSupport(resolver);
TestResultHandler resultHandler = new TestResultHandler(new FixedContentTypeResolver(IMAGE_GIF));
List<MediaType> mediaTypes = Arrays.asList(IMAGE_JPEG, IMAGE_GIF, IMAGE_PNG);
MediaType actual = handlerSupport.selectMediaType(this.exchange, mediaTypes);
MediaType actual = resultHandler.selectMediaType(this.exchange, mediaTypes);
assertEquals(IMAGE_GIF, actual);
}
......@@ -85,7 +83,7 @@ public class ContentNegotiatingResultHandlerSupportTests {
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);
MediaType actual = resultHandler.selectMediaType(this.exchange, mediaTypes);
assertEquals(IMAGE_GIF, actual);
}
......@@ -95,7 +93,7 @@ public class ContentNegotiatingResultHandlerSupportTests {
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);
MediaType actual = this.resultHandler.selectMediaType(this.exchange, mediaTypes);
assertEquals(APPLICATION_JSON_UTF8, actual);
}
......@@ -104,9 +102,8 @@ public class ContentNegotiatingResultHandlerSupportTests {
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));
MediaType actual = this.resultHandler.selectMediaType(this.exchange, Collections.singletonList(textUtf8));
assertEquals(text8859, actual);
}
......@@ -114,21 +111,20 @@ public class ContentNegotiatingResultHandlerSupportTests {
@Test // SPR-12894
public void noConcreteMediaType() throws Exception {
List<MediaType> producible = Collections.singletonList(ALL);
MediaType actual = this.handlerSupport.selectMediaType(this.exchange, producible);
MediaType actual = this.resultHandler.selectMediaType(this.exchange, producible);
assertEquals(APPLICATION_OCTET_STREAM, actual);
}
@SuppressWarnings("WeakerAccess")
private static class TestResultHandler extends ContentNegotiatingResultHandlerSupport {
private static class TestHandlerSupport extends ContentNegotiatingResultHandlerSupport {
protected TestHandlerSupport() {
protected TestResultHandler() {
this(new HeaderContentTypeResolver());
}
public TestHandlerSupport(RequestedContentTypeResolver contentTypeResolver) {
public TestResultHandler(RequestedContentTypeResolver contentTypeResolver) {
super(new GenericConversionService(), contentTypeResolver);
}
}
......
......@@ -21,11 +21,14 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.bouncycastle.util.Arrays;
import org.springframework.core.MethodIntrospector;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
/**
......@@ -66,6 +69,8 @@ public class ResolvableMethod {
private String methodName;
private Class<?>[] argumentTypes;
private ResolvableType returnType;
private final List<Class<? extends Annotation>> annotationTypes = new ArrayList<>(4);
......@@ -81,6 +86,11 @@ public class ResolvableMethod {
return this;
}
public ResolvableMethod argumentTypes(Class<?>... argumentTypes) {
this.argumentTypes = argumentTypes;
return this;
}
public ResolvableMethod returning(ResolvableType resolvableType) {
this.returnType = resolvableType;
return this;
......@@ -94,16 +104,21 @@ public class ResolvableMethod {
public Method resolve() {
// String comparison (ResolvableType's with different providers)
String expected = this.returnType != null ? this.returnType.toString() : null;
String expectedReturnType = getReturnType();
Set<Method> methods = MethodIntrospector.selectMethods(this.targetClass,
(ReflectionUtils.MethodFilter) method -> {
String actual = ResolvableType.forMethodReturnType(method).toString();
if (this.methodName != null && !this.methodName.equals(method.getName())) {
return false;
}
if (expected != null) {
if (!actual.equals(expected) && !Object.class.equals(method.getDeclaringClass())) {
if (getReturnType() != null) {
String actual = ResolvableType.forMethodReturnType(method).toString();
if (!actual.equals(getReturnType()) && !Object.class.equals(method.getDeclaringClass())) {
return false;
}
}
if (!ObjectUtils.isEmpty(this.argumentTypes)) {
if (!Arrays.areEqual(this.argumentTypes, method.getParameterTypes())) {
return false;
}
}
......@@ -121,6 +136,10 @@ public class ResolvableMethod {
return methods.iterator().next();
}
private String getReturnType() {
return this.returnType != null ? this.returnType.toString() : null;
}
public MethodParameter resolveReturnType() {
Method method = resolve();
return new MethodParameter(method, -1);
......
......@@ -49,7 +49,6 @@ import static org.junit.Assert.assertNull;
/**
* Unit tests for {@link AbstractHandlerMethodMapping}.
*
* @author Rossen Stoyanchev
*/
public class HandlerMethodMappingTests {
......@@ -82,8 +81,8 @@ public class HandlerMethodMappingTests {
public void directMatch() throws Exception {
String key = "foo";
this.mapping.registerMapping(key, this.handler, this.method1);
Mono<Object> result = this.mapping.getHandler(createExchange(HttpMethod.GET, key));
assertEquals(this.method1, ((HandlerMethod) result.block()).getMethod());
}
......@@ -102,9 +101,7 @@ public class HandlerMethodMappingTests {
this.mapping.registerMapping("/fo?", this.handler, this.method2);
Mono<Object> result = this.mapping.getHandler(createExchange(HttpMethod.GET, "/foo"));
TestSubscriber
.subscribe(result)
.assertError(IllegalStateException.class);
TestSubscriber.subscribe(result).assertError(IllegalStateException.class);
}
@Test
......@@ -115,6 +112,7 @@ public class HandlerMethodMappingTests {
this.mapping.registerMapping(key2, this.handler, this.method2);
List directUrlMatches = this.mapping.getMappingRegistry().getMappingsByUrl(key1);
assertNotNull(directUrlMatches);
assertEquals(1, directUrlMatches.size());
assertEquals(key1, directUrlMatches.get(0));
......@@ -130,6 +128,7 @@ public class HandlerMethodMappingTests {
this.mapping.registerMapping(key2, handler2, this.method1);
List directUrlMatches = this.mapping.getMappingRegistry().getMappingsByUrl(key1);
assertNotNull(directUrlMatches);
assertEquals(1, directUrlMatches.size());
assertEquals(key1, directUrlMatches.get(0));
......@@ -140,14 +139,17 @@ public class HandlerMethodMappingTests {
String key = "foo";
this.mapping.registerMapping(key, this.handler, this.method1);
Mono<Object> result = this.mapping.getHandler(createExchange(HttpMethod.GET, key));
assertNotNull(result.block());
this.mapping.unregisterMapping(key);
result = this.mapping.getHandler(createExchange(HttpMethod.GET, key));
assertNull(result.block());
assertNull(this.mapping.getMappingRegistry().getMappingsByUrl(key));
}
private ServerWebExchange createExchange(HttpMethod httpMethod, String path) throws URISyntaxException {
ServerHttpRequest request = new MockServerHttpRequest(httpMethod, new URI(path));
WebSessionManager sessionManager = new MockWebSessionManager();
......
......@@ -17,197 +17,156 @@ package org.springframework.web.reactive.result.method;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Arrays;
import java.util.Collections;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.publisher.Signal;
import reactor.core.util.SignalKind;
import reactor.core.test.TestSubscriber;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.MockServerHttpRequest;
import org.springframework.http.server.reactive.MockServerHttpResponse;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.ModelMap;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.result.method.annotation.RequestParamMethodArgumentResolver;
import org.springframework.web.reactive.result.ResolvableMethod;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.session.MockWebSessionManager;
import org.springframework.web.server.session.WebSessionManager;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Unit tests for {@link InvocableHandlerMethod}.
* @author Rossen Stoyanchev
*/
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
public class InvocableHandlerMethodTests {
private ServerHttpRequest request;
private ServerWebExchange exchange;
private ModelMap model;
private ModelMap model = new ExtendedModelMap();
@Before
public void setUp() throws Exception {
WebSessionManager sessionManager = new MockWebSessionManager();
this.request = mock(ServerHttpRequest.class);
this.exchange = new DefaultServerWebExchange(request, mock(ServerHttpResponse.class), sessionManager);
this.model = new ExtendedModelMap();
this.exchange = new DefaultServerWebExchange(
new MockServerHttpRequest(HttpMethod.GET, new URI("http://localhost:8080/path")),
new MockServerHttpResponse(),
new MockWebSessionManager());
}
@Test
public void noArgsMethod() throws Exception {
InvocableHandlerMethod hm = createHandlerMethod("noArgs");
public void invokeMethodWithNoArguments() throws Exception {
InvocableHandlerMethod hm = handlerMethod("noArgs");
Mono<HandlerResult> mono = hm.invokeForRequest(this.exchange, this.model);
HandlerResult value = mono.block();
assertNotNull(value);
assertEquals("success", value.getReturnValue().get());
assertHandlerResultValue(mono, "success");
}
@Test
public void resolveArgToZeroValues() throws Exception {
when(this.request.getURI()).thenReturn(new URI("http://localhost:8080/path"));
when(this.request.getQueryParams()).thenReturn(new LinkedMultiValueMap<>());
InvocableHandlerMethod hm = createHandlerMethod("singleArg", String.class);
hm.setHandlerMethodArgumentResolvers(Collections.singletonList(
new RequestParamMethodArgumentResolver(new GenericConversionService(), null, false)));
public void invokeMethodWithNoValue() throws Exception {
InvocableHandlerMethod hm = handlerMethod("singleArg");
addResolver(hm, Mono.empty());
Mono<HandlerResult> mono = hm.invokeForRequest(this.exchange, this.model);
HandlerResult value = mono.block();
assertNotNull(value);
assertEquals("success:null", value.getReturnValue().get());
assertHandlerResultValue(mono, "success:null");
}
@Test
public void resolveArgToOneValue() throws Exception {
InvocableHandlerMethod hm = createHandlerMethod("singleArg", String.class);
public void invokeMethodWithValue() throws Exception {
InvocableHandlerMethod hm = handlerMethod("singleArg", String.class);
addResolver(hm, Mono.just("value1"));
Mono<HandlerResult> mono = hm.invokeForRequest(this.exchange, this.model);
HandlerResult value = mono.block();
assertNotNull(value);
assertEquals("success:value1", value.getReturnValue().get());
assertHandlerResultValue(mono, "success:value1");
}
@Test
public void resolveArgToMultipleValues() throws Exception {
InvocableHandlerMethod hm = createHandlerMethod("singleArg", String.class);
addResolver(hm, Flux.fromIterable(Arrays.asList("value1", "value2", "value3")));
public void noMatchingResolver() throws Exception {
InvocableHandlerMethod hm = handlerMethod("singleArg", String.class);
Mono<HandlerResult> mono = hm.invokeForRequest(this.exchange, this.model);
HandlerResult value = mono.block();
assertNotNull(value);
assertEquals("success:value1", value.getReturnValue().get());
}
@Test
public void noResolverForArg() throws Exception {
InvocableHandlerMethod hm = createHandlerMethod("singleArg", String.class);
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange, this.model);
Throwable ex = awaitErrorSignal(publisher);
assertEquals(IllegalStateException.class, ex.getClass());
assertEquals("No resolver for argument [0] of type [java.lang.String] on method " +
"[" + hm.getMethod().toGenericString() + "]", ex.getMessage());
TestSubscriber.subscribe(mono)
.assertError(IllegalStateException.class)
.assertErrorMessage("No resolver for argument [0] of type [java.lang.String] " +
"on method [" + hm.getMethod().toGenericString() + "]");
}
@Test
public void resolveArgumentWithThrownException() throws Exception {
HandlerMethodArgumentResolver resolver = mock(HandlerMethodArgumentResolver.class);
when(resolver.supportsParameter(any())).thenReturn(true);
when(resolver.resolveArgument(any(), any(), any())).thenThrow(new IllegalStateException("boo"));
InvocableHandlerMethod hm = createHandlerMethod("singleArg", String.class);
hm.setHandlerMethodArgumentResolvers(Collections.singletonList(resolver));
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange, this.model);
Throwable ex = awaitErrorSignal(publisher);
public void resolverThrowsException() throws Exception {
InvocableHandlerMethod hm = handlerMethod("singleArg", String.class);
addResolver(hm, Mono.error(new IllegalStateException("boo")));
Mono<HandlerResult> mono = hm.invokeForRequest(this.exchange, this.model);
assertEquals(IllegalStateException.class, ex.getClass());
assertEquals("Exception not wrapped with helpful argument details",
"Error resolving argument [0] of type [java.lang.String] on method " +
"[" + hm.getMethod().toGenericString() + "]", ex.getMessage());
TestSubscriber.subscribe(mono)
.assertError(IllegalStateException.class)
.assertErrorMessage("Error resolving argument [0] of type [java.lang.String] " +
"on method [" + hm.getMethod().toGenericString() + "]");
}
@Test
public void resolveArgumentWithErrorSignal() throws Exception {
InvocableHandlerMethod hm = createHandlerMethod("singleArg", String.class);
public void resolverWithErrorSignal() throws Exception {
InvocableHandlerMethod hm = handlerMethod("singleArg", String.class);
addResolver(hm, Mono.error(new IllegalStateException("boo")));
Mono<HandlerResult> mono = hm.invokeForRequest(this.exchange, this.model);
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange, this.model);
Throwable ex = awaitErrorSignal(publisher);
assertEquals(IllegalStateException.class, ex.getClass());
assertEquals("Exception not wrapped with helpful argument details",
"Error resolving argument [0] of type [java.lang.String] on method " +
"[" + hm.getMethod().toGenericString() + "]", ex.getMessage());
TestSubscriber.subscribe(mono)
.assertError(IllegalStateException.class)
.assertErrorMessage("Error resolving argument [0] of type [java.lang.String] " +
"on method [" + hm.getMethod().toGenericString() + "]");
}
@Test
public void illegalArgumentExceptionIsWrappedWithHelpfulDetails() throws Exception {
InvocableHandlerMethod hm = createHandlerMethod("singleArg", String.class);
public void illegalArgumentExceptionIsWrappedWithInvocationDetails() throws Exception {
InvocableHandlerMethod hm = handlerMethod("singleArg", String.class);
addResolver(hm, Mono.just(1));
Mono<HandlerResult> mono = hm.invokeForRequest(this.exchange, this.model);
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange, this.model);
Throwable ex = awaitErrorSignal(publisher);
assertEquals(IllegalStateException.class, ex.getClass());
assertEquals("Failed to invoke controller with resolved arguments: " +
"[0][type=java.lang.Integer][value=1] " +
"on method [" + hm.getMethod().toGenericString() + "]", ex.getMessage());
TestSubscriber.subscribe(mono)
.assertError(IllegalStateException.class)
.assertErrorMessage("Failed to invoke controller with resolved arguments: " +
"[0][type=java.lang.Integer][value=1] " +
"on method [" + hm.getMethod().toGenericString() + "]");
}
@Test
public void invocationTargetExceptionIsUnwrapped() throws Exception {
InvocableHandlerMethod hm = createHandlerMethod("exceptionMethod");
Publisher<HandlerResult> publisher = hm.invokeForRequest(this.exchange, this.model);
Throwable ex = awaitErrorSignal(publisher);
InvocableHandlerMethod hm = handlerMethod("exceptionMethod");
Mono<HandlerResult> mono = hm.invokeForRequest(this.exchange, this.model);
assertEquals(IllegalStateException.class, ex.getClass());
assertEquals("boo", ex.getMessage());
TestSubscriber.subscribe(mono)
.assertError(IllegalStateException.class)
.assertErrorMessage("boo");
}
private InvocableHandlerMethod createHandlerMethod(String methodName, Class<?>... argTypes) throws Exception {
Object controller = new TestController();
Method method = controller.getClass().getMethod(methodName, argTypes);
return new InvocableHandlerMethod(new HandlerMethod(controller, method));
private InvocableHandlerMethod handlerMethod(String name, Class<?>... args) throws Exception {
Method method = ResolvableMethod.on(TestController.class).name(name).argumentTypes(args).resolve();
return new InvocableHandlerMethod(new HandlerMethod(new TestController(), method));
}
private void addResolver(InvocableHandlerMethod handlerMethod, Publisher<Object> resolvedValue) {
private void addResolver(InvocableHandlerMethod handlerMethod, Mono<Object> resolvedValue) {
HandlerMethodArgumentResolver resolver = mock(HandlerMethodArgumentResolver.class);
when(resolver.supportsParameter(any())).thenReturn(true);
when(resolver.resolveArgument(any(), any(), any())).thenReturn(Mono.from(resolvedValue));
when(resolver.resolveArgument(any(), any(), any())).thenReturn(resolvedValue);
handlerMethod.setHandlerMethodArgumentResolvers(Collections.singletonList(resolver));
}
private Throwable awaitErrorSignal(Publisher<?> publisher) throws Exception {
Signal<?> signal = Flux.from(publisher).materialize().collectList().block().get(0);
assertEquals("Unexpected signal: " + signal, SignalKind.onError, signal.getType());
return signal.getThrowable();
private void assertHandlerResultValue(Mono<HandlerResult> mono, String expected) {
TestSubscriber.subscribe(mono).assertValuesWith(result -> {
Optional<?> optional = result.getReturnValue();
assertTrue(optional.isPresent());
assertEquals(expected, optional.get());
});
}
......@@ -218,7 +177,7 @@ public class InvocableHandlerMethodTests {
return "success";
}
public String singleArg(@RequestParam(required=false) String q) {
public String singleArg(String q) {
return "success:" + q;
}
......@@ -227,5 +186,4 @@ public class InvocableHandlerMethodTests {
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册