feat: release 1.5.1 with human review and batch filters
This commit is contained in:
1 parent
53c5680260
commit
bdd1aa2c14
36 files changed
+672
-57
No files matched your search
@@ -780,7 +780,7 @@ def test_failed_report_exposes_logged_reason_and_formats_chinese_markdown(isolat
|
||||
)
|
||||
report = reports.session_report(job["session_id"])
|
||||
assert "连续 3 次" in report["error"]
|
||||
assert report["verdict"] == "测试阻塞"
|
||||
assert report["verdict"] == "测试阻塞(AI确认)"
|
||||
assert report["test_result"]["status"] == "blocked"
|
||||
assert "连续 3 次" in report["test_result"]["reason"]
|
||||
assert "abc123secret" not in reports.failure_reason(
|
||||
@@ -844,8 +844,8 @@ def test_prompt_based_verdict_is_consistent_in_history_batch_and_reports(
|
||||
report = client.get(f"/api/automation/reports/{job['session_id']}").json()
|
||||
for item in (history, batch_job, report):
|
||||
assert item["status"] == "completed"
|
||||
assert item["test_result"] == result
|
||||
assert report["verdict"] == "测试不通过"
|
||||
assert item["test_result"] == {**result, "source": "ai"}
|
||||
assert report["verdict"] == "测试不通过(AI确认)"
|
||||
paths = reports.export_session(job["session_id"])
|
||||
doc = Document(next(path for path in paths if path.suffix == ".docx"))
|
||||
doc_text = "\n".join(
|
||||
@@ -856,10 +856,133 @@ def test_prompt_based_verdict_is_consistent_in_history_batch_and_reports(
|
||||
assert result["evidence"][0] in doc_text
|
||||
wb = load_workbook(next(path for path in paths if path.suffix == ".xlsx"))
|
||||
values = [cell.value for row in wb["任务结果"].iter_rows() for cell in row]
|
||||
assert "测试不通过" in values
|
||||
assert "测试不通过(AI确认)" in values
|
||||
assert result["reason"] in values
|
||||
|
||||
|
||||
def test_human_review_overrides_every_report_preserves_ai_and_invalidates_batch_cache(
|
||||
client, isolated, monkeypatch
|
||||
):
|
||||
from artemis.runtime import case_result
|
||||
from apps.admin_console.routers import sessions as sessions_api
|
||||
|
||||
monkeypatch.setattr(case_result, "TRACES_PATH", reports.TRACES_PATH)
|
||||
batch = service.create_batch(payload())
|
||||
jobs = isolated.jobs(batch["id"])
|
||||
for job in jobs:
|
||||
isolated.save_job({**job, "status": "completed", "ended_at": time.time()})
|
||||
session_id = jobs[0]["session_id"]
|
||||
ai = {"status": "failed", "reason": "AI识别到预期不匹配", "evidence": ["步骤 3 截图"]}
|
||||
directory = reports.TRACES_PATH / session_id
|
||||
directory.mkdir(parents=True)
|
||||
outcome_file = directory / "run_outcome.json"
|
||||
original = json.dumps({"task_status": "completed", "test_result": ai}, ensure_ascii=False)
|
||||
outcome_file.write_text(original, encoding="utf-8")
|
||||
archive = reports.export_batch(batch["id"])
|
||||
isolated.put("batch", batch["id"], {**batch, "report_ready": True})
|
||||
|
||||
response = client.put(
|
||||
f"/api/automation/reports/{session_id}/review",
|
||||
json={"status": "passed", "reason": "已人工核对,符合预期"},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json()["status"] == "completed"
|
||||
assert response.json()["verdict"] == "测试通过(人工确认)"
|
||||
assert outcome_file.read_text(encoding="utf-8") == original
|
||||
assert not archive.exists()
|
||||
assert not isolated.get("batch", batch["id"])["report_ready"]
|
||||
assert len(isolated.get("case_review", session_id)["reviews"]) == 1
|
||||
for result in (
|
||||
response.json(),
|
||||
client.get("/api/automation/history", params={"q": session_id}).json()["items"][0],
|
||||
client.get(f"/api/automation/batches/{batch['id']}").json()["jobs"][0],
|
||||
):
|
||||
assert result["test_result"]["source"] == "human"
|
||||
assert result["test_result"]["status"] == "passed"
|
||||
assert result["test_result"]["ai_result"] == {**ai, "source": "ai"}
|
||||
assert result["test_result"]["reviewed_at"] > 0
|
||||
|
||||
monkeypatch.setattr(sessions_api, "store", isolated)
|
||||
monkeypatch.setattr(sessions_api, "TRACES_PATH", reports.TRACES_PATH)
|
||||
monkeypatch.setattr(
|
||||
sessions_api.session_repo,
|
||||
"get_session_by_id",
|
||||
lambda sid: {"session_id": sid, "status": "completed"},
|
||||
)
|
||||
client.app.include_router(sessions_api.router)
|
||||
detail = client.get(f"/api/sessions/{session_id}").json()
|
||||
assert detail["test_result"]["source"] == "human"
|
||||
assert detail["batch_id"] == batch["id"]
|
||||
|
||||
downloaded = client.get(f"/api/automation/batches/{batch['id']}/archive")
|
||||
assert downloaded.status_code == 200
|
||||
with zipfile.ZipFile(BytesIO(downloaded.content)) as bundle:
|
||||
wb = load_workbook(BytesIO(bundle.read("批次结果.xlsx")))
|
||||
assert wb.active["D2"].value == "测试通过(人工确认)"
|
||||
assert "AI确认" in wb.active["D3"].value
|
||||
doc = Document(BytesIO(bundle.read("批次汇总.docx")))
|
||||
assert doc.tables[0].rows[1].cells[3].text == "测试通过(人工确认)"
|
||||
|
||||
changed = client.put(f"/api/automation/reports/{session_id}/review", json={"status": "failed"})
|
||||
assert changed.status_code == 200
|
||||
assert changed.json()["verdict"] == "测试不通过(人工确认)"
|
||||
assert len(isolated.get("case_review", session_id)["reviews"]) == 2
|
||||
assert outcome_file.read_text(encoding="utf-8") == original
|
||||
|
||||
|
||||
def test_review_rejects_active_missing_invalid_and_packing_tasks(client, isolated, monkeypatch):
|
||||
job = isolated.jobs(service.create_batch(payload())["id"])[0]
|
||||
url = f"/api/automation/reports/{job['session_id']}/review"
|
||||
assert client.put(url, json={"status": "passed"}).status_code == 409
|
||||
assert isolated.get("case_review", job["session_id"]) is None
|
||||
assert client.put(url, json={"status": "inconclusive"}).status_code == 422
|
||||
assert client.put(url, json={"status": "passed", "source": "human"}).status_code == 422
|
||||
assert client.put(url, json={"status": "passed", "reason": "字" * 2001}).status_code == 422
|
||||
assert (
|
||||
client.put("/api/automation/reports/missing/review", json={"status": "passed"}).status_code
|
||||
== 404
|
||||
)
|
||||
isolated.save_job({**job, "status": "completed"})
|
||||
monkeypatch.setattr(api.archive_service, "status", lambda *args: {"status": "preparing"})
|
||||
assert client.put(url, json={"status": "passed"}).status_code == 409
|
||||
assert isolated.get("case_review", job["session_id"]) is None
|
||||
|
||||
|
||||
def test_batch_filter_searches_full_history_and_reviews_are_removed_with_batch(client, isolated):
|
||||
first, second = [service.create_batch(payload(name=name)) for name in ("第一批", "第二批")]
|
||||
for batch in (first, second):
|
||||
for job in isolated.jobs(batch["id"]):
|
||||
isolated.save_job({**job, "status": "completed"})
|
||||
with isolated.connection() as conn:
|
||||
conn.execute(
|
||||
"INSERT INTO sessions(session_id,initial_goal,start_time,status) VALUES (?,?,?,?)",
|
||||
("single-case", "单独检查", time.time(), "completed"),
|
||||
)
|
||||
conn.commit()
|
||||
filtered = client.get(
|
||||
"/api/automation/history",
|
||||
params={"batch_id": first["id"], "q": "用例", "size": 1, "page": 2},
|
||||
).json()
|
||||
assert filtered["total"] == 2
|
||||
assert len(filtered["items"]) == 1
|
||||
assert filtered["items"][0]["batch_id"] == first["id"]
|
||||
assert (
|
||||
client.get("/api/automation/history", params={"batch_id": "__batch__"}).json()["total"] == 4
|
||||
)
|
||||
singles = client.get("/api/automation/history", params={"batch_id": "__single__"}).json()
|
||||
assert [item["session_id"] for item in singles["items"]] == ["single-case"]
|
||||
assert client.get("/api/automation/history", params={"batch_id": "bad/path"}).status_code == 400
|
||||
reviewed_id = isolated.jobs(first["id"])[0]["session_id"]
|
||||
isolated.save_case_review(reviewed_id, "passed", "人工核对")
|
||||
isolated.begin_delete_batch(first["id"])
|
||||
isolated.delete_batch(first["id"])
|
||||
assert isolated.get("case_review", reviewed_id) is None
|
||||
assert len(isolated.jobs(second["id"])) == 2
|
||||
isolated.save_case_review("single-case", "failed", "不符合预期")
|
||||
isolated.delete_history("single-case")
|
||||
assert isolated.get("case_review", "single-case") is None
|
||||
|
||||
|
||||
def test_task_material_zip_contains_ordered_evidence_and_reports(
|
||||
client, isolated, tmp_path, monkeypatch
|
||||
):
|
||||
|
||||
Reference in new issue
Block a user