Files
tick-stock-panel/backend/tests/test_monitor_demo_rules.py
T
19486fc061 fix(monitor): 演示规则不再写入已下线的内置策略 id (#491)
内置策略在去内置化后已全部下线, 但 _DEMO_STRATEGY_RULES 仍硬编码
trend_breakout / macd_golden。seed 接口不校验就 save_one(), 于是:

- 规则列表显示「已启用」, 实际永远不会触发;
- 运行时 _match_strategy 把 unknown strategy 异常吞成 return [], 日志无线索;
- 同样的规则走单条创建接口(POST /api/monitor-rules)会被 engine.get() 拒掉,
  两条路径契约不一致。

修复:
- 新增 _strategy_available(): 落盘前用策略引擎 has() 校验, 引擎未装配/查询
  异常一律视为不可用(宁可不种, 不种死规则);
- 不可用的演示策略跳过, 响应里返回 skipped 列表, 日志 warning 提示需自建策略;
- _match_strategy 的 except 分支补 debug 日志, 不再完全静默。

测试: tests/test_monitor_demo_rules.py (5 例, 覆盖已注册/未注册/引擎缺失/
引擎异常/存在同名策略时照常生成)。

Co-authored-by: leejialing <leejialing@users.noreply.github.com>
2026-10-19 08:56:07 +08:00

54 lines
2.0 KiB
Python

"""Dev 页演示规则不得引用不存在的策略 id (#490)。
背景: 内置策略在去内置化后已全部下线, 但 `_DEMO_STRATEGY_RULES` 仍硬编码
`trend_breakout` / `macd_golden`。种子接口不校验就落盘 → 规则列表里显示
「已启用」, 运行时 `_match_strategy` 把 `unknown strategy` 异常吞成空列表,
于是规则永远不触发、日志也查不出原因。
修复: 落盘前用策略引擎校验, 不存在的跳过并在响应里列出 `skipped`。
"""
from app.api.monitor_rules import _DEMO_STRATEGY_RULES, _strategy_available
class _FakeEngine:
def __init__(self, ids):
self._ids = set(ids)
def has(self, strategy_id: str) -> bool:
return strategy_id in self._ids
class _BoomEngine:
def has(self, strategy_id: str) -> bool:
raise RuntimeError("engine exploded")
def test_available_only_for_registered_ids():
eng = _FakeEngine({"my_custom"})
assert _strategy_available(eng, "my_custom") is True
assert _strategy_available(eng, "trend_breakout") is False
def test_missing_engine_is_not_available():
# 引擎未装配时宁可不种, 也不种一条永远不触发的规则
assert _strategy_available(None, "trend_breakout") is False
def test_engine_error_is_not_available():
assert _strategy_available(_BoomEngine(), "trend_breakout") is False
def test_builtin_demo_ids_are_filtered_out_on_fresh_install():
"""全新安装(没有任何自建策略): 两条内置演示策略都应被跳过。"""
eng = _FakeEngine(set())
kept = [t for t in _DEMO_STRATEGY_RULES if _strategy_available(eng, t["strategy_id"])]
assert kept == []
def test_demo_templates_still_seed_when_strategy_exists():
"""用户自建了同名/同 id 策略时, 演示规则应照常生成(不能被一刀切掉)。"""
ids = {t["strategy_id"] for t in _DEMO_STRATEGY_RULES}
eng = _FakeEngine(ids)
kept = [t for t in _DEMO_STRATEGY_RULES if _strategy_available(eng, t["strategy_id"])]
assert len(kept) == len(_DEMO_STRATEGY_RULES)