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"]