Exemple #1
0
 def extra_headers(self) -> None:
     sr = StubStartResponse()
     respond_with_html(
         sr,
         "<div>Täst</div>",
         extra_headers=[("X-Custom-Header", "Foobar")],
     )
     sr.assert_header_equals("X-Custom-Header", "Foobar")
Exemple #2
0
 def error_if_content_type_also_in_extra_headers(self) -> None:
     sr = StubStartResponse()
     with assert_raises(ValueError):
         respond(
             sr,
             content_type="image/png",
             extra_headers=[("Content-Type", "image/jpeg")],
         )
Exemple #3
0
 def content_length(self) -> None:
     sr = StubStartResponse()
     respond_with_json(sr, {"foo": 33})
     sr.assert_header_equals("Content-Length", "11")
Exemple #4
0
class RouterTest(TestCase):
    @before
    def setup_router(self) -> None:
        self.router = Router()
        self.router.error_handling = False
        self.start_response = StubStartResponse()
        self.environment = default_environment()
        self.disable_logger()

    def disable_logger(self) -> None:
        logging.getLogger(LOGGER_NAME).disabled = True

    def _create_path_checker(self, expected_path: str) -> WSGIApplication:
        def handle(environ: WSGIEnvironment,
                   sr: StartResponse) -> Sequence[bytes]:
            assert_equal(expected_path, environ["PATH_INFO"])
            sr("200 OK", [])
            return []

        return handle

    def handle_wsgi(self,
                    method: str = "GET",
                    path: str = "/") -> Iterable[bytes]:
        self.environment["REQUEST_METHOD"] = method
        self.environment["PATH_INFO"] = path
        return self.router(self.environment, self.start_response)

    @test
    def not_found_response_page(self) -> None:
        response = self.handle_wsgi("GET", "/foo/bar")
        html = b"".join(response).decode("utf-8")
        assert_equal(
            """<!DOCTYPE html>
<html>
    <head>
        <title>404 &#x2014; Not Found</title>
    </head>
    <body>
        <h1>404 &#x2014; Not Found</h1>
        <p>Path &#x27;/foo/bar&#x27; not found.</p>
    </body>
</html>
""",
            html,
        )

    @test
    def not_found_escape_path(self) -> None:
        response = self.handle_wsgi("GET", "/foo/<bar")
        html = b"".join(response).decode("utf-8")
        assert_in("<p>Path &#x27;/foo/&lt;bar&#x27; not found.</p>", html)

    @test
    def no_routes(self) -> None:
        self.handle_wsgi("GET", "/foo/bar")
        self.start_response.assert_status(HTTPStatus.NOT_FOUND)
        self.start_response.assert_header_equals("Content-Type",
                                                 "text/html; charset=utf-8")

    @test
    def handler_request(self) -> None:
        def handle(environ: WSGIEnvironment,
                   start_response: StartResponse) -> Iterable[bytes]:
            assert_equal("test.example.com", environ["SERVER_NAME"])
            start_response("200 OK", [])
            return [b""]

        self.router.add_routes([("", "GET", handle)])
        self.environment["SERVER_NAME"] = "test.example.com"
        self.handle_wsgi("GET", "")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def empty_route(self) -> None:
        self.router.add_routes([("", "GET", handle_empty_path)])
        self.handle_wsgi("GET", "")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def root_route(self) -> None:
        self.router.add_routes([("", "GET", handle_empty_path)])
        self.handle_wsgi("GET", "/")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def first_level(self) -> None:
        def handle(environ: WSGIEnvironment,
                   start_response: StartResponse) -> Iterable[bytes]:
            assert_equal("", environ["rouver.wildcard_path"])
            start_response("200 OK", [])
            return []

        self.router.add_routes([("foo", "GET", handle)])
        self.handle_wsgi("GET", "/foo")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def first_level__trailing_slash(self) -> None:
        def handle(environ: WSGIEnvironment,
                   start_response: StartResponse) -> Iterable[bytes]:
            assert_equal("/", environ["rouver.wildcard_path"])
            start_response("200 OK", [])
            return []

        self.router.add_routes([("foo", "GET", handle)])
        self.handle_wsgi("GET", "/foo/")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def first_level_wrong_path(self) -> None:
        self.router.add_routes([("foo", "GET", handle_empty_path)])
        self.handle_wsgi("GET", "/bar")
        self.start_response.assert_status(HTTPStatus.NOT_FOUND)

    @test
    def level_mismatch_1(self) -> None:
        self.router.add_routes([("foo/bar", "GET", handle_empty_path)])
        self.handle_wsgi("GET", "/foo")
        self.start_response.assert_status(HTTPStatus.NOT_FOUND)

    @test
    def level_mismatch_2(self) -> None:
        self.router.add_routes([("foo", "GET", handle_empty_path)])
        self.handle_wsgi("GET", "/foo/bar")
        self.start_response.assert_status(HTTPStatus.NOT_FOUND)

    @test
    def decode_path(self) -> None:
        self.router.add_routes([("foo/bär", "GET", handle_success)])
        self.handle_wsgi("GET", "/foo/b%c3%a4r")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def invalid_path_encoding(self) -> None:
        self.router.add_routes([("foo/bar", "GET", handle_success)])
        self.handle_wsgi("GET", "/foo/b%c3r")
        self.start_response.assert_status(HTTPStatus.NOT_FOUND)

    # Method Handling

    @test
    def wrong_method_response_page(self) -> None:
        self.router.add_routes([("foo", "GET", fail_if_called),
                                ("foo", "PUT", fail_if_called)])
        response = self.handle_wsgi("POST", "/foo")
        html = b"".join(response).decode("utf-8")
        assert_equal(
            """<!DOCTYPE html>
<html>
    <head>
        <title>405 &#x2014; Method Not Allowed</title>
    </head>
    <body>
        <h1>405 &#x2014; Method Not Allowed</h1>
        <p>Method &#x27;POST&#x27; not allowed. Please try GET or PUT.</p>
    </body>
</html>
""",
            html,
        )

    @test
    def wrong_method_escape_method(self) -> None:
        self.router.add_routes([("foo", "GET", fail_if_called)])
        response = self.handle_wsgi("G<T", "/foo")
        html = b"".join(response).decode("utf-8")
        assert_in(
            "<p>Method &#x27;G&lt;T&#x27; not allowed. Please try GET.</p>",
            html,
        )

    @test
    def wrong_method(self) -> None:
        self.router.add_routes([("foo", "GET", fail_if_called),
                                ("foo", "PUT", fail_if_called)])
        self.handle_wsgi("POST", "/foo")
        self.start_response.assert_status(HTTPStatus.METHOD_NOT_ALLOWED)
        self.start_response.assert_header_equals("Allow", "GET, PUT")

    @test
    def wrong_method__multiple_matches(self) -> None:
        self.router.add_routes([("foo", "GET", fail_if_called),
                                ("foo", "GET", fail_if_called)])
        self.handle_wsgi("POST", "/foo")
        self.start_response.assert_status(HTTPStatus.METHOD_NOT_ALLOWED)
        self.start_response.assert_header_equals("Allow", "GET")

    @test
    def call_right_method(self) -> None:
        self.router.add_routes([
            ("foo", "GET", fail_if_called),
            ("foo", "POST", handle_success),
            ("foo", "PUT", fail_if_called),
        ])
        self.handle_wsgi("POST", "/foo")
        self.start_response.assert_status(HTTPStatus.OK)

    # Path Templates

    @test
    def unknown_template(self) -> None:
        with assert_raises(KeyError):
            self.router.add_routes([("foo/{unknown}/bar", "GET",
                                     fail_if_called)])

    @test
    def no_template(self) -> None:
        def handle(environ: WSGIEnvironment,
                   start_response: StartResponse) -> Iterable[bytes]:
            assert_equal([], environ["rouver.path_args"])
            start_response("200 OK", [])
            return [b""]

        self.router.add_routes([("foo/bar", "GET", handle)])
        self.handle_wsgi("GET", "/foo/bar")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def template(self) -> None:
        def handle(environ: WSGIEnvironment,
                   start_response: StartResponse) -> Iterable[bytes]:
            assert_equal(["xyzxyz"], environ["rouver.path_args"])
            start_response("200 OK", [])
            return [b""]

        def handle_path(request: Request, paths: Sequence[Any],
                        path: str) -> str:
            assert_is_instance(request, Request)
            assert_equal((), paths)
            return path * 2

        self.router.add_template_handler("handler", handle_path)

        self.router.add_routes([("foo/{handler}/bar", "GET", handle)])
        self.handle_wsgi("GET", "/foo/xyz/bar")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def multiple_templates(self) -> None:
        def handle(environ: WSGIEnvironment,
                   start_response: StartResponse) -> Iterable[bytes]:
            assert_equal(["xyz", 123], environ["rouver.path_args"])
            start_response("200 OK", [])
            return [b""]

        def handle_path(_: Request, paths: Sequence[Any], __: str) -> int:
            assert_equal(("xyz", ), paths)
            return 123

        self.router.add_template_handler("handler1", lambda _, __, ___: "xyz")
        self.router.add_template_handler("handler2", handle_path)

        self.router.add_routes([("foo/{handler1}/bar/{handler2}", "GET",
                                 handle)])
        self.handle_wsgi("GET", "/foo/xyz/bar/abc")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def template_handler_is_passed_decoded_value(self) -> None:
        def handle_path(_: Request, __: Any, v: str) -> None:
            assert_equal("foo/bar", v)

        self.router.add_template_handler("handler", handle_path)

        self.router.add_routes([("foo/{handler}", "GET", handle_success)])
        self.handle_wsgi("GET", "/foo/foo%2Fbar")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def template_handler_is_not_passed_an_invalid_value(self) -> None:
        def handle_path(_: Request, __: Any, v: str) -> None:
            fail("template handler should not have been called")

        self.router.add_template_handler("handler", handle_path)

        self.router.add_routes([("foo/{handler}", "GET", handle_success)])
        self.handle_wsgi("GET", "/foo/foo%C3bar")
        self.start_response.assert_status(HTTPStatus.NOT_FOUND)

    @test
    def template_value_error(self) -> None:
        def raise_value_error(_: Request, __: Sequence[str], ___: str) -> None:
            raise ValueError()

        self.router.add_template_handler("handler", raise_value_error)

        self.router.add_routes([("foo/{handler}/bar", "GET", fail_if_called)])
        self.handle_wsgi("GET", "/foo/xyz/bar")
        self.start_response.assert_status(HTTPStatus.NOT_FOUND)

    @test
    def template_multiple_matches(self) -> None:
        def raise_value_error(_: Request, __: Sequence[str], ___: str) -> None:
            raise ValueError()

        self.router.add_template_handler("handler1", raise_value_error)
        self.router.add_template_handler("handler2", lambda _, __, ___: None)

        self.router.add_routes([
            ("foo/{handler1}/bar", "GET", fail_if_called),
            ("foo/{handler2}/bar", "GET", handle_success),
        ])
        self.handle_wsgi("GET", "/foo/xyz/bar")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def template_multiple_matches__match_first(self) -> None:
        self.router.add_template_handler("handler1", lambda _, __, ___: None)
        self.router.add_template_handler("handler2", lambda _, __, ___: None)

        self.router.add_routes([
            ("foo/{handler1}/bar", "GET", handle_success),
            ("foo/{handler2}/bar", "GET", fail_if_called),
        ])
        self.handle_wsgi("GET", "/foo/xyz/bar")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def template_call_once_per_value(self) -> None:
        calls = 0

        def increase_count(_: Request, __: Sequence[str], ___: str) -> None:
            nonlocal calls
            calls += 1

        self.router.add_template_handler("handler", increase_count)

        self.router.add_routes([
            ("foo/{handler}/bar", "GET", fail_if_called),
            ("foo/{handler}/baz", "GET", handle_success),
        ])
        self.handle_wsgi("GET", "/foo/xyz/baz")
        assert_equal(1, calls)

    @test
    def template_call_twice_for_differing_values(self) -> None:
        calls = 0

        def increase_count(_: Request, __: Sequence[str], ___: str) -> None:
            nonlocal calls
            calls += 1

        self.router.add_template_handler("handler", increase_count)

        self.router.add_routes([
            ("foo/{handler}/bar", "GET", fail_if_called),
            ("foo/xyz/{handler}", "GET", handle_success),
        ])
        self.handle_wsgi("GET", "/foo/xyz/baz")
        assert_equal(2, calls)

    # Wildcard Paths

    @test
    def no_wildcard_path(self) -> None:
        def handle(environ: WSGIEnvironment,
                   start_response: StartResponse) -> Iterable[bytes]:
            assert_equal("", environ["rouver.wildcard_path"])
            start_response("200 OK", [])
            return [b""]

        self.router.add_routes([("foo/bar", "GET", handle)])
        self.handle_wsgi("GET", "/foo/bar")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def wildcard_path__no_trailing_slash(self) -> None:
        def handle(environ: WSGIEnvironment,
                   start_response: StartResponse) -> Iterable[bytes]:
            assert_equal([], environ["rouver.path_args"])
            assert_equal("", environ["rouver.wildcard_path"])
            start_response("200 OK", [])
            return [b""]

        self.router.add_routes([("foo/bar/*", "GET", handle)])
        self.handle_wsgi("GET", "/foo/bar")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def wildcard_path__with_trailing_slash(self) -> None:
        def handle(environ: WSGIEnvironment,
                   start_response: StartResponse) -> Iterable[bytes]:
            assert_equal([], environ["rouver.path_args"])
            assert_equal("/", environ["rouver.wildcard_path"])
            start_response("200 OK", [])
            return [b""]

        self.router.add_routes([("foo/bar/*", "GET", handle)])
        self.handle_wsgi("GET", "/foo/bar/")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def wildcard_path__additional_path(self) -> None:
        def handle(environ: WSGIEnvironment,
                   start_response: StartResponse) -> Iterable[bytes]:
            assert_equal([], environ["rouver.path_args"])
            assert_equal("/abc/def", environ["rouver.wildcard_path"])
            start_response("200 OK", [])
            return [b""]

        self.router.add_routes([("foo/bar/*", "GET", handle)])
        self.handle_wsgi("GET", "/foo/bar/abc/def")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def wildcard_path__with_template(self) -> None:
        def handle(environ: WSGIEnvironment,
                   start_response: StartResponse) -> Iterable[bytes]:
            assert_equal(["value"], environ["rouver.path_args"])
            assert_equal("/abc/def", environ["rouver.wildcard_path"])
            start_response("200 OK", [])
            return [b""]

        self.router.add_template_handler("bar", lambda *args: "value")
        self.router.add_routes([("foo/{bar}/*", "GET", handle)])
        self.handle_wsgi("GET", "/foo/unknown/abc/def")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def wildcard_path__too_short(self) -> None:
        self.router.add_routes([("foo/bar/*", "GET", handle_success)])
        self.handle_wsgi("GET", "/foo")
        self.start_response.assert_status(HTTPStatus.NOT_FOUND)

    @test
    def wildcard_path__does_not_match(self) -> None:
        self.router.add_routes([("foo/bar/*", "GET", handle_success)])
        self.handle_wsgi("GET", "/foo/wrong")
        self.start_response.assert_status(HTTPStatus.NOT_FOUND)

    @test
    def wildcard_path__not_at_end(self) -> None:
        with assert_raises(ValueError):
            self.router.add_routes([("foo/*/bar", "GET", handle_success)])

    @test
    def wildcard__before_more_specific(self) -> None:
        self.router.add_routes([
            ("foo/*", "GET", handle_success),
            ("foo/bar", "GET", fail_if_called),
        ])
        self.handle_wsgi("GET", "/foo/bar")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def wildcard__after_more_specific(self) -> None:
        self.router.add_routes([
            ("foo/bar", "GET", handle_success),
            ("foo/*", "GET", fail_if_called),
        ])
        self.handle_wsgi("GET", "/foo/bar")
        self.start_response.assert_status(HTTPStatus.OK)

    # Sub routers

    @test
    def sub_router(self) -> None:
        sub = Router()
        sub.error_handling = False
        sub.add_routes([("sub", "GET", self._create_path_checker("/sub"))])
        self.router.add_sub_router("foo/bar", sub)
        self.handle_wsgi("GET", "/foo/bar/sub")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def sub_router__no_match(self) -> None:
        sub = Router()
        sub.error_handling = False
        sub.add_routes([("sub", "GET", fail_if_called)])
        self.router.add_sub_router("foo", sub)
        self.handle_wsgi("GET", "/wrong/sub")
        self.start_response.assert_status(HTTPStatus.NOT_FOUND)

    @test
    def sub_router__base_with_slash(self) -> None:
        sub = Router()
        sub.error_handling = False
        sub.add_routes([("", "GET", self._create_path_checker("/"))])
        self.router.add_sub_router("foo/bar", sub)
        self.handle_wsgi("GET", "/foo/bar/")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def sub_router__base_without_slash(self) -> None:
        sub = Router()
        sub.error_handling = False
        sub.add_routes([("", "GET", self._create_path_checker(""))])
        self.router.add_sub_router("foo/bar", sub)
        self.handle_wsgi("GET", "/foo/bar")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def sub_router__path_info(self) -> None:
        def app(env: WSGIEnvironment, sr: StartResponse) -> Iterable[bytes]:
            assert_equal("/foo", env["PATH_INFO"])
            assert_equal("/sub/foo", env["rouver.original_path_info"])
            sr("200 OK", [])
            return []

        self.router.error_handling = False
        self.router.add_sub_router("sub", app)
        self.handle_wsgi("GET", "/sub/foo")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def sub_router__path_info_encoding(self) -> None:
        expected_path = "/föo".encode("utf-8").decode("latin-1")

        def app(env: WSGIEnvironment, sr: StartResponse) -> Iterable[bytes]:
            assert_equal(expected_path, env["PATH_INFO"])
            sr("200 OK", [])
            return []

        self.router.error_handling = False
        self.router.add_sub_router("sub", app)
        self.handle_wsgi("GET", "/sub/föo".encode("utf-8").decode("latin-1"))
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def sub_router__template_in_super_router(self) -> None:
        def handle(environ: WSGIEnvironment,
                   start_response: StartResponse) -> Iterable[bytes]:
            assert_equal([], environ["rouver.path_args"])
            start_response("200 OK", [])
            return []

        def tmpl(_: Request, path: Sequence[str], v: str) -> str:
            assert_equal((), path)
            return v * 2

        sub = Router()
        sub.error_handling = False
        sub.add_template_handler("tmpl", tmpl)
        sub.add_routes([("sub", "GET", handle)])
        self.router.add_template_handler("tmpl", tmpl)
        self.router.add_sub_router("foo/{tmpl}", sub)
        self.handle_wsgi("GET", "/foo/bar/sub")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def sub_router__template_in_sub_router(self) -> None:
        def handle(environ: WSGIEnvironment,
                   start_response: StartResponse) -> Iterable[bytes]:
            assert_equal(["xyzxyz"], environ["rouver.path_args"])
            start_response("200 OK", [])
            return []

        def tmpl(_: Request, path: Sequence[str], v: str) -> str:
            assert_equal((), path)
            return v * 2

        sub = Router()
        sub.error_handling = False
        sub.add_template_handler("tmpl", tmpl)
        sub.add_routes([("{tmpl}", "GET", handle)])
        self.router.add_sub_router("foo/bar", sub)
        self.handle_wsgi("GET", "/foo/bar/xyz")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def sub_router__path_component(self) -> None:
        sub = Router()
        sub.error_handling = False
        sub.add_routes([("sub", "GET", handle_success)])
        self.router.add_sub_router("foo/bar", sub)
        self.handle_wsgi("GET", "/foo/barsub")
        self.start_response.assert_status(HTTPStatus.NOT_FOUND)

    @test
    def sub_router__match_after_other_routes(self) -> None:
        sub = Router()
        sub.error_handling = False
        sub.add_routes([("sub", "GET", fail_if_called)])
        self.router.add_routes([("foo/bar/sub", "GET", handle_success)])
        self.router.add_sub_router("foo/bar", sub)
        self.handle_wsgi("GET", "/foo/bar/sub")
        self.start_response.assert_status(HTTPStatus.OK)

    @test
    def sub_router__accepts_any_wsgi_app(self) -> None:
        def sub(environ: WSGIEnvironment, sr: StartResponse) -> WSGIResponse:
            assert_equal("/sub", environ["PATH_INFO"])
            sr("204 No Content", [])
            return []

        self.router.add_sub_router("foo/bar", sub)
        self.handle_wsgi("GET", "/foo/bar/sub")
        self.start_response.assert_status(HTTPStatus.NO_CONTENT)

    @test
    def sub_router__escaped_path(self) -> None:
        sub = Router()
        sub.error_handling = False
        sub.add_routes([("sub", "GET", self._create_path_checker("/s%75b"))])
        self.router.add_sub_router("foo/bar", sub)
        self.handle_wsgi("GET", "/foo/b%61r/s%75b")
        self.start_response.assert_status(HTTPStatus.OK)

    # Error Handling

    @test
    def internal_error_page(self) -> None:
        def handle(_: WSGIEnvironment, __: StartResponse) -> Iterable[bytes]:
            raise KeyError("Custom < error")

        self.router.error_handling = True
        self.router.add_routes([("foo", "GET", handle)])
        response = self.handle_wsgi("GET", "/foo")
        html = b"".join(response).decode("utf-8")
        assert_equal(
            """<!DOCTYPE html>
<html>
    <head>
        <title>500 &#x2014; Internal Server Error</title>
    </head>
    <body>
        <h1>500 &#x2014; Internal Server Error</h1>
        <p>Internal server error.</p>
    </body>
</html>
""",
            html,
        )

    @test
    def template_key_error_with_error_handling(self) -> None:
        def raise_key_error(_: Request, __: Sequence[str], ___: str) -> None:
            raise KeyError()

        self.router.add_template_handler("handler", raise_key_error)

        self.router.add_routes([("foo/{handler}/bar", "GET", fail_if_called)])
        self.router.error_handling = True
        self.handle_wsgi("GET", "/foo/xyz/bar")
        self.start_response.assert_status(HTTPStatus.INTERNAL_SERVER_ERROR)

    @test
    def template_key_error_without_error_handling(self) -> None:
        def raise_key_error(_: Request, __: Sequence[str], ___: str) -> None:
            raise KeyError()

        self.router.add_template_handler("handler", raise_key_error)

        self.router.add_routes([("foo/{handler}/bar", "GET", fail_if_called)])
        self.router.error_handling = False
        with assert_raises(KeyError):
            self.handle_wsgi("GET", "/foo/xyz/bar")

    @test
    def handler_key_error_with_error_handling(self) -> None:
        def handle(_: WSGIEnvironment, __: StartResponse) -> Iterable[bytes]:
            raise KeyError()

        self.router.error_handling = True
        self.router.add_routes([("foo", "GET", handle)])
        self.handle_wsgi("GET", "/foo")
        self.start_response.assert_status(HTTPStatus.INTERNAL_SERVER_ERROR)

    @test
    def handler_key_error_without_error_handling(self) -> None:
        def handle(_: WSGIEnvironment, __: StartResponse) -> Iterable[bytes]:
            raise KeyError()

        self.router.add_routes([("foo", "GET", handle)])
        self.router.error_handling = False
        with assert_raises(KeyError):
            self.handle_wsgi("GET", "/foo")

    @test
    def http_error(self) -> None:
        def handle(_: WSGIEnvironment, __: StartResponse) -> Iterable[bytes]:
            raise Unauthorized("Foo < Bar",
                               www_authenticate=WWWAuthenticate("Test"))

        self.router.error_handling = False
        self.router.add_routes([("foo", "GET", handle)])
        response = self.handle_wsgi("GET", "/foo")
        self.start_response.assert_status(HTTPStatus.UNAUTHORIZED)
        self.start_response.assert_header_equals("Content-Type",
                                                 "text/html; charset=utf-8")
        self.start_response.assert_header_equals("WWW-Authenticate", "Test ")
        html = b"".join(response).decode("utf-8")
        assert_equal(
            """<!DOCTYPE html>
<html>
    <head>
        <title>401 &#x2014; Unauthorized</title>
    </head>
    <body>
        <h1>401 &#x2014; Unauthorized</h1>
        <p>Foo &lt; Bar</p>
    </body>
</html>
""",
            html,
        )

    @test
    def arguments_error(self) -> None:
        def handle(_: WSGIEnvironment, __: StartResponse) -> Iterable[bytes]:
            raise ArgumentsError({"foo": "bar"})

        self.router.add_routes([("foo", "GET", handle)])
        response = self.handle_wsgi("GET", "/foo")
        self.start_response.assert_status(HTTPStatus.BAD_REQUEST)
        html = b"".join(response).decode("utf-8")
        assert html.startswith("<!DOCTYPE html>")
        assert_regex(
            html,
            r'<li class="argument">\s*'
            r'<span class="argument-name">foo</span>:\s*'
            r'<span class="error-message">bar</span>\s*'
            r"</li>",
        )
