package com.elibom.jogger.middleware.router; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import com.elibom.jogger.AnnotatedActionMockController; import com.elibom.jogger.AnnotatedMockController; import com.elibom.jogger.MiddlewareChain; import com.elibom.jogger.MockAnnotation; import com.elibom.jogger.MockController; import com.elibom.jogger.http.Request; import com.elibom.jogger.http.Response; import com.elibom.jogger.middleware.router.Route; import com.elibom.jogger.middleware.router.RouteHandler; import com.elibom.jogger.middleware.router.RouterMiddleware; import com.elibom.jogger.middleware.router.Route.HttpMethod; import com.elibom.jogger.middleware.router.interceptor.Interceptor; import com.elibom.jogger.middleware.router.interceptor.InterceptorExecution; import org.testng.Assert; import org.testng.annotations.Test; public class RouterMiddlewareTest { @Test public void shouldAddRoutes() throws Exception { RouterMiddleware jogger = new RouterMiddleware(); MockController controller = new MockController(); Method initMethod = MockController.class.getMethod("init", Request.class, Response.class); Method showMethod = MockController.class.getMethod("show", Request.class, Response.class); List<Route> routes = new ArrayList<Route>(); routes.add( new Route(HttpMethod.GET, "/", controller, initMethod) ); routes.add( new Route(HttpMethod.GET, "/", controller, showMethod) ); jogger.setRoutes(routes); jogger.addRoute(HttpMethod.GET, "/test", controller, "init"); jogger.addRoute(HttpMethod.GET, "/test", controller, showMethod); jogger.get("/another", mock(RouteHandler.class)); jogger.post("/another", mock(RouteHandler.class)); Assert.assertEquals(jogger.getRoutes().size(), 6); } @Test(dependsOnMethods="shouldAddRoutes") public void shouldMatchEmptyRoute() throws Exception { shouldMatchRoute(HttpMethod.GET, "", ""); shouldMatchRoute(HttpMethod.GET, "", "/"); } private void shouldMatchRoute(HttpMethod method, String routePath, String path) throws Exception { RouterMiddleware router = new RouterMiddleware(); RouteHandler handler = mock(RouteHandler.class); router.addRoute(method, routePath, handler, "handle"); Request request = mock(Request.class); when(request.getMethod()).thenReturn(method.toString().toUpperCase()); when(request.getPath()).thenReturn(path); router.handle(request, mock(Response.class), mock(MiddlewareChain.class)); verify(handler).handle(any(Request.class), any(Response.class)); reset(handler); when(request.getMethod()).thenReturn(method.toString().toLowerCase()); router.handle(request, mock(Response.class), mock(MiddlewareChain.class)); verify(handler).handle(any(Request.class), any(Response.class)); } @Test(dependsOnMethods="shouldAddRoutes") public void shouldMatchSimplePath() throws Exception { shouldMatchRoute(HttpMethod.GET, "/test", "/test"); shouldMatchRoute(HttpMethod.GET, "/test", "/test/"); } @Test(dependsOnMethods="shouldAddRoutes") public void shouldMatchPathWithVariables() throws Exception { shouldMatchRoute(HttpMethod.POST, "/test/{id}/", "/Test/1"); shouldMatchRoute(HttpMethod.POST, "/test/{id}/", "/test/1-234234/"); } @Test(dependsOnMethods="shouldAddRoutes") public void shouldMatchComplexPath() throws Exception { shouldMatchRoute(HttpMethod.POST, "/test/{id_test}/mocks/{id_mock}", "/test/1/mocks/2"); shouldMatchRoute(HttpMethod.POST, "/test/{id_test}/mocks/{id_mock}", "/test/1/mocks/2/"); } @Test(dependsOnMethods="shouldAddRoutes") public void shouldNotFindRouteWithWrongHttpMethod() throws Exception { RouterMiddleware router = new RouterMiddleware(); RouteHandler handler = mock(RouteHandler.class); router.addRoute(HttpMethod.GET, "", handler, "handle"); Request request = mock(Request.class); when(request.getMethod()).thenReturn("post"); when(request.getPath()).thenReturn("/"); Response response = mock(Response.class); router.handle(request, response, mock(MiddlewareChain.class)); verify(handler, never()).handle(any(Request.class), any(Response.class)); verify(response, never()).notFound(); verify(response, never()).status(Response.NOT_FOUND); } @Test(dependsOnMethods="shouldAddRoutes") public void shouldNotFindRouteThatMatchesNoPath() throws Exception { RouterMiddleware router = new RouterMiddleware(); RouteHandler handler = mock(RouteHandler.class); router.addRoute(HttpMethod.GET, "", handler, "handle"); Request request = mock(Request.class); when(request.getMethod()).thenReturn("post"); when(request.getPath()).thenReturn("/"); Response response = mock(Response.class); router.handle(request, response, mock(MiddlewareChain.class)); verify(handler, never()).handle(any(Request.class), any(Response.class)); verify(response, never()).notFound(); verify(response, never()).status(Response.NOT_FOUND); } @Test public void shouldCallInterceptors() throws Exception { RouterMiddleware router = new RouterMiddleware(); RouteHandler handler = mock(RouteHandler.class); router.get("/", handler); ProceedInterceptor interceptor1 = new ProceedInterceptor(); ProceedInterceptor interceptor2 = new ProceedInterceptor(); router.addInterceptor(interceptor1); router.addInterceptor(interceptor2); router.handle(mockRequest("get", "/"), mock(Response.class), mock(MiddlewareChain.class)); Assert.assertTrue(interceptor1.wasCalled()); Assert.assertFalse(interceptor1.getControllerHasAnnotation()); Assert.assertFalse(interceptor1.getActionHasAnnotation()); Assert.assertTrue(interceptor2.wasCalled()); verify(handler).handle(any(Request.class), any(Response.class)); } private Request mockRequest(String httpMethod, String path) { Request request = mock(Request.class); when(request.getMethod()).thenReturn(httpMethod); when(request.getPath()).thenReturn(path); return request; } @Test public void shouldRetrieveControllerAnnotation() throws Exception { AnnotatedMockController controller = new AnnotatedMockController(); Method method = AnnotatedMockController.class.getMethod("action", com.elibom.jogger.http.Request.class, Response.class); Route route = new Route(HttpMethod.GET, "/", controller, method); RouterMiddleware router = new RouterMiddleware(); router.addRoute(route); ProceedInterceptor interceptor = new ProceedInterceptor(); router.addInterceptor(interceptor); router.handle(mockRequest("get", "/"), mock(Response.class), mock(MiddlewareChain.class)); Assert.assertTrue(interceptor.getControllerHasAnnotation()); Assert.assertFalse(interceptor.getActionHasAnnotation()); } @Test public void shouldRetrieveActionAnnotation() throws Exception { AnnotatedActionMockController controller = new AnnotatedActionMockController(); Method method = AnnotatedActionMockController.class.getMethod("action", com.elibom.jogger.http.Request.class, Response.class); Route route = new Route(HttpMethod.GET, "/", controller, method); RouterMiddleware router = new RouterMiddleware(); router.addRoute(route); ProceedInterceptor interceptor = new ProceedInterceptor(); router.addInterceptor(interceptor); router.handle(mockRequest("get", "/"), mock(Response.class), mock(MiddlewareChain.class)); Assert.assertFalse(interceptor.getControllerHasAnnotation()); Assert.assertTrue(interceptor.getActionHasAnnotation()); } @Test public void shouldRetrieveActionAnnotationInSuperclass() throws Exception { AnnotatedActionSubclassMockController controller = new AnnotatedActionSubclassMockController(); Method method = AnnotatedActionSubclassMockController.class.getMethod("action", com.elibom.jogger.http.Request.class, Response.class); Route route = new Route(HttpMethod.GET, "/", controller, method); RouterMiddleware router = new RouterMiddleware(); router.addRoute(route); ProceedInterceptor interceptor = new ProceedInterceptor(); router.addInterceptor(interceptor); router.handle(mockRequest("get", "/"), mock(Response.class), mock(MiddlewareChain.class)); Assert.assertFalse(interceptor.getControllerHasAnnotation()); Assert.assertTrue(interceptor.getActionHasAnnotation()); } private class AnnotatedActionSubclassMockController extends AnnotatedActionMockController { @Override public void action(Request request, Response response) {} } @Test public void shouldAddRouteUsingObjectAndMethod() throws Exception { RouterMiddleware router = new RouterMiddleware(); MockController controller = new MockController(); Method initMethod = MockController.class.getMethod("init", Request.class, Response.class); router.addRoute(HttpMethod.GET, "", controller, initMethod); // also check that empty path maps to root Assert.assertEquals(router.getRoutes().size(), 1); Route route = router.getRoutes().iterator().next(); Assert.assertNotNull(route); Assert.assertEquals(route.getHttpMethod(), HttpMethod.GET); Assert.assertEquals(route.getPath(), "/"); Assert.assertEquals(route.getController(), controller); Assert.assertEquals(route.getAction(), initMethod); } @Test public void shouldAddRouteUsingObjectAndMethodName() throws Exception { RouterMiddleware router = new RouterMiddleware(); MockController controller = new MockController(); router.addRoute(HttpMethod.GET, "/", controller, "init"); Assert.assertEquals(router.getRoutes().size(), 1); Route route = router.getRoutes().iterator().next(); Assert.assertNotNull(route); Assert.assertEquals(route.getHttpMethod(), HttpMethod.GET); Assert.assertEquals(route.getPath(), "/"); Assert.assertEquals(route.getController(), controller); Method method = route.getAction(); Assert.assertNotNull(method); Assert.assertEquals(method.getName(), "init"); } @Test(expectedExceptions=NoSuchMethodException.class) public void shouldFailToAddRouteWithInvalidMethodName() throws Exception { RouterMiddleware router = new RouterMiddleware(); router.addRoute(HttpMethod.GET, "", new MockController(), "invalidMethod"); } @Test(expectedExceptions=IllegalArgumentException.class) public void shouldFailToAddRouteWithNullHttpMethod() throws Exception { RouterMiddleware router = new RouterMiddleware(); router.addRoute(null, "", new MockController(), "init"); } @Test(expectedExceptions=IllegalArgumentException.class) public void shouldFailToAddRouteWithNullPath() throws Exception { RouterMiddleware router = new RouterMiddleware(); router.addRoute(null, "", new MockController(), "init"); } @Test(expectedExceptions=IllegalArgumentException.class) public void shouldFailToAddRouteWithNullObject() throws Exception { RouterMiddleware router = new RouterMiddleware(); router.addRoute(HttpMethod.GET, "", null, "init"); } @Test public void shouldAddRouteUsingGetMethod() throws Exception { RouterMiddleware router = new RouterMiddleware(); RouteHandler handler = mock(RouteHandler.class); router.get("/", handler); Assert.assertEquals(router.getRoutes().size(), 1); Route route = router.getRoutes().iterator().next(); Assert.assertNotNull(route); Assert.assertEquals(route.getHttpMethod(), HttpMethod.GET); Assert.assertEquals(route.getPath(), "/"); Assert.assertEquals(route.getController(), handler); Method method = route.getAction(); Assert.assertNotNull(method); Assert.assertEquals(method.getName(), "handle"); } @Test public void shouldAddRouteUsingPostMethod() throws Exception { RouterMiddleware router = new RouterMiddleware(); RouteHandler handler = mock(RouteHandler.class); router.get("/", handler); Assert.assertEquals(router.getRoutes().size(), 1); Route route = router.getRoutes().iterator().next(); Assert.assertNotNull(route); Assert.assertEquals(route.getHttpMethod(), HttpMethod.GET); Assert.assertEquals(route.getPath(), "/"); Assert.assertEquals(route.getController(), handler); Method method = route.getAction(); Assert.assertNotNull(method); Assert.assertEquals(method.getName(), "handle"); } @Test(expectedExceptions=IllegalArgumentException.class) public void shouldFailToSetEmptyRoutes() throws Exception { RouterMiddleware router = new RouterMiddleware(); router.setRoutes(null); } @Test(expectedExceptions=IllegalArgumentException.class) public void shouldFailToAddNullRoute() throws Exception { RouterMiddleware router = new RouterMiddleware(); router.addRoute(null); } @Test(expectedExceptions=IllegalArgumentException.class) public void shouldFailToSetNullInterceptors() throws Exception { RouterMiddleware router = new RouterMiddleware(); router.setInterceptors(null); } @Test(expectedExceptions=IllegalArgumentException.class) public void shouldFailToAddNullInterceptor() throws Exception { RouterMiddleware router = new RouterMiddleware(); router.addInterceptor(null); } class ProceedInterceptor implements Interceptor { boolean called = false; boolean controllerHasAnnotation = false; boolean actionHasAnnotation = false; @Override public void intercept(Request request, Response response, InterceptorExecution execution) throws Exception { controllerHasAnnotation = execution.getController().getAnnotation(MockAnnotation.class) != null; actionHasAnnotation = execution.getAction().getAnnotation(MockAnnotation.class) != null; execution.proceed(); called = true; } public boolean wasCalled() { return called; } public boolean getControllerHasAnnotation() { return controllerHasAnnotation; } public boolean getActionHasAnnotation() { return actionHasAnnotation; } } }