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