Files
PlantAI-rag-new/bioflow_service/tests/test_manifests.py
T

118 lines
3.7 KiB
Python

"""tests/test_manifests.py —— manifest 解析/校验/跨阶段输入定位。"""
from __future__ import annotations
import json
import pytest
from app.services.bioflow.manifests import (
Manifest,
ManifestError,
artifact_paths,
input_resolution,
locate_manifest,
parse_manifest,
)
pytestmark = pytest.mark.bioflow_unit
def _write_manifest(workspace, stage, status="success", prefix="Ft.SPL", extra=None):
final = workspace / "final"
final.mkdir(parents=True, exist_ok=True)
raw = {
"manifest_version": "1", "job_id": "j1", "stage": stage, "status": status,
"prefix": prefix,
"artifacts": {
"final_members": {"artifact": "final_members",
"full_path": str(final / f"{prefix}.final_members.id"),
"type": "table", "size": 100},
},
"parameters": {"cpu": 8}, "metrics": {"final_members": 24},
}
raw.update(extra or {})
path = final / f"{prefix}.{stage}.manifest.json"
path.write_text(json.dumps(raw), encoding="utf-8")
return path
def test_parse_success(tmp_path):
_write_manifest(tmp_path, "identify")
m = parse_manifest(tmp_path, "identify")
assert isinstance(m, Manifest)
assert m.status == "success"
assert m.artifacts["final_members"]["type"] == "table"
assert m.metrics["final_members"] == 24
assert m.prefix == "Ft.SPL"
def test_missing_manifest(tmp_path):
with pytest.raises(ManifestError, match="缺失"):
parse_manifest(tmp_path, "identify")
def test_invalid_json(tmp_path):
final = tmp_path / "final"
final.mkdir(parents=True)
(final / "Ft.SPL.identify.manifest.json").write_text("{broken", encoding="utf-8")
with pytest.raises(ManifestError, match="非法 JSON"):
parse_manifest(tmp_path, "identify")
def test_missing_required_keys(tmp_path):
final = tmp_path / "final"
final.mkdir(parents=True)
(final / "Ft.SPL.identify.manifest.json").write_text('{"stage": "identify"}', encoding="utf-8")
with pytest.raises(ManifestError, match="缺必需字段"):
parse_manifest(tmp_path, "identify")
def test_invalid_status(tmp_path):
_write_manifest(tmp_path, "identify", status="weird")
with pytest.raises(ManifestError, match="status 非法"):
parse_manifest(tmp_path, "identify")
def test_failed_status_valid(tmp_path):
_write_manifest(tmp_path, "identify", status="failed")
m = parse_manifest(tmp_path, "identify")
assert m.status == "failed"
def test_locate_manifest_strict_no_fallback(tmp_path):
# 无 prefix 匹配时绝不兜底其他阶段 manifest(跨阶段误配会导致误判成败)
path = _write_manifest(tmp_path, "identify")
assert locate_manifest(tmp_path, "phylogeny", prefix="OTHER") is None
assert locate_manifest(tmp_path, "identify") == path
def test_artifact_paths():
artifacts = {
"a": {"full_path": "/x/a.id", "type": "table"},
"b": "/y/b.fa",
"c": {"path": "/z/c.txt"},
"d": {"relpath_or_hint": "final/d.txt"},
}
paths = artifact_paths(artifacts)
assert "/x/a.id" in paths
assert "/y/b.fa" in paths
assert "/z/c.txt" in paths
assert "final/d.txt" in paths
def test_input_resolution(tmp_path):
final = tmp_path / "final"
final.mkdir(parents=True, exist_ok=True)
(final / "Ft.SPL.final_members.id").write_text("gene1\ngene2\n", encoding="utf-8")
_write_manifest(tmp_path, "identify")
res = input_resolution(tmp_path, "identify")
assert res["resolved"] is True
assert res["manifest_path"]
assert res["inputs"]
def test_input_resolution_missing(tmp_path):
res = input_resolution(tmp_path, "identify")
assert res["resolved"] is False
assert "缺失" in res["error"]