From 772a178c116845628f371899726f71ea0aa94ab0 Mon Sep 17 00:00:00 2001 From: Daniel Dolezal Date: Sun, 6 Sep 2026 02:57:37 +0200 Subject: [PATCH] fix(observability): bump quart_common and refresh stale error tests - Bump quart_common to 53b7599 with the httpx request-less crash fix - The global exception handler no longer dies on RequestError without request - Expect 503 for Convex connect failures, 504 is reserved for timeouts - Add an API timeout case so the 504 branch stays covered - Register a link_composer blueprint so error.htm can render its navigation - Move the legacy logger assertion into a WIDE_EVENT_ENABLED=false test - Assert user.session_age_seconds instead of the removed session.age_seconds - Expect no legacy middleware logs while wide-event logging is active The middleware moved into quart_common's register_security_middleware, so the NanoShare copies of those assertions had been describing pre-refactor behaviour. Suite is green again at 141 passed. --- quart_common | 2 +- tests/test_database_error_handler.py | 40 +++++++++++++++++++++++++++- tests/test_wide_event_nanoshare.py | 5 ++-- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/quart_common b/quart_common index d61514d..53b7599 160000 --- a/quart_common +++ b/quart_common @@ -1 +1 @@ -Subproject commit d61514d755c00f920d9b1a552d05a10ae2ff55cd +Subproject commit 53b759919331381d15992414ab928baec54d2baa diff --git a/tests/test_database_error_handler.py b/tests/test_database_error_handler.py index 9750bb2..a2410c6 100644 --- a/tests/test_database_error_handler.py +++ b/tests/test_database_error_handler.py @@ -77,6 +77,10 @@ def register_template_routes(app): auth_login.add_url_rule("/logout", "logout", index) app.register_blueprint(auth_login) + link_composer = Blueprint("link_composer", __name__) + link_composer.add_url_rule("/links", "link_composer_page", index) + app.register_blueprint(link_composer) + def load_errors_and_basics(monkeypatch, app): logger = FakeLogger() @@ -96,7 +100,24 @@ def test_convex_connect_error_is_returned_as_global_database_error(monkeypatch): response = await app.test_client().get("/favicon.ico") - assert response.status_code == 504 + assert response.status_code == 503 + assert response.headers["Retry-After"] + assert logger.errors == [] + + asyncio.run(run_test()) + +def test_convex_connect_error_uses_legacy_logger_when_wide_events_are_disabled(monkeypatch): + async def run_test(): + monkeypatch.setenv("WIDE_EVENT_ENABLED", "false") + app = Quart(__name__, template_folder=str(Path(__file__).resolve().parents[1] / "templates" / "side")) + register_template_routes(app) + app.convex = FailingConvex() + _errors, basics, logger = load_errors_and_basics(monkeypatch, app) + app.register_blueprint(basics.basic_bp) + + response = await app.test_client().get("/favicon.ico") + + assert response.status_code == 503 assert any("Name or service not known" in str(error) for error in logger.errors) asyncio.run(run_test()) @@ -113,6 +134,23 @@ def test_api_convex_connect_error_returns_json_database_error(monkeypatch): response = await app.test_client().get("/api/failing") payload = await response.get_json() + assert response.status_code == 503 + assert payload["error"] == "Database Error" + + asyncio.run(run_test()) + +def test_api_convex_timeout_returns_gateway_timeout(monkeypatch): + async def run_test(): + app = Quart(__name__, template_folder=str(Path(__file__).resolve().parents[1] / "templates" / "side")) + load_errors_and_basics(monkeypatch, app) + + @app.get("/api/slow") + async def slow_api(): + raise httpx.ReadTimeout("convex took too long") + + response = await app.test_client().get("/api/slow") + payload = await response.get_json() + assert response.status_code == 504 assert payload["error"] == "Database Error" diff --git a/tests/test_wide_event_nanoshare.py b/tests/test_wide_event_nanoshare.py index bf28e6c..31b64bc 100644 --- a/tests/test_wide_event_nanoshare.py +++ b/tests/test_wide_event_nanoshare.py @@ -98,7 +98,8 @@ def test_middleware_adds_user_and_client_context(monkeypatch): assert "authenticated" not in g.wide_event["session"] assert g.wide_event["session"]["permanent"] is True assert g.wide_event["session"]["login_at_unix"] == 1 - assert g.wide_event["session"]["age_seconds"] >= 0 + assert "age_seconds" not in g.wide_event["session"] + assert g.wide_event["user"]["session_age_seconds"] >= 0 assert g.wide_event["client"]["ip"] == "203.0.113.10" asyncio.run(run_test()) @@ -143,6 +144,6 @@ def test_middleware_records_convex_security_failures(monkeypatch): assert g.wide_event["client"]["ip"] == "203.0.113.12" assert g.wide_event["security"] == {"ip_lookup_failed": True} assert g.wide_event["error"]["type"] == "RuntimeError" - assert fake_logger.records == [("error", "[MIDDLEWARE] Convex ip_lookup failed: convex down")] + assert fake_logger.records == [] asyncio.run(run_test())