"""P7 记分板新增纯函数测试(M3 计划 T8): 成功率/坏源占比/错误分类。""" import pytest from tools.soak.scoreboard import ( inv_errors_classified, inv_fault_share, inv_success_rate, ) _KNOWN = ("TransientError", "AllSourcesExhausted", "cancelled") def _row(source="monkey_1", error=None, cache_hit=0): return {"source_name": source, "error": error, "cache_hit": cache_hit} class TestSuccessRate: def test_pass_at_threshold(self): inv_success_rate(98, 100, min_rate=0.98) def test_fail_below(self): with pytest.raises(AssertionError, match="成功率"): inv_success_rate(97, 100, min_rate=0.98) def test_zero_total_rejected(self): with pytest.raises(AssertionError): inv_success_rate(0, 0, min_rate=0.98) class TestFaultShare: def test_share_within_threshold(self): rows = [_row()] * 9 + [_row("monkey_3")] inv_fault_share(rows, ["monkey_3", "monkey_4"], max_share=0.15) def test_share_exceeds(self): rows = [_row()] * 4 + [_row("monkey_3")] * 2 with pytest.raises(AssertionError, match="坏源尝试占比"): inv_fault_share(rows, ["monkey_3"], max_share=0.15) def test_cache_rows_excluded(self): rows = [_row(cache_hit=1)] * 100 + [_row("monkey_3")] + [_row()] * 9 inv_fault_share(rows, ["monkey_3"], max_share=0.15) # 缓存行不入分母 class TestErrorsClassified: def test_known_prefixes_pass(self): rows = [_row(error="TransientError: m1 超时"), _row(error="cancelled"), _row()] inv_errors_classified(rows, _KNOWN) def test_unknown_prefix_fails(self): rows = [_row(error="KeyError: 'oops'")] with pytest.raises(AssertionError, match="未分类"): inv_errors_classified(rows, _KNOWN) class TestRssAbsolute: def test_within_bound(self): from tools.soak.scoreboard import inv_rss_absolute inv_rss_absolute([120.0, 180.0, 150.0], max_mb=500.0) def test_peak_exceeds(self): from tools.soak.scoreboard import inv_rss_absolute with pytest.raises(AssertionError, match="峰值"): inv_rss_absolute([120.0, 690.0, 200.0], max_mb=500.0) # verifier I1 实测形态 def test_empty_rejected(self): from tools.soak.scoreboard import inv_rss_absolute with pytest.raises(AssertionError): inv_rss_absolute([], max_mb=500.0)