from __future__ import annotations from datetime import UTC, datetime, timedelta from sqlalchemy import create_engine from sqlalchemy.orm import Session, sessionmaker from sqlalchemy.pool import StaticPool from app.db.base import Base from app.models.agent_run import AgentRun, AgentToolCall from app.services.digital_employee_dashboard import DigitalEmployeeDashboardService def build_session() -> Session: engine = create_engine( "sqlite+pysqlite:///:memory:", connect_args={"check_same_thread": False}, poolclass=StaticPool, ) Base.metadata.create_all(bind=engine) session_factory = sessionmaker(bind=engine, autoflush=False, autocommit=False) return session_factory() def test_digital_employee_dashboard_aggregates_daily_work_from_agent_runs() -> None: now = datetime.now(UTC) with build_session() as db: db.add_all( [ AgentRun( run_id="run-digital-risk-001", agent="hermes", source="schedule", user_id="system", status="succeeded", route_json={"task_code": "task.hermes.global_risk_scan"}, result_summary="财务风险图谱巡检完成。", started_at=now - timedelta(hours=4), finished_at=now - timedelta(hours=4, minutes=-3), tool_calls=[ AgentToolCall( run_id="run-digital-risk-001", tool_type="rule_engine", tool_name="digital_employee.financial_risk_graph.scan", request_json={"task_type": "global_risk_scan"}, response_json={ "scanned_claim_count": 18, "risk_observation_count": 3, }, status="succeeded", duration_ms=1200, created_at=now - timedelta(hours=4), ) ], ), AgentRun( run_id="run-digital-clue-001", agent="hermes", source="schedule", user_id="system", status="failed", route_json={"report_type": "risk_clue_collect"}, result_summary="风险线索归集失败。", started_at=now - timedelta(hours=3), finished_at=now - timedelta(hours=3, minutes=-1), tool_calls=[ AgentToolCall( run_id="run-digital-clue-001", tool_type="database", tool_name="digital_employee.risk_clue.collect", request_json={"task_type": "risk_clue_collect"}, response_json={ "fact_count": 12, "rule_hit_count": 5, "risk_clue_count": 2, }, status="failed", duration_ms=800, error_message="collector failed", created_at=now - timedelta(hours=3), ) ], ), AgentRun( run_id="run-digital-knowledge-001", agent="hermes", source="user_message", user_id="admin", status="running", route_json={ "job_type": "knowledge_index_sync", "requested_document_ids": ["doc-1", "doc-2"], }, result_summary="知识归纳任务已入队。", started_at=now - timedelta(hours=1), ), AgentRun( run_id="run-user-001", agent="user_agent", source="user_message", user_id="employee", status="succeeded", result_summary="普通报销预审。", started_at=now - timedelta(hours=2), finished_at=now - timedelta(hours=2, minutes=-1), tool_calls=[ AgentToolCall( run_id="run-user-001", tool_type="llm", tool_name="expense_claim.review", request_json={}, response_json={}, status="succeeded", duration_ms=500, created_at=now - timedelta(hours=2), ) ], ), ] ) db.commit() dashboard = DigitalEmployeeDashboardService(db).build_dashboard(days=7) assert dashboard.has_real_data is True assert dashboard.totals["totalRuns"] == 3 assert dashboard.totals["successRuns"] == 1 assert dashboard.totals["failedRuns"] == 1 assert dashboard.totals["runningRuns"] == 1 assert dashboard.totals["toolCalls"] == 2 assert dashboard.totals["riskObservations"] == 3 assert dashboard.totals["riskClues"] == 2 assert dashboard.totals["knowledgeDocuments"] == 2 assert dashboard.totals["businessOutputs"] == 7 assert dashboard.totals["successRate"] == 33.3 category_counts = {item["name"]: item["count"] for item in dashboard.category_distribution} assert category_counts["评估"] == 1 assert category_counts["升级"] == 1 assert category_counts["整理"] == 1 assert category_counts["积累"] == 0 task_names = {item["name"] for item in dashboard.task_distribution} assert task_names == {"财务风险图谱巡检", "风险线索归集", "知识制度整理"} assert sum(item["total"] for item in dashboard.daily_work) == 3 assert dashboard.recent_runs[0]["runId"] == "run-digital-knowledge-001" assert dashboard.recent_runs[0]["statusLabel"] == "运行中" def test_digital_employee_dashboard_keeps_empty_payload_without_fake_data() -> None: with build_session() as db: dashboard = DigitalEmployeeDashboardService(db).build_dashboard(days=7) assert dashboard.has_real_data is False assert dashboard.totals["totalRuns"] == 0 assert dashboard.daily_work assert dashboard.task_distribution == []