package act.route;
/*-
* #%L
* ACT Framework
* %%
* Copyright (C) 2014 - 2017 ActFramework
* %%
* 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.
* #L%
*/
import act.controller.ParamNames;
import act.handler.RequestHandler;
import act.handler.builtin.AlwaysNotFound;
import act.handler.builtin.StaticFileGetter;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.osgl.$;
import org.osgl.Osgl;
import org.osgl.exception.ConfigurationException;
import org.osgl.exception.NotAppliedException;
import org.osgl.http.H;
import org.osgl.util.C;
import java.io.File;
import static act.route.RouteSource.*;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.osgl.http.H.Method.GET;
public class RouterTest extends RouterTestBase {
private RequestHandler staticDirHandler;
@Override
protected void buildRouteMapping(Router router) {
}
@Before
public void prepare() {
staticDirHandler = Mockito.mock(StaticFileGetter.class);
when(staticDirHandler.supportPartialPath()).thenReturn(true);
}
@Test
public void testMappingAdded() {
no(router.isMapped(GET, "/foo"));
router.addMapping(GET, "/foo", "Foo.bar");
yes(router.isMapped(GET, "/foo"));
}
@Test
public void searchRoot() {
router.addMapping(GET, "/", controller);
router.getInvoker(GET, "/", ctx).handle(ctx);
controllerInvoked();
}
@Test
public void searchBadUrl() {
RequestHandler handler = router.getInvoker(GET, "/nonexists", ctx);
same(handler, AlwaysNotFound.INSTANCE);
}
@Test
public void searchStaticUrl() {
router.addMapping(H.Method.POST, "/foo/bar", controller);
router.getInvoker(H.Method.POST, "/foo/bar", ctx).handle(ctx);
controllerInvoked();
}
@Test
public void searchDynamicUrl() {
router.addMapping(GET, "/svc/{<[0-9]{4}>id}", controller);
H.Request req = Mockito.mock(H.Request.class);
when(ctx.req()).thenReturn(req);
when(req.path()).thenReturn("/svc/1234");
router.getInvoker(GET, "/svc/1234/", ctx).handle(ctx);
controllerInvoked();
verify(ctx).param("id", "1234");
}
@Test
public void searchDynamicUrl2() {
router.addMapping(GET, "/svc/{<[0-9]{4}>id}-{name}", controller);
H.Request req = Mockito.mock(H.Request.class);
when(ctx.req()).thenReturn(req);
when(req.path()).thenReturn("/svc/1234-abc");
router.getInvoker(GET, "/svc/1234-abc/", ctx).handle(ctx);
controllerInvoked();
verify(ctx).param("id", "1234");
verify(ctx).param("name", "abc");
}
@Test
public void searchDynamicUrl3() {
router.addMapping(GET, "/svc/{<[0-9]{4}>id}-{name}", controller);
router.addMapping(GET, "/svc/{<[0-9]{4}>sid}-{sname}/obj", controller);
router.addMapping(GET, "/Persons/Joe/Parents;generations={gen}", controller);
router.addMapping(GET, "/place/{latitude};{longitude}", controller);
H.Request req = Mockito.mock(H.Request.class);
when(ctx.req()).thenReturn(req);
when(req.path()).thenReturn("/svc/1234-abc");
router.getInvoker(GET, "/svc/1234-abc", ctx).handle(ctx);
verify(ctx).param("id", "1234");
verify(ctx).param("name", "abc");
when(req.path()).thenReturn("/svc/1234-abc/obj");
router.getInvoker(GET, "/svc/1234-abc/obj", ctx).handle(ctx);
verify(ctx).param("sid", "1234");
verify(ctx).param("sname", "abc");
when(req.path()).thenReturn("/Persons/Joe/Parents;generations=147");
router.getInvoker(GET, "/Persons/Joe/Parents;generations=147", ctx).handle(ctx);
verify(ctx).param("gen", "147");
when(req.path()).thenReturn("/place/39.87381;-86.1399");
router.getInvoker(GET, "/place/39.87381;-86.1399", ctx).handle(ctx);
verify(ctx).param("latitude", "39.87381");
verify(ctx).param("longitude", "-86.1399");
}
@Test
public void regExtStyleA() {
_regExtTests("n:[0-9]+");
}
@Test
public void regExtStyleB2() {
_regExtTests("{n<[0-9]+>}");
}
private void _regExtTests(String pattern) {
router.addMapping(GET, "/int/" + pattern, controller);
H.Request req = Mockito.mock(H.Request.class);
when(ctx.req()).thenReturn(req);
when(req.path()).thenReturn("/int/33");
RequestHandler handler = router.getInvoker(GET, "/int/33", ctx);
same(controller, handler);
verify(ctx).param("n", "33");
}
@Test
public void searchPathEndsWithIgnoreNotation() {
router.addMapping(GET, "/foo/bar/...", controller);
router.addMapping(GET, "/svc/{id}/...", controller);
H.Request req = Mockito.mock(H.Request.class);
when(ctx.req()).thenReturn(req);
when(req.path()).thenReturn("/foo/bar/something-should-be-ignored");
RequestHandler handler = router.getInvoker(GET, "/foo/bar/something-should-be-ignored", ctx);
same(controller, handler);
when(req.path()).thenReturn("/svc/123/another-thing-should-be-ignored/and-whatever/else");
router.getInvoker(GET, "/svc/123/another-thing-should-be-ignored/and-whatever/else", ctx).handle(ctx);
verify(ctx).param("id", "123");
}
@Test(expected = ConfigurationException.class)
public void routingConfiguredWithEndStarConflict1() {
router.addMapping(GET, "/foo/bar/...", controller);
router.addMapping(GET, "/foo/bar/xyz", controller);
}
@Test(expected = ConfigurationException.class)
public void routingConfiguredWithEndStarConflict2() {
router.addMapping(GET, "/foo/bar/xyz", controller);
router.addMapping(GET, "/foo/bar/...", controller);
}
@Test
public void searchPartialUrl() {
router.addMapping(GET, "/public", staticDirHandler);
router.getInvoker(GET, "/public/foo/bar.txt", ctx).handle(ctx);
verify(staticDirHandler).handle(ctx);
verify(ctx).param(ParamNames.PATH, "/foo/bar.txt");
}
@Test
public void routeWithStaticDir() {
router.addMapping(GET, "/public", "file:/public");
RequestHandler handler = router.getInvoker(GET, "/public/foo/bar.txt", ctx);
yes(handler instanceof StaticFileGetter);
yes(handler.supportPartialPath());
eq(new File(BASE, "/public"), fieldVal(handler, "base"));
}
@Test
public void overrideExistingRouting() {
routeWithStaticDir();
router.addMapping(GET, "/public", "file:/private");
RequestHandler handler = router.getInvoker(GET, "/public/foo/bar.txt", ctx);
yes(handler instanceof StaticFileGetter);
yes(handler.supportPartialPath());
eq(new File(BASE, "/private"), fieldVal(handler, "base"));
}
@Test
public void doNotOverrideExistingRouting() {
routeWithStaticDir();
router.addMapping(GET, "/public", "file:/private", ACTION_ANNOTATION);
RequestHandler handler = router.getInvoker(GET, "/public/foo/bar.txt", ctx);
yes(handler instanceof StaticFileGetter);
yes(handler.supportPartialPath());
eq(new File(BASE, "/public"), fieldVal(handler, "base"));
}
@Test
public void senseControllerMethodWithoutControllerPackage() {
router.addMapping(GET, "/foo", "Controller.foo");
no(router.isActionMethod("foo.controller.Controller", "foo"));
yes(router.isActionMethod("Controller", "foo"));
router.addMapping(GET, "/bar", "com.newcontroller.Controller.bar");
yes(router.isActionMethod("com.newcontroller.Controller", "bar"));
}
@Test
public void itShallNotOverwriteRouteMappingWithSameRouteSource() {
for (RouteSource source : RouteSource.values()) {
router = new Router(controllerLookup, app);
router.addMapping(GET, "/foo", "Controller.foo", source);
try {
router.addMapping(GET, "/foo", "Foo.bar", source);
if (source != ROUTE_TABLE && source != ADMIN_OVERWRITE) {
fail("expected DuplicateRouteMappingException");
}
} catch (DuplicateRouteMappingException e) {
// good
}
}
}
@Test
public void testAddingTwoRoutesWithSameDynamicPart() {
router.addMapping(GET, "/foo/{id}", "Controller.foo");
router.addMapping(GET, "/foo/{id}/bar", "Foo.bar");
}
@Test(expected = DuplicateRouteMappingException.class)
public void itShallNotAllowAddingHandlersToSameRouteEndingWithDynamicPart() {
router.addMapping(GET, "/foo/{id}", "Controller.foo", ACTION_ANNOTATION);
router.addMapping(GET, "/foo/{id}", "Foo.bar", ACTION_ANNOTATION);
}
@Test
public void testReverseRoute() {
router.addMapping(GET, "/foo/bar", "pkg.Foo.bar");
eq(router.reverseRoute("pkg.Foo.bar"), "/foo/bar");
eq(router.reverseRoute("pkg.Foo.bar", C.<String, Object>map("foo", "bar")), "/foo/bar?foo=bar");
}
@Test
public void testReverseRouteWithPathVar() {
router.addMapping(GET, "/foo/{foo}", "pkg.Foo.foo");
router.addMapping(GET, "/foo/{fooId}/bar/{barId}", "pkg.Foo.bar");
eq(router.reverseRoute("pkg.Foo.bar"), "/foo/-/bar/-");
eq(router.reverseRoute("pkg.Foo.bar", C.<String, Object>map("fooId", 1, "barId", 3)), "/foo/1/bar/3");
eq(router.reverseRoute("pkg.Foo.foo", C.<String, Object>map("foo", 1)), "/foo/1");
}
@Test
public void testReverseRouteWithPathVar2() {
router.addMapping(GET, "/foo/{fooId}-{barId}", "pkg.Foo.bar");
router.addMapping(GET, "/foo/{foo}.htm", "pkg.Foo.foo");
//eq(router.reverseRoute("pkg.Foo.bar"), "/foo/---");
eq(router.reverseRoute("pkg.Foo.bar", C.<String, Object>map("fooId", 1, "barId", 3)), "/foo/1-3");
eq(router.reverseRoute("pkg.Foo.foo", C.<String, Object>map("foo", 1)), "/foo/1.htm");
}
@Test
public void testInferFullActionPath() {
final String currentActionPath = "com.my.comp.proj_a.controller.MyController.login";
$.Func0<String> provider = new $.Func0<String>() {
@Override
public String apply() throws NotAppliedException, Osgl.Break {
return currentActionPath;
}
};
eq("com.my.comp.proj_a.controller.MyController.home", Router.inferFullActionPath("home", provider));
eq("com.my.comp.proj_a.controller.YourController.home", Router.inferFullActionPath("YourController.home", provider));
eq("pkg.YourController.home", Router.inferFullActionPath("pkg.YourController.home", provider));
}
@Test
public void ghIssue121() {
router.addMapping(GET, "/abc/134/foo/{a}", "pkg.Foo.any", ACTION_ANNOTATION);
router.addMapping(GET, "/abc/134/foo/bar", "pkg.Foo.bar", ACTION_ANNOTATION);
router.addMapping(GET, "/abc/134/foo/zee", "pkg.Foo.zee", ACTION_ANNOTATION);
eq("/abc/134/foo/abc", router.reverseRoute("pkg.Foo.any", C.<String, Object>map("a", "abc")));
eq("/abc/134/foo/bar", router.reverseRoute("pkg.Foo.bar"));
eq("/abc/134/foo/zee", router.reverseRoute("pkg.Foo.zee"));
}
}