smoke_financial_api.py 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. """
  2. 金融 / 行情 API 冒烟测试(直连 FastAPI,需项目根目录 .env 已配置 MX_APIKEY)
  3. 用法(在项目根目录):
  4. py -3 -m backend.scripts.smoke_financial_api
  5. 或在 backend 目录:
  6. py -3 scripts/smoke_financial_api.py
  7. """
  8. from __future__ import annotations
  9. import json
  10. import sys
  11. from pathlib import Path
  12. # 路径:backend/scripts -> backend -> 项目根
  13. _BACKEND = Path(__file__).resolve().parent.parent
  14. _ROOT = _BACKEND.parent
  15. sys.path.insert(0, str(_ROOT))
  16. sys.path.insert(0, str(_BACKEND))
  17. from fastapi.testclient import TestClient # noqa: E402
  18. from app.main import app # noqa: E402
  19. def _short(obj, limit: int = 600) -> str:
  20. s = json.dumps(obj, ensure_ascii=False, default=str)
  21. return s if len(s) <= limit else s[:limit] + "…"
  22. def _summarize_tables(data: dict) -> str:
  23. if not isinstance(data, dict):
  24. return "(非 dict)"
  25. tables = data.get("tables") or []
  26. if not tables:
  27. return "tables=[]"
  28. t0 = tables[0]
  29. names = t0.get("fieldnames") or []
  30. rows = t0.get("rows") or []
  31. row0 = rows[0] if rows else None
  32. return f"fieldnames={names!r}, row0={row0!r}"
  33. def main() -> int:
  34. client = TestClient(app)
  35. endpoints = [
  36. ("GET", "/api/v1/system/health", None),
  37. ("GET", "/api/v1/market/index", {"params": {"name": "上证指数"}}),
  38. ("GET", "/api/v1/market/index", {"params": {"name": "沪深300"}}),
  39. ("GET", "/api/v1/market/quote/600519", None),
  40. ("GET", "/api/v1/financial/indicators/600519", None),
  41. ("GET", "/api/v1/financial/profile/600519", None),
  42. ("GET", "/api/v1/financial/holders/600519", None),
  43. ]
  44. print("=== 金融 / 行情 API 冒烟(TestClient)===\n")
  45. for method, path, kw in endpoints:
  46. kw = kw or {}
  47. r = client.request(method, path, **kw)
  48. body = r.json()
  49. inner = body.get("data") if isinstance(body, dict) else None
  50. ok_http = r.status_code == 200
  51. ok_biz = isinstance(body, dict) and body.get("code") == 0
  52. mx_ok = isinstance(inner, dict) and inner.get("success") is True
  53. line1 = f"{method} {path} [{r.status_code}] code={body.get('code') if isinstance(body, dict) else '?'}"
  54. print(line1)
  55. if not ok_http or not ok_biz:
  56. print(f" -> 响应异常: {_short(body)}")
  57. print()
  58. continue
  59. if inner is None:
  60. print(f" -> data=None {_short(body)}")
  61. print()
  62. continue
  63. if isinstance(inner, dict) and "success" in inner:
  64. print(f" -> mx success={inner.get('success')} total_rows={inner.get('total_rows')} error={inner.get('error')}")
  65. print(f" -> {_summarize_tables(inner)}")
  66. else:
  67. print(f" -> {_short(inner)}")
  68. print()
  69. print("说明: mx success=false 或 tables 空时,多为妙想接口返回或解析问题;HTTP 非 200 看 message。")
  70. return 0
  71. if __name__ == "__main__":
  72. raise SystemExit(main())