aps-agent/tests/golden/test_optimize_simulation_wo...

94 lines
3.7 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.

from __future__ import annotations
import copy
import json
from datetime import date
from pathlib import Path
from server.aps_domain.closed_loop_runtime import run_closed_loop_candidate
from server.aps_domain.views import due_view
from server.state.packs import load_pack, list_packs
PACK_PATH = Path(__file__).resolve().parents[2] / "server" / "data" / "packs" / "optimize-simulation-v1.json"
RULES = ("EDD", "SPT", "PRIORITY", "FIFO", "LPT", "CR", "ATC")
def _next_id_factory():
counters: dict[str, int] = {}
def next_id(kind: str) -> int:
counters[kind] = counters.get(kind, 0) + 1
return counters[kind]
return next_id
def test_simulation_world_pack_is_a_generic_aps_fixture():
pack = json.loads(PACK_PATH.read_text(encoding="utf-8"))
world = load_pack(str(PACK_PATH))
assert pack["packVersion"] == 1
assert pack["name"] == "Optimize synthetic debug V1"
assert world["flexParams"]["dataGrade"] == "synthetic"
assert len(world["flexOrders"]) == 10
assert len(world["salesOrders"]) == 10
assert len(world["flexRoutings"]) == 72
assert len(world["flexEquipment"]) == 6
assert all(row["source"] == "SYNTHETIC" for row in world["flexOrders"])
assert {row["productCode"] for row in world["flexRoutings"]} == {
row["productCode"] for row in world["flexOrders"]
}
assert any(item["file"] == PACK_PATH.name for item in list_packs())
def test_simulation_world_pack_runs_all_optimize_dispatch_rules():
source_world = load_pack(str(PACK_PATH))
for rule in RULES:
world = copy.deepcopy(source_world)
result = run_closed_loop_candidate(
world,
_next_id_factory(),
business_date="2026-08-02",
engine_type="OPTIMIZE",
sort_mode=rule,
strict=True,
)
assert result["solveStatus"] == "FEASIBLE", rule
assert result["engineType"] == "OPTIMIZE", rule
assert result["algorithmId"] == f"optimize.{rule.lower()}", rule
assert result["orderCount"] == 10, rule
assert result["vlCount"] == 10, rule
assert result["woCount"] == 72, rule
assert result["validation"]["valid"] is True, rule
assert result["validation"]["hardViolations"] == [], rule
def test_simulation_world_pack_keeps_sales_order_fields_the_due_board_reads():
"""交期承诺看板直取订单客户字段,数据包必须按订单契约补齐(回归:/api/world/due 500)。"""
world = load_pack(str(PACK_PATH))
rows = due_view(world)
assert len(rows) == len(world["salesOrders"]) == 10
assert all(row["customerName"] and row["customerLevel"] for row in rows)
assert all(isinstance(row["isRush"], bool) for row in rows)
assert any(row["isRush"] for row in rows) # 至少一张插单,加急标记在 UI 有数据可验
assert {row["customerLevel"] for row in rows} >= {"VIP", "A", "B", "C"} # 等级过滤有数据可筛
def test_simulation_world_pack_timeline_follows_its_case_business_day():
"""回归:baseDate 必须是案例业务日,否则世界日期随运行日漂移、黄金测试输入每天变。
源案例(kangni-simulation-package-v1)的业务日交期结构固定为「9 张逾期 + 最晚交期在业务日 +6 天」,
世界日期整体贴着 baseDate 平移后,这个结构在任意运行日都应原样落在"今天"上。
"""
world = load_pack(str(PACK_PATH))
due_dates = sorted(date.fromisoformat(order["dueDate"]) for order in world["flexOrders"])
today = date.today()
assert (due_dates[-1] - today).days == 6 # 最晚交期 = 案例业务日 +6 天
assert sum(1 for due in due_dates if due < today) == 9 # 案例本身是 9 张逾期单