# ============================================================ # M-E 黄金测试:行业工艺路线模板库(结构化 + 知识互链 + 实例化) # ============================================================ from __future__ import annotations import pytest from server.state.seed import seed_world @pytest.fixture(autouse=True) def db_env(tmp_path, monkeypatch): monkeypatch.setenv("APS_DB_PATH", str(tmp_path / "master.db")) monkeypatch.delenv("APS_DB_DISABLED", raising=False) from server.db.database import reset_engine reset_engine() yield reset_engine() def test_builtin_templates_cover_machining_categories(): from server.knowledge.routing_templates import list_templates tpls = list_templates() categories = {t["category"] for t in tpls} assert {"车削", "铣削", "钻镗", "磨削", "钣金", "焊接", "装配"} <= categories for t in tpls: assert t["steps"], t["code"] for s in t["steps"]: assert s["stdMinLow"] <= s["stdMinDefault"] <= s["stdMinHigh"] assert s["equipmentType"] def test_templates_linked_to_knowledge_assets(): from server.knowledge.routing_templates import list_templates tpls = list_templates() linked = [t for t in tpls if t.get("assetId")] assert linked, "模板应与知识资产互链(assetId)" from server.knowledge.assets import get_knowledge asset_ids = {a["assetId"] for a in get_knowledge().assets} assert all(t["assetId"] in asset_ids for t in linked) def test_recommend_by_product_keywords(): from server.knowledge.routing_templates import recommend_templates hits = recommend_templates("传动轴 车削 外圆 螺纹") assert hits and hits[0]["code"] == "TPL-TURNING" hits = recommend_templates("城轨门机构部装总成") assert any(t["code"] == "TPL-RAIL-ASSY" for t in hits) def test_apply_template_generates_schedulable_routing(): from server.engines import PoolEngine from server.knowledge.routing_templates import apply_template_to_product world = seed_world() world["flexOrders"].append({ "id": 88, "orderNo": "FO-8801", "productCode": "SHAFT-X", "quantity": 10, "dueDate": "2099-12-31", "priority": 1, "wbs": "", "productionController": "测试", "status": "RELEASED"}) applied = apply_template_to_product(world, "TPL-TURNING", "SHAFT-X", "传动轴") assert applied["steps"] > 0 steps = [r for r in world["flexRoutings"] if r["productCode"] == "SHAFT-X"] assert all(r["stdTimeSource"] == "模板" for r in steps) # 能力已补齐 → PoolEngine 可排该单 counters: dict[str, int] = {} def nid(kind: str) -> int: counters[kind] = counters.get(kind, 0) + 1 return counters[kind] result = PoolEngine().solve(world, nid, sort_mode="BOTTLENECK", order_ids=[88]) assert result["orderCount"] == 1 assert result["woCount"] == len(steps) def test_knowledge_refs_injected_into_problem_dto(): from server.aps_domain.scheduling_dto import world_to_flex_problem world = seed_world() problem = world_to_flex_problem(world, include_knowledge=True) refs = problem.meta.get("knowledgeRefs") assert isinstance(refs, list) if refs: # 命中时必须带出处 + 版本(RAG 硬规则) assert all(r.get("assetId") and r.get("version") for r in refs) assert problem.schemaVersion == "1.1"