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 == [] def test_digital_employee_dashboard_counts_finance_dashboard_snapshots() -> None: now = datetime.now(UTC) with build_session() as db: db.add( AgentRun( run_id="run-finance-snapshot-001", agent="hermes", source="schedule", user_id="digital_employee", status="succeeded", route_json={"task_type": "finance_dashboard_snapshot"}, result_summary="finance dashboard snapshot generated", started_at=now - timedelta(minutes=3), finished_at=now - timedelta(minutes=2), tool_calls=[ AgentToolCall( run_id="run-finance-snapshot-001", tool_type="database", tool_name="digital_employee.finance_dashboard.snapshot", request_json={"task_type": "finance_dashboard_snapshot"}, response_json={ "summary": { "finance_snapshot_count": 1, "reimbursement_count": 534, } }, status="succeeded", duration_ms=1200, created_at=now - timedelta(minutes=3), ) ], ) ) db.commit() dashboard = DigitalEmployeeDashboardService(db).build_dashboard(days=7) assert dashboard.totals["financeDashboardSnapshots"] == 1 assert dashboard.totals["businessOutputs"] == 1 assert dashboard.daily_work[-1]["financeDashboardSnapshots"] == 1 assert dashboard.task_distribution[0]["taskType"] == "finance_dashboard_snapshot" def test_digital_employee_dashboard_counts_reminder_outputs() -> None: now = datetime.now(UTC) with build_session() as db: db.add( AgentRun( run_id="run-reminder-scan-001", agent="hermes", source="schedule", user_id="digital_employee", status="succeeded", route_json={"task_type": "digital_employee_reminder_scan"}, result_summary="reminder scan generated", started_at=now - timedelta(minutes=3), finished_at=now - timedelta(minutes=2), tool_calls=[ AgentToolCall( run_id="run-reminder-scan-001", tool_type="database", tool_name="digital_employee.reminder.scan", request_json={"task_type": "digital_employee_reminder_scan"}, response_json={ "summary": { "recipient_count": 3, "reminder_count": 8, "approval_pending_count": 2, } }, status="succeeded", duration_ms=900, created_at=now - timedelta(minutes=3), ) ], ) ) db.commit() dashboard = DigitalEmployeeDashboardService(db).build_dashboard(days=7) assert dashboard.totals["reminders"] == 8 assert dashboard.totals["businessOutputs"] == 8 assert dashboard.daily_work[-1]["reminders"] == 8 assert dashboard.task_distribution[0]["taskType"] == "digital_employee_reminder_scan"