Exemple #5
0
 def default_content_type(self) -> None:
     sr = StubStartResponse()
     respond_with_content(sr, b"")
     sr.assert_header_equals("Content-Type", "application/octet-stream")
Exemple #6
0
 def default_status(self) -> None:
     sr = StubStartResponse()
     respond_with_content(sr, b"")
     sr.assert_status(HTTPStatus.OK)
Exemple #7
0
 def content_type(self) -> None:
     sr = StubStartResponse()
     respond(sr, content_type="image/png")
     sr.assert_header_equals("Content-Type", "image/png")
Exemple #8
0
class SeeOtherTest(TestCase):
    @before
    def setup_environment(self) -> None:
        self.environment = default_environment()
        self.start_response = StubStartResponse()

    @test
    def headers(self) -> None:
        self.environment["SERVER_NAME"] = "www.example.com"
        request = Request(self.environment)
        see_other(request, self.start_response, "/foo/bar")
        self.start_response.assert_status(HTTPStatus.SEE_OTHER)
        self.start_response.assert_header_equals("Content-Type",
                                                 "text/html; charset=utf-8")
        self.start_response.assert_header_equals(
            "Location", "http://www.example.com/foo/bar")

    @test
    def absolute_url(self) -> None:
        request = Request(self.environment)
        see_other(request, self.start_response, "http://example.com/foo")
        self.start_response.assert_header_equals("Location",
                                                 "http://example.com/foo")

    @test
    def url_without_leading_slash(self) -> None:
        self.environment["SERVER_NAME"] = "www.example.com"
        self.environment["PATH_INFO"] = "/abc/def/"
        request = Request(self.environment)
        see_other(request, self.start_response, "foo/bar")
        self.start_response.assert_header_equals(
            "Location", "http://www.example.com/abc/def/foo/bar")

    @test
    def url_path_without_trailing_slash(self) -> None:
        self.environment["SERVER_NAME"] = "www.example.com"
        self.environment["PATH_INFO"] = "/abc/def"
        request = Request(self.environment)
        see_other(request, self.start_response, "foo/bar")
        self.start_response.assert_header_equals(
            "Location", "http://www.example.com/abc/foo/bar")

    @test
    def umlauts_in_url(self) -> None:
        self.environment["SERVER_NAME"] = "www.example.com"
        request = Request(self.environment)
        see_other(request, self.start_response, "foo/bär")
        self.start_response.assert_header_equals(
            "Location", "http://www.example.com/foo/b%C3%A4r")

    @test
    def extra_headers(self) -> None:
        request = Request(self.environment)
        see_other(
            request,
            self.start_response,
            "foo",
            extra_headers=[("X-Foo", "Bar")],
        )
        self.start_response.assert_header_equals("X-Foo", "Bar")

    @test
    def html(self) -> None:
        request = Request(self.environment)
        response = see_other(request, self.start_response, "foo/bar")
        html = b"".join(response).decode("utf-8")
        assert html.startswith("<!DOCTYPE html>")
        assert_in("http://www.example.com/foo/bar", html)
