aps-agent/tests/golden/test_readiness.py

119 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ============================================================
# M-B 黄金测试:数据齐备度 + 工时来源 + TIME_* 冲突标注
# ============================================================
from __future__ import annotations
from server.aps_domain.readiness import (
annotate_time_conflicts, check_readiness, readiness_text,
resolve_step_time, time_matrix,
)
from server.agent_core.intent import parse_fast
from server.state.seed import seed_world
def test_demo_world_readiness_mostly_ready():
world = seed_world()
report = check_readiness(world)
s = report["summary"]
assert s["total"] == len([o for o in world["flexOrders"] if o["status"] not in ("DONE", "CANCELLED")])
# 演示厂路线无覆盖工时但设备 opStdTime 齐 → 不算待维护
assert s["timePending"] == 0
assert s["ready"] >= 1
assert "数据齐备度" in readiness_text(report) or "我帮你看了看" in readiness_text(report)
def test_missing_equipment_time_flags_unmaintained():
world = seed_world()
# 摘掉 OP-ASSY 的设备默认工时 → 该步变「待维护」
for e in world["flexEquipment"]:
e.get("opStdTime", {}).pop("OP-ASSY", None)
report = check_readiness(world)
assert report["summary"]["timePending"] > 0
assy_orders = [r for r in report["orders"] if r["productCode"] == "HV-HARNESS"]
assert any(i["type"] == "TIME_UNMAINTAINED" for r in assy_orders for i in r["issues"])
assert all(not r["ready"] for r in assy_orders)
def test_inferred_time_is_warning_not_blocker():
world = seed_world()
for r in world["flexRoutings"]:
if r["productCode"] == "HV-CONN" and r["operationCode"] == "OP-ASSY":
r["stdTimePerUnit"] = 30.0
r["stdTimeSource"] = "推断"
report = check_readiness(world)
conn = [r for r in report["orders"] if r["productCode"] == "HV-CONN"]
assert any(i["type"] == "TIME_INFERRED" and i["severity"] == "warn"
for r in conn for i in r["issues"])
assert all(r["ready"] for r in conn) # 推断不阻塞,只告警
def test_resolve_step_time_priority():
eq = [{"opStdTime": {"OP-X": 5.0}}]
assert resolve_step_time({"operationCode": "OP-X", "stdTimePerUnit": 8.0}, eq) == \
{"stdMin": 8.0, "source": "实测"}
assert resolve_step_time({"operationCode": "OP-X"}, eq) == \
{"stdMin": 5.0, "source": "设备默认"}
assert resolve_step_time({"operationCode": "OP-Y"}, eq)["source"] == "待维护"
def test_time_matrix_has_sources():
world = seed_world()
rows = time_matrix(world)
assert rows
assert {"productCode", "operationCode", "stdMin", "source"} <= set(rows[0].keys())
assert all(r["source"] in ("实测", "推断", "模板", "设备默认", "待维护") for r in rows)
def test_annotate_time_conflicts_after_schedule():
world = seed_world()
# 制造一个待维护步骤
for e in world["flexEquipment"]:
e.get("opStdTime", {}).pop("OP-PKG", None)
counters: dict[str, int] = {}
def nid(kind: str) -> int:
counters[kind] = counters.get(kind, 0) + 1
return counters[kind]
n = annotate_time_conflicts(world, version_id=99, next_id=nid, order_nos=None)
assert n > 0
cfs = [c for c in world["flexConflicts"] if c["versionId"] == 99]
assert any(c["conflictType"] == "TIME_UNMAINTAINED" for c in cfs)
assert all(c["severity"] in ("MAJOR", "MINOR") for c in cfs)
def test_intent_readiness_and_time_update():
world = seed_world()
r = parse_fast("工时维护情况", world)
assert r is not None and r.intent == "readiness.query"
r = parse_fast("哪些工时还没维护", world)
assert r is not None and r.intent == "readiness.query"
r = parse_fast("把部装工时改成50分钟", world)
assert r is not None and r.intent == "flex.time.update"
assert r.params["operationCode"] == "部装"
assert r.params["stdMin"] == 50.0
r = parse_fast("把 0503727Z1M 工时调成 45 分钟", world)
assert r is not None and r.intent == "flex.time.update"
assert r.params["stdMin"] == 45.0
def test_intent_and_analyze_project_data():
from server.aps_domain.readiness import analyze_project_data
world = seed_world()
for text in (
"给我分析一下这个文件里面数据内容",
"分析项目数据",
"【文件解析】\n文件:demo.xlsx\n有效 3 行 · 错误 0 行(可入库)\n\n请分析这些文件",
):
r = parse_fast(text, world)
assert r is not None and r.intent == "data.analyze", text
text = analyze_project_data(world, "分析项目数据")
assert "手头有啥" in text or "要排的单子" in text
assert "我帮你看了看" in text or "能直接开排" in text
text2 = analyze_project_data(
world,
"【文件解析】\n文件:a.xlsx\n有效 2 行 · 错误 0 行(可入库)\n\n给我分析一下",
)
assert "你刚附的表格" in text2
assert "a.xlsx" in text2