"""比价报警规则分类:记录 → AlertHit | None(纯函数,不碰 DB)。""" from __future__ import annotations from types import SimpleNamespace import pytest from app.services.compare_alert import classify_record KW = dict( cancelled_ms_threshold=90000, cancelled_step_threshold=30, timeout_keywords=("超时", "启动", "加载"), unrecognized_keywords=("未识别",), biz_exclude_keywords=("未找到", "打烊", "起送", "门店", "店内", "不配送", "这些菜", "未入驻", "休息"), ) def _rec(**kw): base = dict( status="failed", fail_reason=None, information=None, total_ms=None, step_count=None, trace_id="t", app_version=None, business_type="food", ) base.update(kw) return SimpleNamespace(**base) @pytest.mark.parametrize( ("rec", "expected_type"), [ (_rec(status="failed", fail_reason=None, information="比价过程出错,请稍后重试"), "T1"), (_rec(status="failed", fail_reason=None, information=None), "T1"), (_rec(status="failed", fail_reason=None, information="美团外卖门店已打烊,无法比价"), None), (_rec(status="failed", fail_reason="未识别到商品"), "T6"), (_rec(status="failed", fail_reason="启动淘宝超时, 请稍后重试"), "T2"), (_rec(status="failed", fail_reason="淘宝闪购店内未找到这些菜品"), None), (_rec(status="cancelled", total_ms=98000, step_count=10), "T5"), (_rec(status="cancelled", total_ms=20000, step_count=31), "T5"), (_rec(status="cancelled", total_ms=20000, step_count=5), None), (_rec(status="cancelled", total_ms=None, step_count=None), None), (_rec(status="success"), None), (_rec(status="running"), None), ], ) def test_classify_record_type(rec, expected_type): hit = classify_record(rec, **KW) assert (hit.alert_type if hit else None) == expected_type def test_t5_boundary_exclusive(): assert classify_record(_rec(status="cancelled", total_ms=90000, step_count=30), **KW) is None assert classify_record(_rec(status="cancelled", total_ms=90001, step_count=30), **KW).alert_type == "T5" def test_reason_texts(): t1 = classify_record(_rec(status="failed", fail_reason=None, information=" 比价过程出错 "), **KW) assert t1.reason == "技术失败·比价过程出错" t1_empty = classify_record(_rec(status="failed", fail_reason=None, information=None), **KW) assert t1_empty.reason == "技术失败·比价过程出错" t5 = classify_record(_rec(status="cancelled", total_ms=98000, step_count=26), **KW) assert t5.reason == "深度放弃"