AgentEvalTool/tests/unit/test_intelligent_eval_model.py
sinohqb 1317552701 feat(intelligent-eval): add backend for OpenClaw-driven intelligent evaluation (tickets 01-04)
Introduce 智能评估 as an evaluation paradigm parallel to static evaluation,
driven by OpenClaw. The platform supplies storage, lifecycle, and reporting;
OpenClaw plans and executes.

- Data model: IntelligentEval + Session + Message tables (new, not reusing exploration)
- Lifecycle state machine: draft → planning → pending_approval → executing → completed/cancelled/failed
- Session API: create/message (channel-forwarded)/close with turn accounting
- Report API: pydantic-validated structured report, executing → completed, Markdown export (pure renderer)
- Alembic migration for the three tables; domain glossary added to CONTEXT.md
2026-08-05 03:18:52 +08:00

161 lines
6.1 KiB
Python

"""Smoke tests for intelligent eval data model (ticket 01)."""
import pytest
from agenteval.intelligent_eval.models import (
IntelligentEval,
IntelligentEvalMessage,
IntelligentEvalSession,
IntelligentEvalSessionStatus,
IntelligentEvalStatus,
)
from agenteval.intelligent_eval.repository import (
IntelligentEvalMessageRepository,
IntelligentEvalRepository,
IntelligentEvalSessionRepository,
)
from agenteval.storage.db import EvalTargetDB
from sqlalchemy.pool import StaticPool
from sqlmodel import Session, SQLModel, create_engine
@pytest.fixture
def db_session():
engine = create_engine("sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool)
SQLModel.metadata.create_all(engine)
session = Session(engine)
target = EvalTargetDB(id="t1", name="test-target")
session.add(target)
session.commit()
yield session
session.close()
class TestIntelligentEvalRepository:
def test_create_and_get(self, db_session):
repo = IntelligentEvalRepository(db_session)
ev = repo.create(IntelligentEval(
name="test-eval",
target_id="t1",
goal="evaluate customer service",
seeds={"personas": [], "goals": []},
intent="test intent",
role_description="impatient customer",
time_window_hours=24,
))
assert ev.id is not None
assert ev.status == IntelligentEvalStatus.DRAFT
assert ev.name == "test-eval"
assert ev.time_window_hours == 24
fetched = repo.get(ev.id)
assert fetched is not None
assert fetched.goal == "evaluate customer service"
assert fetched.seeds == {"personas": [], "goals": []}
def test_list_all(self, db_session):
repo = IntelligentEvalRepository(db_session)
repo.create(IntelligentEval(name="eval-1", target_id="t1"))
repo.create(IntelligentEval(name="eval-2", target_id="t1"))
all_evals = repo.list_all()
assert len(all_evals) == 2
def test_status_transitions(self, db_session):
repo = IntelligentEvalRepository(db_session)
ev = repo.create(IntelligentEval(name="eval", target_id="t1"))
assert ev.status == IntelligentEvalStatus.DRAFT
ev = repo.transition_status(ev.id, IntelligentEvalStatus.PLANNING)
assert ev.status == IntelligentEvalStatus.PLANNING
ev = repo.transition_status(ev.id, IntelligentEvalStatus.PENDING_APPROVAL)
assert ev.status == IntelligentEvalStatus.PENDING_APPROVAL
ev = repo.transition_status(ev.id, IntelligentEvalStatus.EXECUTING)
assert ev.status == IntelligentEvalStatus.EXECUTING
assert ev.started_at is not None
ev = repo.transition_status(ev.id, IntelligentEvalStatus.COMPLETED)
assert ev.status == IntelligentEvalStatus.COMPLETED
assert ev.completed_at is not None
def test_plan_and_report_json(self, db_session):
repo = IntelligentEvalRepository(db_session)
ev = repo.create(IntelligentEval(name="eval", target_id="t1"))
plan = {"dimensions": ["退货"], "virtual_users": [], "estimated_sessions": 3}
ev.plan = plan
ev.status = IntelligentEvalStatus.PENDING_APPROVAL
ev = repo.update(ev)
assert ev.plan == plan
report = {"summary": "good", "findings": []}
ev.report = report
ev = repo.update(ev)
assert ev.report == report
class TestIntelligentEvalSessionRepository:
def test_create_and_list(self, db_session):
eval_repo = IntelligentEvalRepository(db_session)
ev = eval_repo.create(IntelligentEval(name="eval", target_id="t1"))
sess_repo = IntelligentEvalSessionRepository(db_session)
sess = sess_repo.create(IntelligentEvalSession(
eval_id=ev.id,
target_id="t1",
persona={"name": "user1", "patience": "low"},
goal="complete return",
dimension="退货流程",
))
assert sess.id is not None
assert sess.status == IntelligentEvalSessionStatus.RUNNING
assert sess.persona == {"name": "user1", "patience": "low"}
sessions = sess_repo.list_by_eval(ev.id)
assert len(sessions) == 1
def test_close_session(self, db_session):
eval_repo = IntelligentEvalRepository(db_session)
ev = eval_repo.create(IntelligentEval(name="eval", target_id="t1"))
sess_repo = IntelligentEvalSessionRepository(db_session)
sess = sess_repo.create(IntelligentEvalSession(eval_id=ev.id, target_id="t1"))
verdict = {"goal_achieved": True, "issues": []}
closed = sess_repo.close(sess.id, verdict)
assert closed.status == IntelligentEvalSessionStatus.COMPLETED
assert closed.verdict == verdict
assert closed.closed_at is not None
def test_increment_turns(self, db_session):
eval_repo = IntelligentEvalRepository(db_session)
ev = eval_repo.create(IntelligentEval(name="eval", target_id="t1"))
sess_repo = IntelligentEvalSessionRepository(db_session)
sess = sess_repo.create(IntelligentEvalSession(eval_id=ev.id, target_id="t1"))
assert sess.turn_count == 0
sess_repo.increment_turns(sess.id)
sess_repo.increment_turns(sess.id)
updated = sess_repo.get(sess.id)
assert updated.turn_count == 2
class TestIntelligentEvalMessageRepository:
def test_create_and_list(self, db_session):
eval_repo = IntelligentEvalRepository(db_session)
ev = eval_repo.create(IntelligentEval(name="eval", target_id="t1"))
sess_repo = IntelligentEvalSessionRepository(db_session)
sess = sess_repo.create(IntelligentEvalSession(eval_id=ev.id, target_id="t1"))
msg_repo = IntelligentEvalMessageRepository(db_session)
msg_repo.create(IntelligentEvalMessage(session_id=sess.id, role="user", content="hello"))
msg_repo.create(IntelligentEvalMessage(session_id=sess.id, role="assistant", content="hi", latency_ms=120))
messages = msg_repo.list_by_session(sess.id)
assert len(messages) == 2
assert messages[0].role == "user"
assert messages[1].role == "assistant"
assert messages[1].latency_ms == 120