Exemple #9
0
 def content_length(self) -> None:
     sr = StubStartResponse()
     respond_with_html(sr, "<div>Test</div>")
     sr.assert_header_equals("Content-Length", "15")
Exemple #10
0
 def content_type(self) -> None:
     sr = StubStartResponse()
     respond_with_html(sr, "<div>Test</div>")
     sr.assert_header_equals("Content-Type", "text/html; charset=utf-8")
Exemple #11
0
 def custom_status(self) -> None:
     sr = StubStartResponse()
     respond_with_html(sr,
                       "<div>Test</div>",
                       status=HTTPStatus.NOT_ACCEPTABLE)
     sr.assert_status(HTTPStatus.NOT_ACCEPTABLE)
Exemple #12
0
 def default_status(self) -> None:
     sr = StubStartResponse()
     respond_with_html(sr, "<div>Test</div>")
     sr.assert_status(HTTPStatus.OK)
Exemple #13
0
 def json_as_object(self) -> None:
     sr = StubStartResponse()
     response = respond_with_json(sr, {"föo": 3})
     assert_equal(b'{"f\\u00f6o": 3}', b"".join(response))
Exemple #14
0
 def json_as_str(self) -> None:
     sr = StubStartResponse()
     response = respond_with_json(sr, '{"föo": 3}')
     assert_equal('{"föo": 3}'.encode("utf-8"), b"".join(response))
