mirror of
https://ghfast.top/https://github.com/aeroxw/tick-stock-panel.git
synced 2026-09-12 15:34:16 +08:00
test(panelcache): 子代理审查加固 — 去 flaky + 补遥测差值覆盖
三处审查驱动的测试改进: - 并发计数测试放宽 reuse_count==4 为 reuse+hit==4 (保留"只扫盘1次"核心不变量), 消除慢调度下 leader 已写缓存致某线程走 hit 分支的 flaky。 - _FakeEngine 零值 dict 改从 PanelCache().stats() 取键 —— 字段重命名时桩自动跟随, 杜绝 test 绿而生产 cache_stats KeyError 的契约漂移。 - 新增 test_walkforward_cache_telemetry_computes_deltas: 递增桩验证 scans/hits/ reuses/秒数 = after-before, 覆盖此前 _FakeEngine 恒返 0 掩盖的差值/顺序逻辑。
This commit is contained in:
@@ -136,11 +136,14 @@ class _FakeOptimizer:
|
||||
return {"best_params": {"p": cfg.start.month}, "best_score": 2.0, "results": [], "n_completed": 1}
|
||||
|
||||
|
||||
_ZERO_CACHE_STATS = {"compute_seconds": 0.0, "compute_count": 0, "hit_count": 0, "reuse_count": 0}
|
||||
# 从真实 PanelCache 取字段模板 —— 字段被重命名时本桩自动跟随, 避免 test 绿而生产 KeyError。
|
||||
from app.backtest.engine import PanelCache
|
||||
|
||||
_ZERO_CACHE_STATS = {k: type(v)() for k, v in PanelCache().stats().items()}
|
||||
|
||||
|
||||
class _FakeEngine:
|
||||
"""最小引擎桩: 仅提供 WF 遥测所需的 cache_stats。"""
|
||||
"""最小引擎桩: 仅提供 WF 遥测所需的 cache_stats (字段同源自 PanelCache.stats)。"""
|
||||
def cache_stats(self):
|
||||
return dict(_ZERO_CACHE_STATS)
|
||||
|
||||
@@ -182,6 +185,33 @@ def test_walkforward_optimizes_train_applies_oos():
|
||||
assert svc.calls[0]["start"] >= opt.train_ranges[0][1]
|
||||
|
||||
|
||||
class _CountingEngine:
|
||||
"""首尾两次 cache_stats 返回不同值, 用于验证 WF 遥测差值/顺序计算 (非全零掩盖)。"""
|
||||
def __init__(self):
|
||||
self._n = 0
|
||||
|
||||
def cache_stats(self):
|
||||
self._n += 1
|
||||
if self._n == 1: # run 开头快照 (before)
|
||||
return {"compute_seconds": 1.0, "compute_count": 2, "hit_count": 0, "reuse_count": 0}
|
||||
return {"compute_seconds": 3.5, "compute_count": 7, "hit_count": 4, "reuse_count": 3} # after
|
||||
|
||||
|
||||
def test_walkforward_cache_telemetry_computes_deltas():
|
||||
"""cache_telemetry 用首尾快照差值: scans/hits/reuses/秒数 = after - before, 且方向正确。"""
|
||||
opt, svc = _FakeOptimizer(), _FakeService()
|
||||
svc.engine = _CountingEngine()
|
||||
wf = WalkForwardService(opt, svc, strategy_engine=None)
|
||||
out = wf.run(_wf_cfg())
|
||||
|
||||
tel = out["cache_telemetry"]
|
||||
assert tel["scans"] == 5 # 7 - 2, 顺序写反会得 -5
|
||||
assert tel["hits"] == 4 # 4 - 0
|
||||
assert tel["single_flight_reuses"] == 3 # 3 - 0
|
||||
assert abs(tel["load_panel_seconds"] - 2.5) < 1e-9 # 3.5 - 1.0
|
||||
assert tel["load_panel_pct"] >= 0.0 # 扫盘耗时 / WF总耗时, 非负
|
||||
|
||||
|
||||
def test_walkforward_reports_degradation():
|
||||
opt, svc = _FakeOptimizer(), _FakeService()
|
||||
wf = WalkForwardService(opt, svc, strategy_engine=None)
|
||||
|
||||
@@ -187,8 +187,11 @@ def test_panel_cache_stats_counts_scans_hits_reuses():
|
||||
t.join()
|
||||
|
||||
s = cache.stats()
|
||||
# 核心不变量: 5 线程并发同 key 只扫盘 1 次 (args1 首次 + args2 一次 = 2)。
|
||||
assert s["compute_count"] == 2, "并发同 key 应只扫盘 1 次"
|
||||
assert s["reuse_count"] == 4, "其余 4 个跟随者应计为复用"
|
||||
# 其余 4 线程要么 single-flight 复用, 要么(慢调度下 leader 已写缓存)命中 ——
|
||||
# 二者之和恒为 4。不锁定 reuse/hit 具体分配, 避免时序 flaky。
|
||||
assert s["reuse_count"] + (s["hit_count"] - 1) == 4, "4 个非 leader 线程应复用或命中"
|
||||
|
||||
|
||||
def test_job_key_includes_asset_type_and_is_consistent():
|
||||
|
||||
Reference in New Issue
Block a user