aps-agent/tests/golden/test_algolib.py

126 lines
5.3 KiB
Python
Raw Normal View History

# ============================================================
# 内置算法库注册表黄金测试(矩阵 86 行 · 方向 E)
# 覆盖:注册/查询、元数据完整(A-E 分类)、健康检查、版本查询、随机种子
# ============================================================
from __future__ import annotations
import pytest
from server.agent_core.algolib import (
CATEGORY_LABELS,
AlgorithmManifest,
AlgorithmRegistry,
get_algolib,
reset_algolib_registry,
)
def _registry() -> AlgorithmRegistry:
reset_algolib_registry()
return get_algolib()
def test_register_query_roundtrip():
"""注册→查询→更新(upsert)→注销 全链路。"""
reg = _registry()
manifest = {
"algo_id": "opt.grid_search",
"name": "网格搜索调参",
"category": "C",
"description": "候选网格枚举(黄金测试资产)",
"scale_limit": "<=1k 工单",
"time_budget": "分钟级",
"input_schema": {"grid": "dict"},
"output_schema": {"best": "dict"},
"golden_tests": ["tests/golden/test_param_opt.py"],
"deterministic": True,
"version": "1.0",
}
reg.register(manifest)
got = reg.get("opt.grid_search")
assert got is not None
assert got["algo_id"] == "opt.grid_search"
assert got["category"] == "C"
# 查询:类别 + 关键词
hits = reg.query(category="C", keywords="网格")
assert any(h["algo_id"] == "opt.grid_search" for h in hits)
assert not reg.query(category="B", keywords="网格")
# 重复注册 = upsert(版本升级)
reg.register({**manifest, "version": "2.0"})
assert reg.get("opt.grid_search")["version"] == "2.0"
# 注销
assert reg.unregister("opt.grid_search") is True
assert reg.get("opt.grid_search") is None
assert reg.unregister("opt.grid_search") is False
def test_register_rejects_incomplete_metadata():
"""元数据不完整 / 非确定性缺种子 注册必须拒绝。"""
reg = _registry()
with pytest.raises(ValueError):
reg.register({"algo_id": "bad", "name": "缺类别"})
with pytest.raises(ValueError):
reg.register({"algo_id": "bad2", "name": "非确定性无种子",
"category": "C", "deterministic": False})
def test_builtin_catalog_metadata_complete_and_a_e_cover():
"""内置目录:A-E 五类齐全,每条元数据完整(名称/适用条件/schema/版本/测试/种子)。"""
reg = _registry()
items = reg.list()
assert len(items) >= 10
for m in items:
problems = AlgorithmManifest(**m).validate_manifest()
assert problems == [], f"{m['algo_id']} 元数据不完整: {problems}"
assert set(CATEGORY_LABELS) == {"A", "B", "C", "D", "E"}
for cat in "ABCDE":
assert any(x["category"] == cat for x in items), f"缺 {cat} 类资产"
ids = {x["algo_id"] for x in items}
# 关键内置资产在位:A 规则 / B 精确 / C 元启发 / D ML 目录 / E 集成与评估链
assert {"rule.delivery_first", "rule.comprehensive"} <= ids
assert "cp_sat" in ids
assert "ga" in ids
assert "ml.worktime_regression" in ids
assert {"hybrid", "eval.sensitivity_tornado", "opt.parameter_optimizer"} <= ids
# 非确定性算法都带随机种子(复现锚点)
for m in items:
if not m["deterministic"]:
assert m["random_seed"] is not None, m["algo_id"]
def test_health_check_ok_for_ready_and_fail_for_catalog_only():
"""健康检查:可用内置算法 ok,目录资产如实报未就绪,自定义探针生效。"""
reg = _registry()
by_id = {h["algo_id"]: h for h in reg.health()}
assert by_id["cp_sat"]["ok"] is True
assert by_id["rule.delivery_first"]["ok"] is True
assert by_id["eval.sensitivity_tornado"]["ok"] is True
assert by_id["milp"]["ok"] is False # 未落地资产如实报告
# 自定义健康探针(健康/不健康)
reg.register({"algo_id": "test.ok", "name": "健康算法", "category": "B",
"health_fn": lambda: {"ok": True, "detail": "ready"}})
reg.register({"algo_id": "test.flaky", "name": "易挂算法", "category": "B",
"health_fn": lambda: {"ok": False, "detail": "license expired"}})
assert reg.health("test.ok")[0]["ok"] is True
assert reg.health("test.flaky")[0]["ok"] is False
# 历史记录与未知 id
assert reg.history("test.ok")
assert reg.health("no.such.algo") == []
def test_version_query_and_random_seed_service():
"""版本查询 + 随机种子服务(GA 等非确定性算法复现锚点)。"""
reg = _registry()
v = reg.version("rule.delivery_first")
assert v is not None and v["version"] == "1.0"
assert v["regen_strategy"] in ("llm", "manual", "hybrid")
assert reg.version("no.such") is None
# 升级版本后查询到新版本
reg.register({"algo_id": "rule.delivery_first", "name": "EDD 最早交期",
"category": "A", "version": "2.1", "regen_strategy": "hybrid"})
assert reg.version("rule.delivery_first")["version"] == "2.1"
# 随机种子:确定性算法返回声明种子(缺省 0),非确定性返回稳定种子
assert reg.next_seed("ga") == 20260802
assert reg.next_seed("rule.delivery_first") == 0
assert isinstance(reg.next_seed("no.such"), int)