muse-agent-example/tests/单元/test_发布缓存回收.py
zizi d909d1bd1b 后端实现与用例身份:19 包集成落地并修复收尾缺陷
实现侧:
- 上下文:任务范围拆分为 范围校验/范围授权;索引按可发现口径重建、索引新鲜度改对称差;依赖校验统一快照漂移说明。
- 知识方法:方法与材料读取口径统一;超限方法材料按可选省略,核对路径不再二次计费;删除无合同的读时重算。
- 任务运行:新增 context.usage/tool.denied 事件类型;连接池常驻并在装配生命周期内开关;调用结算与核对分列。
- 效果评测/审校修订/交付连载/作者经验/作品规划:凭据冻结、标定消费、导出补证、事实引文核对等收尾修复。
- 资源加载:能力正文不再夹带索引用的导航注记(该注记此前进入角色与技能的模型提示)。
- 元数据:受保护骨架与代码保护属性对齐;字段校验与内置结构口径同步。
- 基础设施:环境预检进入装配生命周期;数据库连接运行期字段不参与相等比较;索引指纹归一化 jsonb 浮点。
- 删除被替代实现:7 份旧提示词模板与空壳 资料来源 读取器。

用例侧:
- 用例身份与导航元信息迁移;夹具补生命周期、同库暴露与模板封存;
- 本轮定向修复:方法材料省略、事实引文、迁移回执、额度与暂停用例、慢用例超时预算等。
2026-09-18 01:15:00 +08:00

205 lines
7.4 KiB
Python