Exemple #15
0
 def json_as_bytes(self) -> None:
     sr = StubStartResponse()
     response = respond_with_json(sr, b'{"foo": 3}')
     assert_equal(b'{"foo": 3}', b"".join(response))
Exemple #16
0
class TemporaryRedirectTest(TestCase):
    @before
    def setup_environment(self) -> None:
        self.environment = default_environment()
        self.start_response = StubStartResponse()

    @test
    def headers(self) -> None:
        self.environment["SERVER_NAME"] = "www.example.com"
        request = Request(self.environment)
        temporary_redirect(request, self.start_response, "/foo/bar")
        self.start_response.assert_status(HTTPStatus.TEMPORARY_REDIRECT)
        self.start_response.assert_header_equals("Content-Type",
                                                 "text/html; charset=utf-8")
        self.start_response.assert_header_equals(
            "Location", "http://www.example.com/foo/bar")

    @test
    def absolute_url(self) -> None:
        request = Request(self.environment)
        temporary_redirect(request, self.start_response,
                           "http://example.com/foo")
        self.start_response.assert_header_equals("Location",
                                                 "http://example.com/foo")

    @test
    def url_without_leading_slash(self) -> None:
        self.environment["SERVER_NAME"] = "www.example.com"
        request = Request(self.environment)
        temporary_redirect(request, self.start_response, "foo/bar")
        self.start_response.assert_header_equals(
            "Location", "http://www.example.com/foo/bar")

    @test
    def umlauts_in_url(self) -> None:
        self.environment["SERVER_NAME"] = "www.example.com"
        request = Request(self.environment)
        temporary_redirect(request, self.start_response, "foo/bär")
        self.start_response.assert_header_equals(
            "Location", "http://www.example.com/foo/b%C3%A4r")

    @test
    def do_not_encode_cgi_arguments(self) -> None:
        self.environment["SERVER_NAME"] = "www.example.com"
        request = Request(self.environment)
        temporary_redirect(request, self.start_response,
                           "foo?bar=baz&abc=%6A;+,@:$")
        self.start_response.assert_header_equals(
            "Location", "http://www.example.com/foo?bar=baz&abc=%6A;+,@:$")

    @test
    def extra_headers(self) -> None:
        request = Request(self.environment)
        temporary_redirect(
            request,
            self.start_response,
            "foo",
            extra_headers=[("X-Foo", "Bar")],
        )
        self.start_response.assert_header_equals("X-Foo", "Bar")

    @test
    def html(self) -> None:
        request = Request(self.environment)
        response = temporary_redirect(request, self.start_response, "foo/bar")
        html = b"".join(response).decode("utf-8")
        assert html.startswith("<!DOCTYPE html>")
        assert_in("http://www.example.com/foo/bar", html)
