"""Tests for sanguo_api.main container entrypoint (app loader + SPA mount). Covers Task S0.1: build_app(config_path, static_dir) loads backtest.yaml and mounts SPA static files when the directory exists. """ from fastapi.testclient import TestClient from sanguo_api.main import build_app def _cfg(tmp_path) -> str: cfg = tmp_path / "bt.yaml" cfg.write_text( "backtest:\n max_workers: 1\n db_path: %s\n file_dir: %s\n" "api:\n host: 0.0.0.0\n port: 8000\n" "auth:\n username: admin\n password_hash: x\n jwt_secret: s\n token_expire_minutes: 60\n" "pool:\n max_workers: 1\n" % (tmp_path / "r.db", tmp_path / "f") ) return str(cfg) def _has_route(app, path: str, method: str = "GET") -> bool: """路由存在性探测(FastAPI 0.139+ 兼容)。 FastAPI 0.139 起 include_router 的子路由包成 _IncludedRouter,不再 flatten 到 app.routes 顶层,因此 [r.path for r in app.routes] 看不到 /api/v1/* 路由。 用 TestClient 实际探测:404 = 路由不存在,其他状态码(405/401/200)= 存在。 前后端对齐的真实验证:前端能打的端点,后端确实挂载。 """ return TestClient(app).request(method, path).status_code != 404 def test_build_app_has_api_routes(tmp_path): app = build_app(_cfg(tmp_path)) assert _has_route(app, "/api/v1/auth/login", "POST") def test_build_app_mounts_spa_when_static_exists(tmp_path): spa = tmp_path / "spa" spa.mkdir() (spa / "index.html").write_text("