Files
WiseGrade/backend/tests/test_workflow.py
T

91 lines
4.7 KiB
Python

import shutil
from pathlib import Path
import pymupdf as fitz
import pytest
from fastapi.testclient import TestClient
from sqlalchemy import select
from wisegrade.config import get_settings
from wisegrade.db import get_db
from wisegrade.llm import ConsistencyResult, FactResult, ScoreResult
from wisegrade.main import app
from wisegrade.models import CourseVersion, CriterionScore, RubricVersion, ScoringBatch, TeacherRevision
from wisegrade.rag import retrieve
from wisegrade.scoring import run_batch
from wisegrade.storage import scan
def fake_embed(texts):
return [[1.0] + [0.0] * 1023 for _ in texts]
class FakeModel:
def json_call(self, _prompt, payload, schema, images=None):
if schema is FactResult:
return FactResult(topic="自动化实践示例")
if schema is ConsistencyResult:
return ConsistencyResult()
criterion = payload["criterion"]
evidence = payload["evidence"][0]
return ScoreResult(criterion_id=criterion["criterion_id"], score=criterion["max_score"] / 2,
max_score=criterion["max_score"], reason="示例证据支持部分要求",
evidence=[{"chunk_id": evidence["chunk_id"], "page": evidence["page"],
"quote": evidence["text"][:min(12, len(evidence["text"]))]}],
missing_evidence=[], suggestion="补充量化论证", confidence=.7)
def make_pdf(path, title):
pdf = fitz.open()
page = pdf.new_page()
page.insert_text((72, 72), title + " results and analysis for robot control system. " * 4)
pdf.save(path)
@pytest.mark.integration
def test_docs_examples_end_to_end(environment, session_factory):
root = environment / "inbox" / "2026春季第1批" / "1023009006_李傲琦_基于ROS2系统的自瞄移动机器人"
root.mkdir(parents=True)
docs = Path(__file__).resolve().parents[2] / "docs"
for filename in ("阶段报告1.pdf", "阶段报告2.pdf", "阶段报告3.pdf", "自动化专业综合实践报告.pdf"):
shutil.copy2(docs / filename, root / filename)
make_pdf(root / "汇报PPT.pdf", "Presentation")
data = scan("2026春季第1批")
assert len(data["projects"]) == 1
scanned = data["projects"][0]
assert scanned["missing"] == []
assert next(f for f in scanned["files"] if f["category"] == "presentation")["status"] == "needs_confirmation"
def override_db():
with session_factory() as session:
yield session
app.dependency_overrides[get_db] = override_db
client = TestClient(app)
try:
files = [{"relative_path": f["relative_path"], "category": f["category"], "sha256": f["sha256"], "status": "recognized"} for f in scanned["files"]]
response = client.post("/api/import/confirm", json={"course_version_id": 1, "projects": [{"relative_dir": scanned["relative_dir"],
"student_no": scanned["student_no"], "name": scanned["name"], "topic": scanned["topic"], "files": files}]})
assert response.status_code == 200, response.text
project_id = response.json()["project_ids"][0]
response = client.post("/api/scoring-batches", json={"course_version_id": 1, "rubric_version_id": 1})
assert response.status_code == 200, response.text
batch_id = response.json()["id"]
run_batch(batch_id, session_factory=session_factory, client_factory=lambda db, batch: FakeModel(), embedder=fake_embed,
retriever=lambda db, **kwargs: retrieve(db, embedder=fake_embed, **kwargs))
result = client.get(f"/api/projects/{project_id}/scores?batch_id={batch_id}").json()
assert result["totals"]["overall"] == 50
assert all(row["evidence"] and row["evidence"][0]["page"] >= 1 for row in result["rows"])
assert client.get(result["rows"][0]["evidence"][0]["image_url"]).content[:8] == b"\x89PNG\r\n\x1a\n"
score_id = result["rows"][0]["score_id"]
reviewed = client.put(f"/api/criterion-scores/{score_id}/review", json={"score": 20, "comment": "教师核定", "reason": "核查原文"})
assert reviewed.status_code == 200
assert reviewed.json()["model_score"] != reviewed.json()["teacher_score"]
assert len(client.get(f"/api/criterion-scores/{score_id}/revisions").json()) == 1
excel = client.post("/api/exports/excel", json={"batch_id": batch_id})
pdf = client.post("/api/exports/project-pdf", json={"batch_id": batch_id, "project_id": project_id})
assert excel.status_code == pdf.status_code == 200
assert client.get(f"/api/exports/{excel.json()['id']}/download").content[:2] == b"PK"
assert client.get(f"/api/exports/{pdf.json()['id']}/download").content[:4] == b"%PDF"
finally:
app.dependency_overrides.clear()