Exemple #17
0
 def no_content_type(self) -> None:
     sr = StubStartResponse()
     respond(sr)
     sr.assert_header_missing("Content-Type")
Exemple #18
0
 def return_value(self) -> None:
     sr = StubStartResponse()
     response = respond_with_html(sr, "<div>Test</div>")
     assert_equal(b"<div>Test</div>", b"".join(response))
Exemple #19
0
 def setup_environment(self) -> None:
     self.environment = default_environment()
     self.start_response = StubStartResponse()
Exemple #20
0
 def return_value_encoding(self) -> None:
     sr = StubStartResponse()
     response = respond_with_html(sr, "<div>Täst</div>")
     assert_equal("<div>Täst</div>".encode("utf-8"), b"".join(response))
Exemple #21
0
 def content_type_in_extra_headers(self) -> None:
     sr = StubStartResponse()
     respond(sr, extra_headers=[("Content-Type", "image/png")])
     sr.assert_header_equals("Content-Type", "image/png")
Exemple #22
0
 def default_status(self) -> None:
     sr = StubStartResponse()
     respond(sr)
     sr.assert_status(HTTPStatus.OK)
Exemple #23
0
 def response(self) -> None:
     sr = StubStartResponse()
     response = respond(sr)
     assert_equal(b"", b"".join(response))