"""只使用合成临时目录;发布缓存与备份/未知资料不混用。"""
import hashlib
import json
from contextlib import contextmanager
import pytest
from muse.基础设施 import 保留回收 as 模块
from muse.基础设施.保留回收 import 初始化发布缓存, 发布缓存回收, 回收错误
def 建发布(root, name, build):
release = root / name
(release / "wheels").mkdir(parents=True)
data = b"synthetic-wheel"
(release / "wheels/muse.whl").write_bytes(data)
manifest = {
"schema_version": 1,
"version": "1",
"build_id": build,
"code_hash": "c" * 64,
"resource_release": "r" * 64,
"files": {"wheels/muse.whl": hashlib.sha256(data).hexdigest()},
}
manifest["release_id"] = hashlib.sha256(
json.dumps(manifest, ensure_ascii=False, sort_keys=True).encode()
).hexdigest()
(release / "发布清单.json").write_text(json.dumps(manifest, ensure_ascii=False))
return release
@pytest.fixture
def 环境(tmp_path):
root = tmp_path / "cache"
初始化发布缓存(root)
protection = {"complete": True, "build_ids": ["current"], "generation": "inventory-1"}
@contextmanager
def 读取保护():
yield protection.copy()
return root, protection, 发布缓存回收(root, 读取保护)
def 快照(root):
return {
str(p.relative_to(root)): p.read_bytes()
for p in root.rglob("*")
if p.is_file() and not p.is_symlink()
}
@pytest.mark.case_id("NC-release-retention-preview")
def test_预览零写入并区分当前构建未知和候选(环境):
root, protection, service = 环境
建发布(root, "old", "old")
建发布(root, "live", "current")
(root / "backup").mkdir()
(root / "backup/manifest.json").write_text('{"backup_id":"retained"}')
before = 快照(root)
items = {r["entry_id"]: r for r in service.预览()["items"]}
assert {k: r["decision"] for k, r in items.items()} == {
"old": "candidate",
"live": "keep",
"backup": "unknown",
}
assert 快照(root) == before
protection["complete"] = False
assert {r["decision"] for r in service.预览()["items"]} == {"unknown"}
@pytest.mark.case_id("NC-release-retention-idempotent")
def test_具名回收和重复执行返回同一回执(环境):
root, _, service = 环境
target = 建发布(root, "old", "old")
plan = service.预览()["items"][0]
first = service.执行(plan)
assert first["state"] == "completed" and not target.exists()
assert service.执行(plan) == first
assert list((root / 模块.暂存目录).iterdir()) == []
@pytest.mark.case_id("NC-release-retention-drift")
@pytest.mark.parametrize("drift", ["references", "file", "manifest", "namespace", "unknown-file"])
def test_执行前引用身份或字节变化拒绝删除(环境, drift):
root, protection, service = 环境
target = 建发布(root, "old", "old")
plan = service.预览()["items"][0]
if drift == "references":
protection["build_ids"].append("old")
if drift == "file":
(target / "wheels/muse.whl").write_bytes(b"changed")
if drift == "manifest":
(target / "发布清单.json").write_text("{}")
if drift == "namespace":
(root / 模块.标记名).write_text("{}")
if drift == "unknown-file":
(target / "private.bin").write_bytes(b"private")
with pytest.raises(回收错误):
service.执行(plan)
assert target.exists()
@pytest.mark.case_id("NC-release-retention-interruption")
def test_删除后回执写入中断可恢复同一具名结果(环境, monkeypatch):
root, _, service = 环境
target = 建发布(root, "old", "old")
plan = service.预览()["items"][0]
write = 模块._写JSON
def 中断(fd, name, data):
if data.get("state") == "completed":
raise OSError("synthetic receipt interruption")
write(fd, name, data)
monkeypatch.setattr(模块, "_写JSON", 中断)
with pytest.raises(OSError):
service.执行(plan)
assert not target.exists()
monkeypatch.setattr(模块, "_写JSON", write)
receipt = service.执行(plan)
assert receipt["state"] == "completed" and service.执行(plan) == receipt
@pytest.mark.case_id("NC-release-retention-pending-unknown")
def test_中断后出现未知文件不继续删除(环境, monkeypatch):
root, _, service = 环境
建发布(root, "old", "old")
plan = service.预览()["items"][0]
remove = service._删除已登记
monkeypatch.setattr(
service, "_删除已登记", lambda *_: (_ for _ in ()).throw(OSError("synthetic"))
)
with pytest.raises(OSError):
service.执行(plan)
pending = next((root / 模块.暂存目录).iterdir())
unknown = pending / "unexpected.bin"
unknown.write_bytes(b"preserve")
monkeypatch.setattr(service, "_删除已登记", remove)
with pytest.raises(回收错误, match="未知字节"):
service.执行(plan)
assert unknown.read_bytes() == b"preserve"
assert (pending / "wheels/muse.whl").exists()
@pytest.mark.case_id("NC-release-retention-no-adoption")
def test_已有备份或普通目录不能被接管为缓存(tmp_path):
backup = tmp_path / "backup"
backup.mkdir()
(backup / "manifest.json").write_text("{}")
with pytest.raises(FileExistsError):
初始化发布缓存(backup)
@contextmanager
def 保护():
yield {"complete": True, "build_ids": []}
with pytest.raises(FileNotFoundError):
发布缓存回收(backup, 保护).预览()
assert (backup / "manifest.json").read_text() == "{}"
@pytest.mark.case_id("NC-release-retention-symlink")
def test_符号链接始终未知且不影响目标(环境, tmp_path):
root, _, service = 环境
outside = tmp_path / "outside"
outside.mkdir()
(outside / "keep").write_bytes(b"preserve")
(root / "linked").symlink_to(outside, target_is_directory=True)
assert service.预览()["items"] == [
{"entry_id": "linked", "decision": "unknown", "reason": "unrecognized_or_damaged"}
]
assert (outside / "keep").read_bytes() == b"preserve"
@pytest.mark.case_id("NC-release-retention-receipt-tamper")
@pytest.mark.parametrize("改变", ["files-copy", "completed", "manifest"])
def test_中断回执篡改不能授权删新字节或伪造完成(环境, monkeypatch, 改变):
root, _, service = 环境
建发布(root, "old", "old")
plan = service.预览()["items"][0]
原删除 = service._删除已登记
monkeypatch.setattr(service, "_删除已登记", lambda *_: (_ for _ in ()).throw(OSError("stop")))
with pytest.raises(OSError):
service.执行(plan)
pending = next((root / 模块.暂存目录).iterdir())
receipt_path = next((root / 模块.回执目录).iterdir())
receipt = json.loads(receipt_path.read_text())
wheel = pending / "wheels/muse.whl"
if 改变 == "completed":
receipt["state"] = "completed"
else:
wheel.write_bytes(b"unapproved-new-bytes")
files = {"wheels/muse.whl": hashlib.sha256(wheel.read_bytes()).hexdigest()}
if 改变 == "files-copy":
receipt["files"] = files
else:
receipt["release_manifest"]["files"] = files
receipt_path.write_text(json.dumps(receipt))
monkeypatch.setattr(service, "_删除已登记", 原删除)
with pytest.raises(回收错误, match="回执"):
service.执行(plan)
assert wheel.exists()