Files
ss-tools/backend/tests/test_app_handlers.py
busya 9cb5717a78 fix(agent): auto-start scenario chat, robust HITL resume, strict service auth
- frontend: fix auto-start on dashboards->/agent navigation (undefined params
  ReferenceError), route initial connect through ConnectionManager with auto-retry,
  reset runModel on objectId change and failed recovery
- agent: fix closure-over-loop-variable bug in _inject_env_id_into_tools (env now
  resolved from request-local ContextVar; idempotent wrapping), make
  execute_dashboard_result.result_key optional, resilient checkpoint resume with
  ToolMessage repair + direct-tool fallback, remove dead fast-path, consolidate
  tool_call parsing in _tool_resolver, context-safe ContextVar resets
- backend: llm-config gated by strict service-only auth (no user-JWT fallback),
  tighten idempotent run reuse (dashboard/env/intent match + 6h staleness),
  terminal event transitions run.status to COMPLETED/FAILED/CANCELLED,
  null-safe metric parsing in dashboard query model
- run.sh/docker-compose: require SERVICE_JWT (random per-run secret) instead of
  public default
2026-08-06 18:26:50 +07:00

95 lines
3.9 KiB
Python

# #region Test.AppModule.Handlers [C:3] [TYPE Module] [SEMANTICS test,app,handlers,exceptions]
# @BRIEF Tests for app.py — global_exception_handler, network_error_handler.
# @RELATION BINDS_TO -> [App.AppModule]
# @TEST_EDGE: unhandled_exception -> returns 500 JSON with path
# @TEST_EDGE: network_error -> returns 503
# @TEST_INVARIANT: every_500_logged -> VERIFIED_BY: test_global_exception_handler_logs_and_returns_500
from pathlib import Path
import sys
import json
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
import pytest
from unittest.mock import MagicMock
from fastapi import Request, HTTPException
from fastapi.responses import JSONResponse
# #region _make_mock_request [C:1] [TYPE Function]
def _make_mock_request(method="GET", path="/api/test", client_host="127.0.0.1"):
req = MagicMock(spec=Request)
req.method = method
req.url = MagicMock()
req.url.path = path
req.client = MagicMock()
req.client.host = client_host
req.query_params = {}
return req
# #endregion _make_mock_request
class TestExceptionHandlers:
"""global_exception_handler and network_error_handler."""
# #region Test.AppModule.TestGlobalHandler500 [C:2] [TYPE Function]
@pytest.mark.asyncio
async def test_global_handler_500(self):
from src.app import global_exception_handler
request = _make_mock_request(method="POST", path="/api/break")
response = await global_exception_handler(request, ValueError("broke"))
assert isinstance(response, JSONResponse)
assert response.status_code == 500
body = json.loads(response.body)
assert body["detail"] == "Internal server error"
assert body["path"] == "/api/break"
# #endregion Test.AppModule.TestGlobalHandler500
# #region Test.AppModule.TestGlobalHandlerUnknownClient [C:2] [TYPE Function]
@pytest.mark.asyncio
async def test_global_handler_unknown_client(self):
from src.app import global_exception_handler
req = _make_mock_request()
req.client = None
response = await global_exception_handler(req, RuntimeError("no client"))
assert response.status_code == 500
# #endregion Test.AppModule.TestGlobalHandlerUnknownClient
# #region Test.AppModule.TestNetworkErrorHandler [C:2] [TYPE Function]
@pytest.mark.asyncio
async def test_network_error_handler(self):
from src.app import network_error_handler
from src.core.utils.network import NetworkError
request = _make_mock_request()
response = await network_error_handler(request, NetworkError("down"))
from starlette.responses import JSONResponse
assert isinstance(response, JSONResponse)
assert response.status_code == 503
body = json.loads(response.body)
assert "Environment unavailable" in body["detail"]
# #endregion Test.AppModule.TestNetworkErrorHandler
# #region Test.AppModule.TestGlobalHandlerWithQueryParams [C:2] [TYPE Function]
@pytest.mark.asyncio
async def test_global_handler_with_query_params(self):
from src.app import global_exception_handler
req = _make_mock_request()
req.query_params = {"env_id": "prod"}
response = await global_exception_handler(req, Exception("test"))
assert response.status_code == 500
# #endregion Test.AppModule.TestGlobalHandlerWithQueryParams
# #region Test.AppModule.TestInternalServerErrorReturnsJson [C:2] [TYPE Function]
@pytest.mark.asyncio
async def test_internal_server_error_returns_json(self):
from src.app import global_exception_handler
request = _make_mock_request(method="POST", path="/api/crash")
response = await global_exception_handler(request, RuntimeError("crash"))
assert response.status_code == 500
body = json.loads(response.body)
assert body["path"] == "/api/crash"
# #endregion Test.AppModule.TestInternalServerErrorReturnsJson
# #endregion Test.AppModule.Handlers