/* * 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; import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; import org.junit.Before; import org.junit.Test; import reactor.core.publisher.Mono; import reactor.core.test.TestSubscriber; import org.springframework.http.HttpMethod; import org.springframework.http.server.reactive.MockServerHttpRequest; import org.springframework.http.server.reactive.MockServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Controller; import org.springframework.util.AntPathMatcher; import org.springframework.util.PathMatcher; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.method.HandlerMethod; 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.assertNull; /** * Unit tests for {@link AbstractHandlerMethodMapping}. * @author Rossen Stoyanchev */ public class HandlerMethodMappingTests { private AbstractHandlerMethodMapping<String> mapping; private MyHandler handler; private Method method1; private Method method2; @Before public void setUp() throws Exception { this.mapping = new MyHandlerMethodMapping(); this.handler = new MyHandler(); this.method1 = handler.getClass().getMethod("handlerMethod1"); this.method2 = handler.getClass().getMethod("handlerMethod2"); } @Test(expected = IllegalStateException.class) public void registerDuplicates() { this.mapping.registerMapping("foo", this.handler, this.method1); this.mapping.registerMapping("foo", this.handler, this.method2); } @Test 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()); } @Test public void patternMatch() throws Exception { this.mapping.registerMapping("/fo*", this.handler, this.method1); this.mapping.registerMapping("/f*", this.handler, this.method2); Mono<Object> result = this.mapping.getHandler(createExchange(HttpMethod.GET, "/foo")); assertEquals(this.method1, ((HandlerMethod) result.block()).getMethod()); } @Test public void ambiguousMatch() throws Exception { this.mapping.registerMapping("/f?o", this.handler, this.method1); this.mapping.registerMapping("/fo?", this.handler, this.method2); Mono<Object> result = this.mapping.getHandler(createExchange(HttpMethod.GET, "/foo")); TestSubscriber.subscribe(result).assertError(IllegalStateException.class); } @Test public void registerMapping() throws Exception { String key1 = "/foo"; String key2 = "/foo*"; this.mapping.registerMapping(key1, this.handler, this.method1); 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)); } @Test public void registerMappingWithSameMethodAndTwoHandlerInstances() throws Exception { String key1 = "foo"; String key2 = "bar"; MyHandler handler1 = new MyHandler(); MyHandler handler2 = new MyHandler(); this.mapping.registerMapping(key1, handler1, this.method1); 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)); } @Test public void unregisterMapping() throws Exception { 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(); return new DefaultServerWebExchange(request, new MockServerHttpResponse(), sessionManager); } private static class MyHandlerMethodMapping extends AbstractHandlerMethodMapping<String> { private PathMatcher pathMatcher = new AntPathMatcher(); @Override protected boolean isHandler(Class<?> beanType) { return true; } @Override protected String getMappingForMethod(Method method, Class<?> handlerType) { String methodName = method.getName(); return methodName.startsWith("handler") ? methodName : null; } @Override protected Set<String> getMappingPathPatterns(String key) { return (this.pathMatcher.isPattern(key) ? Collections.emptySet() : Collections.singleton(key)); } @Override protected String getMatchingMapping(String pattern, ServerWebExchange exchange) { String lookupPath = exchange.getRequest().getURI().getPath(); return (this.pathMatcher.match(pattern, lookupPath) ? pattern : null); } @Override protected Comparator<String> getMappingComparator(ServerWebExchange exchange) { String lookupPath = exchange.getRequest().getURI().getPath(); return this.pathMatcher.getPatternComparator(lookupPath); } } @Controller private static class MyHandler { @RequestMapping @SuppressWarnings("unused") public void handlerMethod1() { } @RequestMapping @SuppressWarnings("unused") public void handlerMethod2() { } } }