43376abae6
Co-authored-by: guke <guke@autohome.com.cn> Reviewed-on: #221
93 lines
4.2 KiB
Python
93 lines
4.2 KiB
Python
"""比价报警规则分类:记录 → 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 == "深度放弃"
|
|
|
|
|
|
# ---- failed 混合单:业务 headline 盖住某平台真技术失败(线上 trace 20260806_144544)----
|
|
|
|
def test_failed_business_headline_masks_target_technical_failure_reports_t1():
|
|
# fail_reason 被派生成京东业务原因(未找到),却盖住淘宝 status=failed 的真技术崩溃 → 补判 T1。
|
|
rec = _rec(
|
|
status="failed", fail_reason="京东此店内未找到这些菜品",
|
|
information="比价过程出错,请稍后重试",
|
|
raw_payload={"platform_results": {
|
|
"meituan": {"status": "source", "is_source": True},
|
|
"jd_waimai": {"status": "items_not_found", "reason": "京东此店内未找到这些菜品", "is_source": False},
|
|
"taobao_flash": {"status": "failed", "reason": "比价过程出错,请稍后重试", "is_source": False},
|
|
}},
|
|
)
|
|
hit = classify_record(rec, **KW)
|
|
assert hit is not None
|
|
assert hit.alert_type == "T1"
|
|
|
|
|
|
def test_failed_target_failed_but_business_reason_no_false_positive():
|
|
# pricebot 把打烊漏标成 status=failed,但 reason 是业务话术 → 不算技术崩溃,不报(不误报)。
|
|
rec = _rec(
|
|
status="failed", fail_reason="京东此店内未找到这些菜品",
|
|
information="比价过程出错,请稍后重试",
|
|
raw_payload={"platform_results": {
|
|
"jd_waimai": {"status": "items_not_found", "reason": "京东此店内未找到这些菜品", "is_source": False},
|
|
"taobao_flash": {"status": "failed", "reason": "门店已打烊,无法比价", "is_source": False},
|
|
}},
|
|
)
|
|
assert classify_record(rec, **KW) is None
|