126 lines
5.3 KiB
Python
126 lines
5.3 KiB
Python
# ============================================================
|
||
# 内置算法库注册表黄金测试(矩阵 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)
|