Exemple #24
0
class CreatedAtTest(TestCase):
    @before
    def setup_environment(self) -> None:
        self.environment = default_environment()
        self.start_response = StubStartResponse()

    @test
    def headers(self) -> None:
        self.environment["SERVER_NAME"] = "www.example.com"
        request = Request(self.environment)
        created_at(request, self.start_response, "/foo/bar")
        self.start_response.assert_status(HTTPStatus.CREATED)
        self.start_response.assert_header_equals("Content-Type",
                                                 "text/html; charset=utf-8")
        self.start_response.assert_header_equals(
            "Location", "http://www.example.com/foo/bar")

    @test
    def absolute_url(self) -> None:
        request = Request(self.environment)
        created_at(request, self.start_response, "http://example.com/foo")
        self.start_response.assert_header_equals("Location",
                                                 "http://example.com/foo")

    @test
    def url_without_leading_slash(self) -> None:
        self.environment["SERVER_NAME"] = "www.example.com"
        request = Request(self.environment)
        created_at(request, self.start_response, "foo/bar")
        self.start_response.assert_header_equals(
            "Location", "http://www.example.com/foo/bar")

    @test
    def umlauts_in_url(self) -> None:
        self.environment["SERVER_NAME"] = "www.example.com"
        request = Request(self.environment)
        created_at(request, self.start_response, "foo/bär")
        self.start_response.assert_header_equals(
            "Location", "http://www.example.com/foo/b%C3%A4r")

    @test
    def extra_headers(self) -> None:
        request = Request(self.environment)
        created_at(
            request,
            self.start_response,
            "foo",
            extra_headers=[("X-Foo", "Bar")],
        )
        self.start_response.assert_header_equals("X-Foo", "Bar")

    @test
    def html(self) -> None:
        request = Request(self.environment)
        response = created_at(request, self.start_response, "foo/bar")
        html = b"".join(response).decode("utf-8")
        assert html.startswith("<!DOCTYPE html>")
