Skip to content

tests/core/test_server_application.py

Source from this local checkout, regenerated when the reader rebuilds. Line links use #L<number>; a GitHub line range opens its first line.

1 # Copyright 2025 Softwell S.r.l.2 #3 # Licensed under the Apache License, Version 2.0 (the "License");4 # you may not use this file except in compliance with the License.5 # You may obtain a copy of the License at6 #7 #     https://www.apache.org/licenses/LICENSE-2.08 #9 # Unless required by applicable law or agreed to in writing, software10 # distributed under the License is distributed on an "AS IS" BASIS,11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12 # See the License for the specific language governing permissions and13 # limitations under the License.14 15 """Tests for ``ServerApplication`` and the automatic ``_server`` mount (D4)."""16 17 from __future__ import annotations18 19 import json20 21 from genro_routes import RoutingClass, route22 23 from genro_asgi import AsgiServer, BaseApplication, ServerApplication24 25 26 class DemoSection(RoutingClass):27     """A tiny system section to exercise ``attach_section``."""28 29     def __init__(self, application: ServerApplication) -> None:30         self.application = application31 32     @route()33     def ping(self) -> dict[str, bool]:34         return {"pong": True}35 36 37 class TestAutoMount:38     def test_hand_built_server_registers_the_server_app(self) -> None:39         server = AsgiServer(applications=[BaseApplication(mount="")])40         assert "_server" in server.applications41         app = server.applications["_server"]42         assert isinstance(app, ServerApplication)43         assert app.mount == "_server"44         assert app.server is server45 46     def test_registration_hook_is_idempotent(self) -> None:47         server = AsgiServer(applications=[BaseApplication(mount="")])48         app = server.applications["_server"]49         server._register_server_app()50         assert server.applications["_server"] is app51 52     def test_identity_is_declared_on_the_class(self) -> None:53         # D4: the system code and mount are declared, not configured — three54         # cross-file references hardcode /_server/..., so moving the app would55         # 404 them silently.56         app = ServerApplication()57         assert (app.code, app.mount) == ("_server", "_server")58 59 60 class TestServerEndpoints:61     async def test_index_answers_at_server_root(62         self, http_request, response_status, response_body63     ) -> None:64         server = AsgiServer(applications=[BaseApplication(mount="")])65         sent = await http_request(server, "/_server/")66         assert response_status(sent) == 20067         data = json.loads(response_body(sent))68         assert data["sections"] == ["auth", "monitor", "tasks", "tokens", "users"]69 70     async def test_meta_schema_json_is_exposed(71         self, http_request, response_status, response_body72     ) -> None:73         server = AsgiServer(applications=[BaseApplication(mount="")])74         sent = await http_request(server, "/_server/_meta/schema_json")75         assert response_status(sent) == 20076         doc = json.loads(response_body(sent))77         assert doc["openapi"] == "3.1.0"78         assert doc["info"]["title"] == "genro-asgi server endpoints"79 80     async def test_login_schema_hides_the_injected_request_and_is_post(81         self, http_request, response_body82     ) -> None:83         # REVIEW #6: the injected ``_request`` must NOT surface in the public84         # request body, and the route is POST by declaration (openapi_method).85         server = AsgiServer(applications=[BaseApplication(mount="")])86         sent = await http_request(server, "/_server/_meta/schema_json")87         doc = json.loads(response_body(sent))88         login = doc["paths"]["/login"]89         assert set(login) == {"post"}90         props = login["post"]["requestBody"]["content"]["application/json"]["schema"][91             "properties"92         ]93         assert set(props) == {"identity", "password"}94         assert "_request" not in props and "request" not in props95 96 97 class TestDocs:98     async def test_server_serves_the_docs_page(self, http_request, response_status) -> None:99         server = AsgiServer(applications=[BaseApplication(mount="")])100         sent = await http_request(server, "/_server/_meta/docs")101         assert response_status(sent) == 200102 103 104 class TestSections:105     async def test_attach_section_registers_and_routes(106         self, http_request, response_status, response_body107     ) -> None:108         server = AsgiServer(applications=[BaseApplication(mount="")])109         app = server.applications["_server"]110         assert isinstance(app, ServerApplication)111         app.attach_section(DemoSection(app), name="demo")112         assert app.sections["demo"] is not None113         sent = await http_request(server, "/_server/demo/ping")114         assert response_status(sent) == 200115         assert json.loads(response_body(sent)) == {"pong": True}116         sent = await http_request(server, "/_server/")117         data = json.loads(response_body(sent))118         assert data["sections"] == ["auth", "demo", "monitor", "tasks", "tokens", "users"]