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_feedback import AgentOperationFeedback from app.models.agent_run import AgentRun, AgentToolCall from app.models.user_session_metric import UserSessionMetric from app.services.system_dashboard import SystemDashboardService 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_system_dashboard_service_aggregates_real_runtime_metrics() -> None: now = datetime.now(UTC) with build_session() as db: db.add( AgentRun( run_id="run-dashboard-001", agent="orchestrator", source="user_message", user_id="chen.yuqing@example.com", status="succeeded", started_at=now - timedelta(hours=3), finished_at=now - timedelta(hours=3, minutes=-1), tool_calls=[ AgentToolCall( run_id="run-dashboard-001", tool_type="llm", tool_name="expense_claim.review", request_json={"prompt_tokens": 120}, response_json={"completion_tokens": 80}, status="succeeded", duration_ms=1800, created_at=now - timedelta(hours=3), ), AgentToolCall( run_id="run-dashboard-001", tool_type="ocr", tool_name="invoice.ocr", request_json={"image_count": 1}, response_json={"message": "识别失败"}, status="failed", duration_ms=2600, error_message="low confidence", created_at=now - timedelta(hours=2), ), ], ) ) db.add( AgentRun( run_id="run-dashboard-002", agent="hermes", source="schedule", user_id="gu.chengyu@example.com", status="failed", started_at=now - timedelta(hours=1), finished_at=now, tool_calls=[ AgentToolCall( run_id="run-dashboard-002", tool_type="knowledge", tool_name="policy.rag", request_json={"total_tokens": 90}, response_json={}, status="succeeded", duration_ms=900, created_at=now - timedelta(hours=1), ), ], ) ) db.add_all( [ UserSessionMetric( session_id="session-dashboard-001", username="chen.yuqing@example.com", display_name="陈雨晴", email="chen.yuqing@example.com", login_at=now - timedelta(hours=4), logout_at=now - timedelta(hours=3), duration_ms=60 * 60 * 1000, activity_event_count=16, status="closed", ), UserSessionMetric( session_id="session-dashboard-002", username="gu.chengyu@example.com", display_name="顾成宇", email="gu.chengyu@example.com", login_at=now - timedelta(minutes=25), last_activity_at=now - timedelta(minutes=5), activity_event_count=9, status="active", ), ] ) db.add_all( [ AgentOperationFeedback( run_id="run-dashboard-001", user_id="chen.yuqing@example.com", agent="orchestrator", rating=5, created_at=now - timedelta(hours=2), ), AgentOperationFeedback( run_id="run-dashboard-002", user_id="gu.chengyu@example.com", agent="hermes", rating=2, created_at=now - timedelta(hours=1), ), ] ) db.commit() dashboard = SystemDashboardService(db).build_dashboard(days=7) assert dashboard.has_real_data is True assert dashboard.totals["toolCalls"] == 3 assert dashboard.totals["modelTokens"] >= 290 assert dashboard.totals["onlineUsers"] == 1 assert dashboard.totals["executionSuccessRate"] == 50.0 assert dashboard.totals["positiveFeedback"] == 1 assert dashboard.totals["negativeFeedback"] == 1 assert dashboard.user_token_usage[0]["tokens"] >= 200 assert "陈雨晴" in {item["name"] for item in dashboard.user_token_usage} assert dashboard.accuracy_comparison["correct"][ dashboard.accuracy_comparison["categories"].index("报销预审") ] == 1 assert dashboard.accuracy_comparison["wrong"][ dashboard.accuracy_comparison["categories"].index("异常诊断") ] == 1 def test_system_dashboard_counts_online_users_from_active_sessions_across_window() -> None: now = datetime.now(UTC) with build_session() as db: db.add_all( [ UserSessionMetric( session_id="session-online-old-001", username="active.user@example.com", display_name="在线用户", email="active.user@example.com", login_at=now - timedelta(days=2), last_activity_at=now - timedelta(days=2), activity_event_count=3, status="active", ), UserSessionMetric( session_id="session-online-old-002", username="active.user@example.com", display_name="在线用户", email="active.user@example.com", login_at=now - timedelta(minutes=15), last_activity_at=now - timedelta(minutes=15), activity_event_count=5, status="active", ), UserSessionMetric( session_id="session-closed-outside-window", username="offline.user@example.com", display_name="离线用户", email="offline.user@example.com", login_at=now - timedelta(days=3), logout_at=now - timedelta(days=2, hours=23), duration_ms=60 * 60 * 1000, status="closed", ), ] ) db.commit() dashboard = SystemDashboardService(db).build_dashboard(days=1) login_users = dashboard.login_wave["loginUsers"] assert dashboard.totals["onlineUsers"] == 1 assert max(login_users) == 1 assert "00:00" in dashboard.login_wave["labels"] assert "23:00" in dashboard.login_wave["labels"]