Exemple #25
0
 def custom_status(self) -> None:
     sr = StubStartResponse()
     respond_with_content(sr, b"", status=HTTPStatus.NOT_ACCEPTABLE)
     sr.assert_status(HTTPStatus.NOT_ACCEPTABLE)
Exemple #26
0
class CreatedAsJSONTest(TestCase):
    @before
    def setup_environment(self) -> None:
        self.environment = default_environment()
        self.start_response = StubStartResponse()

    @test
    def headers(self) -> None:
        self.environment["SERVER_NAME"] = "www.example.com"
        request = Request(self.environment)
        created_as_json(request, self.start_response, "/foo/bar", {})
        self.start_response.assert_status(HTTPStatus.CREATED)
        self.start_response.assert_header_equals(
            "Content-Type", "application/json; charset=utf-8")
        self.start_response.assert_header_equals(
            "Location", "http://www.example.com/foo/bar")

    @test
    def absolute_url(self) -> None:
        request = Request(self.environment)
        created_as_json(request, self.start_response, "http://example.com/foo",
                        {})
        self.start_response.assert_header_equals("Location",
                                                 "http://example.com/foo")

    @test
    def url_without_leading_slash(self) -> None:
        self.environment["SERVER_NAME"] = "www.example.com"
        request = Request(self.environment)
        created_as_json(request, self.start_response, "foo/bar", {})
        self.start_response.assert_header_equals(
            "Location", "http://www.example.com/foo/bar")

    @test
    def umlauts_in_url(self) -> None:
        self.environment["SERVER_NAME"] = "www.example.com"
        request = Request(self.environment)
        created_as_json(request, self.start_response, "foo/bär", {})
        self.start_response.assert_header_equals(
            "Location", "http://www.example.com/foo/b%C3%A4r")

    @test
    def extra_headers(self) -> None:
        request = Request(self.environment)
        created_as_json(
            request,
            self.start_response,
            "foo",
            {},
            extra_headers=[("X-Foo", "Bar")],
        )
        self.start_response.assert_header_equals("X-Foo", "Bar")

    @test
    def json(self) -> None:
        request = Request(self.environment)
        response = created_as_json(request, self.start_response, "foo/bar",
                                   {"foo": 3})
        json = json_decode(b"".join(response).decode("utf-8"))
        assert_equal({"foo": 3}, json)
Exemple #27
0
 def custom_content_type(self) -> None:
     sr = StubStartResponse()
     respond_with_content(sr, b"", content_type="text/plain")
     sr.assert_header_equals("Content-Type", "text/plain")
Exemple #28
0
 def extra_headers(self) -> None:
     sr = StubStartResponse()
     respond(sr, extra_headers=[("X-Custom-Header", "Foobar")])
     sr.assert_header_equals("X-Custom-Header", "Foobar")
Exemple #29
0
 def setup_router(self) -> None:
     self.router = Router()
     self.router.error_handling = False
     self.start_response = StubStartResponse()
     self.environment = default_environment()
     self.disable_logger()
Exemple #30
0
 def content_type(self) -> None:
     sr = StubStartResponse()
     respond_with_json(sr, {})
     sr.assert_header_equals("Content-Type",
                             "application/json; charset=utf-8")