PMFlow/backend/tests/test_sstc_charter_release_c...

171 lines
6.2 KiB
Python

from types import SimpleNamespace
import pytest
from fastapi import HTTPException
from app.api.sstc_api import charters_ai_alignment as charters_ai_alignment_api
from app.api.sstc_api import releases_status_generate as releases_status_generate_api
@pytest.mark.asyncio
async def test_confirm_alignment_blocks_when_charter_readiness_is_not_ready(monkeypatch) -> None:
async def _fake_ensure_project(service, project_id):
_ = (service, project_id)
return SimpleNamespace(id=6)
async def _fake_ensure_charter(db, *, tenant_id: int, project_id: int, charter_id: int):
_ = (db, tenant_id, project_id, charter_id)
return SimpleNamespace(
id=55,
title="内部知识库升级宪章",
status="aligning",
content={
"readiness": {
"ready_for_confirm": False,
"blocking_fields": ["module_1.kpis", "module_2.alignment_qa"],
"blocking_reasons": ["关键 KPI 缺少证据", "固定对齐问答未完成"],
}
},
)
class _FakeResult:
def scalar_one_or_none(self):
return None
def scalars(self):
return self
def all(self):
return []
class _FakeDB:
async def execute(self, stmt):
_ = stmt
return _FakeResult()
def add(self, value):
_ = value
return None
async def commit(self):
raise AssertionError("readiness blocked charters must not commit confirmation")
monkeypatch.setattr(charters_ai_alignment_api, "_ensure_project", _fake_ensure_project)
monkeypatch.setattr(charters_ai_alignment_api, "_ensure_charter", _fake_ensure_charter)
with pytest.raises(HTTPException) as exc_info:
await charters_ai_alignment_api.confirm_alignment(
project_id="6",
charter_id="55",
body=SimpleNamespace(score=90, confirmed=True, comments="已确认对齐"),
db=_FakeDB(),
current_user=SimpleNamespace(tenant_id=1, id=7),
permission_user=SimpleNamespace(),
)
assert exc_info.value.status_code == 409
assert "关键 KPI 缺少证据" in str(exc_info.value.detail)
assert "module_1.kpis" in str(exc_info.value.detail)
@pytest.mark.asyncio
async def test_generate_release_verification_uses_charter_verification_metrics(monkeypatch) -> None:
async def _fake_ensure_project(service, project_id):
_ = (service, project_id)
return SimpleNamespace(id=6)
async def _fake_ensure_release(db, *, tenant_id: int, project_id: int, release_node_id: int):
_ = (db, tenant_id, project_id, release_node_id)
return SimpleNamespace(
id=88,
status="pending",
content={"charter_id": 55},
)
async def _fake_ensure_charter(db, *, tenant_id: int, project_id: int, charter_id: int):
_ = (db, tenant_id, project_id, charter_id)
return SimpleNamespace(
id=55,
content={
"derived_artifacts": {
"verification_metrics": [
{"name": "首响低于 3 秒", "expected": "P95 <= 3s"},
{"name": "重复提问率下降", "expected": "下降 20%+"},
]
},
"success_metrics": ["不应回退到这里"],
},
)
class _FakeDB:
def __init__(self):
self.committed = False
async def commit(self):
self.committed = True
monkeypatch.setattr(releases_status_generate_api, "_ensure_project", _fake_ensure_project)
monkeypatch.setattr(releases_status_generate_api, "_ensure_release", _fake_ensure_release)
monkeypatch.setattr(releases_status_generate_api, "_ensure_charter", _fake_ensure_charter)
db = _FakeDB()
response = await releases_status_generate_api.generate_release_verification(
project_id="6",
release_node_id="88",
db=db,
current_user=SimpleNamespace(tenant_id=1, id=7, role="REVIEWER"),
permission_user=SimpleNamespace(),
)
payload = response["data"]
assert db.committed is True
assert payload["verification_items"][0]["title"] == "首响低于 3 秒"
assert payload["verification_items"][0]["expected"] == "P95 <= 3s"
assert payload["verification_items"][0]["source"] == "charter_verification_metric"
@pytest.mark.asyncio
async def test_generate_release_verification_fails_without_charter_metrics(monkeypatch) -> None:
async def _fake_ensure_project(service, project_id):
_ = (service, project_id)
return SimpleNamespace(id=6)
async def _fake_ensure_release(db, *, tenant_id: int, project_id: int, release_node_id: int):
_ = (db, tenant_id, project_id, release_node_id)
return SimpleNamespace(
id=88,
status="pending",
content={"charter_id": 55},
)
async def _fake_ensure_charter(db, *, tenant_id: int, project_id: int, charter_id: int):
_ = (db, tenant_id, project_id, charter_id)
return SimpleNamespace(
id=55,
content={
"derived_artifacts": {"verification_metrics": []},
"success_metrics": [],
"core_metrics": [],
},
)
class _FakeDB:
async def commit(self):
raise AssertionError("missing metrics must not commit verification items")
monkeypatch.setattr(releases_status_generate_api, "_ensure_project", _fake_ensure_project)
monkeypatch.setattr(releases_status_generate_api, "_ensure_release", _fake_ensure_release)
monkeypatch.setattr(releases_status_generate_api, "_ensure_charter", _fake_ensure_charter)
with pytest.raises(HTTPException) as exc_info:
await releases_status_generate_api.generate_release_verification(
project_id="6",
release_node_id="88",
db=_FakeDB(),
current_user=SimpleNamespace(tenant_id=1, id=7, role="REVIEWER"),
permission_user=SimpleNamespace(),
)
assert exc_info.value.status_code == 409
assert "verification metrics" in str(exc_info.value.detail).lower()