def test_add_route_endpoint_with_object(self): class MySuperApi: @route("/users") def user(self, _: Request, args): # should be inherited assert not args return Response("user") class MyApi(MySuperApi): @route("/users/<int:user_id>") def user_id(self, _: Request, args): assert args return Response(f"{args['user_id']}") def foo(self, _: Request, args): # should be ignored raise NotImplementedError api = MyApi() router = Router() rules = router.add_route_endpoints(api) assert len(rules) == 2 assert router.dispatch(Request("GET", "/users")).data == b"user" assert router.dispatch(Request("GET", "/users/123")).data == b"123"
def test_dispatch_to_correct_function(self): router = Router(dispatcher=resource_dispatcher(pass_response=False)) requests = [] class TestResource: def on_get(self, req): requests.append(req) return "GET/OK" def on_post(self, req): requests.append(req) return {"ok": "POST"} router.add("/health", TestResource()) request1 = Request("GET", "/health") request2 = Request("POST", "/health") assert router.dispatch(request1).get_data(True) == "GET/OK" assert router.dispatch(request1).get_data(True) == "GET/OK" assert router.dispatch(request2).json == {"ok": "POST"} assert len(requests) == 3 assert requests[0] is request1 assert requests[1] is request1 assert requests[2] is request2
def test_regex_path_dispatcher(self): router = Router() router.url_map.converters["regex"] = RegexConverter rgx = r"([^.]+)endpoint(.*)" regex = f"/<regex('{rgx}'):dist>/" router.add(path=regex, endpoint=noop) assert router.dispatch(Request(method="GET", path="/test-endpoint")) with pytest.raises(NotFound): router.dispatch(Request(method="GET", path="/test-not-point"))
def test_handler_dispatcher_invalid_signature(self): router = Router(dispatcher=handler_dispatcher()) def handler(_request: Request, arg1) -> Response: # invalid signature return Response("ok") router.add("/foo/<arg1>/<arg2>", handler) with pytest.raises(TypeError): router.dispatch(Request("GET", "/foo/a/b"))
def test_dispatch_to_non_existing_method_raises_exception(self): router = Router(dispatcher=resource_dispatcher(pass_response=False)) class TestResource: def on_post(self, request): return "POST/OK" router.add("/health", TestResource()) with pytest.raises(MethodNotAllowed): assert router.dispatch(Request("GET", "/health")) assert router.dispatch(Request("POST", "/health")).get_data(True) == "POST/OK"
def test_router_route_decorator(self): router = Router() @router.route("/users") def user(_: Request, args): assert not args return Response("user") @router.route("/users/<int:user_id>") def user_id(_: Request, args): assert args return Response(f"{args['user_id']}") assert router.dispatch(Request("GET", "/users")).data == b"user" assert router.dispatch(Request("GET", "/users/123")).data == b"123"
def test_dispatcher_with_pass_response(self): router = Router(dispatcher=resource_dispatcher(pass_response=True)) class TestResource: def on_get(self, req, resp: Response): resp.set_json({"message": "GET/OK"}) def on_post(self, req, resp): resp.set_data("POST/OK") router.add("/health", TestResource()) assert router.dispatch(Request("GET", "/health")).json == { "message": "GET/OK" } assert router.dispatch(Request("POST", "/health")).get_data(True) == "POST/OK"
def test_handler_dispatcher_with_none_return(self): router = Router(dispatcher=handler_dispatcher()) def handler(_request: Request): return None router.add("/", handler) assert router.dispatch(Request("GET", "/")).status_code == 200
def test_custom_dispatcher(self): collector = RequestCollector() router = Router(dispatcher=collector) router.add("/", "index") router.add("/users/<int:id>", "users") router.dispatch(Request("GET", "/")) router.dispatch(Request("GET", "/users/12")) _, endpoint, args = collector.requests[0] assert endpoint == "index" assert args == {} _, endpoint, args = collector.requests[1] assert endpoint == "users" assert args == {"id": 12}
def test_handler_dispatcher_with_text_return(self): router = Router(dispatcher=handler_dispatcher()) def handler(_request: Request, arg1) -> str: return f"hello: {arg1}" router.add("/<arg1>", handler) assert router.dispatch(Request("GET", "/world")).data == b"hello: world"
def test_default_dispatcher_invokes_correct_endpoint(self): router = Router() def index(_: Request, args) -> Response: response = Response() response.set_json(args) return response def users(_: Request, args) -> Response: response = Response() response.set_json(args) return response router.add("/", index) router.add("/users/<int:user_id>", users) assert router.dispatch(Request("GET", "/")).json == {} assert router.dispatch(Request("GET", "/users/12")).json == {"user_id": 12}
def test_regex_host_dispatcher(self): router = Router() router.url_map.converters["regex"] = RegexConverter rgx = r"\.cloudfront.(net|localhost\.localstack\.cloud)" router.add(path="/", endpoint=noop, host=f"<dist_id><regex('{rgx}'):host>:<port>") assert router.dispatch( Request( method="GET", headers={"Host": "ad91f538.cloudfront.localhost.localstack.cloud:5446"}, ) ) with pytest.raises(NotFound): router.dispatch( Request( method="GET", headers={"Host": "ad91f538.cloudfront.amazon.aws.com:5446"}, ) )
def test_handler_dispatcher_with_dict_return(self): router = Router(dispatcher=handler_dispatcher()) def handler(_request: Request, arg1) -> Dict[str, Any]: return {"arg1": arg1, "hello": "there"} router.add("/foo/<arg1>", handler) assert router.dispatch(Request("GET", "/foo/a")).json == { "arg1": "a", "hello": "there" }
def test_remove_rule(self): router = Router() def index(_: Request, args) -> Response: return Response(b"index") def users(_: Request, args) -> Response: return Response(b"users") rule0 = router.add("/", index) rule1 = router.add("/users/<int:user_id>", users) assert router.dispatch(Request("GET", "/")).data == b"index" assert router.dispatch(Request("GET", "/users/12")).data == b"users" router.remove_rule(rule1) assert router.dispatch(Request("GET", "/")).data == b"index" with pytest.raises(NotFound): assert router.dispatch(Request("GET", "/users/12")) router.remove_rule(rule0) with pytest.raises(NotFound): assert router.dispatch(Request("GET", "/")) with pytest.raises(NotFound): assert router.dispatch(Request("GET", "/users/12"))
def test_handler_dispatcher(self): router = Router(dispatcher=handler_dispatcher()) def handler_foo(_request: Request) -> Response: return Response("ok") def handler_bar(_request: Request, bar, baz) -> Dict[str, any]: response = Response() response.set_json({"bar": bar, "baz": baz}) return response router.add("/foo", handler_foo) router.add("/bar/<int:bar>/<baz>", handler_bar) assert router.dispatch(Request("GET", "/foo")).data == b"ok" assert router.dispatch(Request("GET", "/bar/420/ed")).json == { "bar": 420, "baz": "ed" } with pytest.raises(NotFound): assert router.dispatch(Request("GET", "/bar/asfg/ed"))
def test_dispatch_raises_not_found(self): router = Router() router.add("/foobar", noop) with pytest.raises(NotFound): assert router.dispatch(Request("GET", "/foo"))