async def test_file_response_from_bytes_io(): app = FakeApplication() bytes_io: Optional[BytesIO] = None @app.router.get("/") async def home(): nonlocal bytes_io bytes_io = BytesIO() bytes_io.write("Żywią i bronią".encode("utf-8")) return file(bytes_io, "text/plain; charset=utf-8", file_name="foo.txt") app.normalize_handlers() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) response = app.response assert response.status == 200 assert response.headers.get_single(b"content-type") == b"text/plain; charset=utf-8" assert ( response.headers.get_single(b"content-disposition") == b'attachment; filename="foo.txt"' ) assert bytes_io is not None assert bytes_io.closed # type: ignore
async def test_pretty_json_response(obj: Any, values: Dict[str, Any]): app = FakeApplication() @app.router.get("/") async def home(): return pretty_json(obj) app.normalize_handlers() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) response = app.response assert response.status == 200 content_type = response.headers.get_single(b"content-type") assert content_type == b"application/json" raw = await response.text() data = await response.json() for name, value in values.items(): assert data.get(name) == value if isinstance(value, str): assert f' "{name}": "{value}"' in raw else: assert f' "{name}": ' in raw
async def test_serve_files_with_custom_files_handler(): app = FakeApplication() file_path = files2_index_path with open(file_path, mode="rt") as actual_file: expected_body = actual_file.read() class CustomFilesHandler(FilesHandler): def __init__(self) -> None: self.calls = [] def open(self, file_path: str, mode: str = "rb") -> FileContext: self.calls.append(file_path) return super().open(file_path, mode) app.files_handler = CustomFilesHandler() folder_path = get_folder_path("files2") app.serve_files(ServeFilesOptions(folder_path, discovery=True)) await app.start() scope = get_example_scope("GET", "/index.html", []) await app( scope, MockReceive(), MockSend(), ) response = app.response assert response.status == 200 body = await response.text() assert body == expected_body assert app.files_handler.calls[0] == file_path
async def test_status_method_response_in_controller(method, expected_status): app = FakeApplication() app.controllers_router = RoutesRegistry() get = app.controllers_router.get method_name = method.__name__ class Home(Controller): @get("/") def greet(self): controller_method = getattr(Home, method_name, None) return controller_method(self, "Everything's good") controller_method = getattr(Home, method_name, None) assert callable(controller_method) await app.start() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) assert app.response.status == expected_status content = await app.response.text() assert content == "Everything's good"
async def test_file_response_from_fs_with_filename(): app = FakeApplication() file_path = get_file_path("example.config", "files2") @app.router.get("/") async def home(): return file(file_path, "text/plain; charset=utf-8", file_name="foo.xml") app.normalize_handlers() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) response = app.response assert response.status == 200 assert response.headers.get_single(b"content-type") == b"text/plain; charset=utf-8" assert ( response.headers.get_single(b"content-disposition") == b'attachment; filename="foo.xml"' ) text = await response.text() with open(file_path, mode="rt", encoding="utf8") as f: contents = f.read() assert contents == text
async def test_redirect_method_in_controller(method, expected_status): app = FakeApplication() app.controllers_router = RoutesRegistry() get = app.controllers_router.get method_name = method.__name__ class Home(Controller): @get("/") def greet(self): controller_method = getattr(Home, method_name, None) return controller_method(self, "https://foo.org/somewhere") controller_method = getattr(Home, method_name, None) assert callable(controller_method) await app.start() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) response = app.response assert response.status == expected_status location = response.headers.get_single(b"location") assert location == b"https://foo.org/somewhere"
async def test_pretty_json_response_in_controller(obj: Any, values: Dict[str, Any]): app = FakeApplication() app.controllers_router = RoutesRegistry() get = app.controllers_router.get class Home(Controller): @get("/") def greet(self): return self.pretty_json(obj) await app.start() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) response = app.response raw = await response.text() assert response.status == 200 content_type = response.headers.get_single(b"content-type") assert content_type == b"application/json" raw = await response.text() data = await response.json() for name, value in values.items(): assert data.get(name) == value if isinstance(value, str): assert f' "{name}": "{value}"' in raw else: assert f' "{name}": ' in raw
async def test_file_response_from_generator_inline_with_name(): app = FakeApplication() @app.router.get("/") async def home(): return file( get_example_css, "text/css", file_name="home.css", content_disposition=ContentDispositionType.INLINE, ) app.normalize_handlers() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) response = app.response assert response.status == 200 assert response.headers.get_single(b"content-type") == b"text/css" assert ( response.headers.get_single(b"content-disposition") == b'inline; filename="home.css"' ) text = await response.text() assert text == await read_from_asynciterable(get_example_css)
async def test_status_method_without_body_response_in_controller( method, expected_status ): app = FakeApplication() app.controllers_router = RoutesRegistry() get = app.controllers_router.get method_name = method.__name__ class Home(Controller): @get("/") def greet(self): controller_method = getattr(Home, method_name, None) return controller_method(self) controller_method = getattr(Home, method_name, None) assert callable(controller_method) await app.start() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) response = app.response assert response.status == expected_status assert response.has_body() is False
async def test_serve_files_discovery(folder_name: str): app = FakeApplication() folder_path = get_folder_path(folder_name) options = ServeFilesOptions(folder_path, discovery=True) app.serve_files(options) await app.start() scope = get_example_scope("GET", "/", []) await app( scope, MockReceive(), MockSend(), ) response = app.response assert response.status == 200 body = await response.text() folder = Path(folder_path) for item in folder.iterdir(): if item.is_dir(): assert f"/{item.name}" in body continue file_extension = get_file_extension(str(item)) if file_extension in options.extensions: assert f"/{item.name}" in body else: assert item.name not in body
async def test_created_response_with_value(): app = FakeApplication() @app.router.get("/") async def home(): return created( Foo(UUID("726807b3-5a82-4a59-8bed-65639d3529ba"), "example", False), location="https://foo.org/foo/726807b3-5a82-4a59-8bed-65639d3529ba", ) app.normalize_handlers() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) response = app.response assert response.status == 201 location = response.headers.get_single(b"location") assert location == b"https://foo.org/foo/726807b3-5a82-4a59-8bed-65639d3529ba" content = await app.response.json() assert content.get("id") == "726807b3-5a82-4a59-8bed-65639d3529ba" assert content.get("name") == "example" assert content.get("ufo") is False
async def test_can_serve_files_with_relative_paths(files2_index_contents): app = FakeApplication() folder_path = get_folder_path("files2") options = ServeFilesOptions(folder_path, discovery=True) app.serve_files(options) await app.start() scope = get_example_scope("GET", "/styles/../index.html", []) await app( scope, MockReceive(), MockSend(), ) response = app.response assert response.status == 200 body = await response.read() assert body == files2_index_contents scope = get_example_scope("GET", "/styles/fonts/../../index.html", []) await app( scope, MockReceive(), MockSend(), ) response = app.response assert response.status == 200 body = await response.read() assert body == files2_index_contents scope = get_example_scope("GET", "/styles/../does-not-exist.html", []) await app( scope, MockReceive(), MockSend(), ) response = app.response assert response.status == 404
async def test_serve_files_can_disable_index_html_by_default(): app = FakeApplication() app.serve_files(get_folder_path("files2"), index_document=None) await app.start() scope = get_example_scope("GET", "/", []) await app( scope, MockReceive(), MockSend(), ) response = app.response assert response.status == 404
async def test_serve_files_serves_index_html_by_default(files2_index_contents): app = FakeApplication() app.serve_files(ServeFilesOptions(get_folder_path("files2"))) await app.start() scope = get_example_scope("GET", "/", []) await app( scope, MockReceive(), MockSend(), ) response = app.response assert response.status == 200 assert files2_index_contents == await response.read()
async def test_serve_files_no_discovery(): app = FakeApplication() # Note the folder files3 does not contain an index.html page app.serve_files(ServeFilesOptions(get_folder_path("files3"))) await app.start() scope = get_example_scope("GET", "/", []) await app( scope, MockReceive(), MockSend(), ) response = app.response assert response.status == 404
async def test_cannot_serve_files_with_unhandled_extension(): app = FakeApplication() folder_path = get_folder_path("files2") app.serve_files(folder_path, discovery=True, extensions={".py"}) await app.start() scope = get_example_scope("GET", "/example.config", []) await app( scope, MockReceive(), MockSend(), ) response = app.response assert response.status == 404
async def test_cannot_serve_files_outside_static_folder(): app = FakeApplication() folder_path = get_folder_path("files") app.serve_files(folder_path, discovery=True, extensions={".py"}) await app.start() scope = get_example_scope("GET", "../test_files_serving.py", []) await app( scope, MockReceive(), MockSend(), ) response = app.response assert response.status == 404
async def test_status_code_response_with_empty_body(status: int): app = FakeApplication() @app.router.get("/") async def home(): return status_code(status) app.normalize_handlers() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) assert app.response.status == status content = await app.response.text() assert content == ""
async def test_status_method_response_empty_body(method, expected_status): app = FakeApplication() @app.router.get("/") async def home(): return method() app.normalize_handlers() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) assert app.response.status == expected_status content = await app.response.text() assert content == ""
async def test_no_body_method(method, expected_status): app = FakeApplication() @app.router.get("/") async def home(): return method() app.normalize_handlers() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) response = app.response assert response.status == expected_status assert response.has_body() is False
async def test_serve_files_deprecated_serve_files_options(files2_index_contents): app = FakeApplication() with pytest.deprecated_call(): app.serve_files(ServeFilesOptions(get_folder_path("files2"))) # type: ignore await app.start() scope = get_example_scope("GET", "/", []) await app( scope, MockReceive(), MockSend(), ) response = app.response assert response.status == 200 assert files2_index_contents == await response.read()
async def test_serve_files_fallback_document(files2_index_contents: bytes): """Feature used to serve SPAs that use HTML5 History API""" app = FakeApplication() app.serve_files(get_folder_path("files2"), fallback_document="index.html") await app.start() for path in {"/", "/one", "/one/two", "/one/two/anything.txt"}: scope = get_example_scope("GET", path, []) await app( scope, MockReceive(), MockSend(), ) response = app.response assert response.status == 200 assert await response.read() == files2_index_contents
async def test_redirect_method_bytes_location(method, expected_status): app = FakeApplication() @app.router.get("/") async def home(): return method(b"https://foo.org/somewhere") app.normalize_handlers() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) response = app.response assert response.status == expected_status location = response.headers.get_single(b"location") assert location == b"https://foo.org/somewhere"
async def test_status_code_response_with_object(status: int): app = FakeApplication() @app.router.get("/") async def home(): return status_code(status, Foo(uuid4(), "foo", True)) app.normalize_handlers() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) assert app.response.status == status content = await app.response.json() assert content.get("name") == "foo" assert content.get("ufo") is True
async def test_created_response_with_empty_body(): app = FakeApplication() @app.router.get("/") async def home(): return created(location="https://foo.org/foo/001") app.normalize_handlers() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) response = app.response assert response.status == 201 location = response.headers.get_single(b"location") assert location == b"https://foo.org/foo/001"
async def test_status_code_response_with_text_in_controller(status: int): app = FakeApplication() app.controllers_router = RoutesRegistry() get = app.controllers_router.get class Home(Controller): @get("/") def greet(self): return self.status_code(status, "Everything's good") await app.start() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) assert app.response.status == status content = await app.response.text() assert content == "Everything's good"
async def test_serve_files_custom_index_page(): app = FakeApplication() # Note the folder files3 does not contain an index.html page app.serve_files(get_folder_path("files3"), index_document="lorem-ipsum.txt") await app.start() scope = get_example_scope("GET", "/", []) await app( scope, MockReceive(), MockSend(), ) response = app.response assert response.status == 200 with open(get_file_path("lorem-ipsum.txt", "files3"), mode="rt") as actual_file: content = actual_file.read() assert content == await response.text()
async def test_serve_files_discovery_subfolder(): app = FakeApplication() folder_path = get_folder_path("files2") app.serve_files(ServeFilesOptions(folder_path, discovery=True)) await app.start() scope = get_example_scope("GET", "/scripts", []) await app( scope, MockReceive(), MockSend(), ) response = app.response assert response.status == 200 body = await response.text() folder = Path(folder_path) / "scripts" for item in folder.iterdir(): assert f"/{item.name}" in body
async def test_file_response_from_generator(): app = FakeApplication() @app.router.get("/") async def home(): return file(get_example_css, "text/css") app.normalize_handlers() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) response = app.response assert response.status == 200 assert response.headers.get_single(b"content-type") == b"text/css" assert response.headers.get_single(b"content-disposition") == b"attachment" text = await response.text() assert text == await read_from_asynciterable(get_example_css)
async def test_html_response_with_status(content, status): app = FakeApplication() @app.router.get("/") async def home(): return html(content, status) app.normalize_handlers() await app( get_example_scope("GET", "/", []), MockReceive(), MockSend(), ) response = app.response assert response.status == status content_type = response.headers.get_single(b"content-type") assert content_type == b"text/html; charset=utf-8" body = await response.text() assert body == content