import unittest from unittest.mock import patch from app.services.ops_service import get_ops_link_snapshot class OpsServiceLinkSnapshotTests(unittest.TestCase): @patch("app.services.ops_service.get_ops_overview") def test_link_snapshot_highlights_log_sync_gap_on_active_scene(self, mock_get_ops_overview) -> None: mock_get_ops_overview.return_value = { "current_topology": { "node_code": "overseas-control-01", "node_region": "overseas", "node_role": "control", "worker_mode": "linux-systemd", "sync_push_enabled": True, "sync_target_api_base_url": "http://152.53.37.118:8100", }, "cluster_summary": { "online_control_nodes": 2, "online_worker_nodes": 3, "dedicated_online_worker_nodes": 1, "busy_nodes": ["mainland-worker-01", "overseas-control-01"], }, "runtime_summary": { "readiness_status": "ready", "readiness_summary": "当前多机与跨地域骨架已进入可联调状态。", "phase_label": "running", "phase_detail": "当前任务正在推进", "active_job_code": "detect-20260417164852-75f7cc", "progress_percent": 42.5, }, "execution_scene": { "participation_summary": { "effective_online_nodes": 3, "participating_nodes": 3, "dispatch_active_nodes": 2, "recent_only_nodes": 1, "non_participating_nodes": 0, "standby_nodes": 0, "load_syncing_nodes": 0, "dispatch_active_node_codes": ["mainland-worker-01", "overseas-control-01"], "non_participating_node_codes": [], }, "log_sync": { "enabled": False, "mode": "key", "line_count": 0, "source_node_count": 0, "covered_participating_node_count": 0, "participating_node_count": 3, "missing_participating_nodes": [ "mainland-controller-01", "mainland-worker-01", "overseas-control-01", ], "last_at": "", "preview_lines": [], }, }, "sync_summary": { "enabled": True, "source_region": "mainland", "target_region": "overseas", "projected_batches": 0, "failed_batches": 0, "records_total": 2513, }, "recommendation": { "key": "enable-scene-log-sync", "priority": "先补现场日志回传", "summary": "当前有 3 台节点正在真实参与检测,但海外控制面还看不到过程日志。", "reason": "先把远端日志回传切到关键模式,才能看到阶段、异常、代理与执行过程。", "primary_label": "开启关键回传", "primary_action_code": "enable_log_sync_key", "primary_node_codes": ["mainland-controller-01", "mainland-worker-01", "overseas-control-01"], "primary_action_payload": {}, "secondary_label": "开启全量回传", "secondary_action_code": "enable_log_sync_full", "secondary_node_codes": ["mainland-controller-01", "mainland-worker-01", "overseas-control-01"], "secondary_action_payload": {}, }, } snapshot = get_ops_link_snapshot() self.assertEqual("attention", snapshot["status"]) self.assertIn("日志回传", snapshot["headline"]) self.assertIn("活跃任务 detect-20260417164852-75f7cc", snapshot["summary_lines"][2]) self.assertIn("远端日志:关闭", snapshot["summary_lines"][4]) self.assertEqual("enable_log_sync_key", snapshot["next_actions"][0]["action_code"]) self.assertEqual(3, snapshot["execution"]["participating_nodes"]) self.assertFalse(snapshot["log_sync"]["enabled"]) @patch("app.services.ops_service.get_ops_overview") def test_link_snapshot_reports_ready_when_scene_is_observable(self, mock_get_ops_overview) -> None: mock_get_ops_overview.return_value = { "current_topology": { "node_code": "overseas-control-01", "node_region": "overseas", "node_role": "control", "worker_mode": "linux-systemd", "sync_push_enabled": True, "sync_target_api_base_url": "http://152.53.37.118:8100", }, "cluster_summary": { "online_control_nodes": 2, "online_worker_nodes": 2, "dedicated_online_worker_nodes": 1, "busy_nodes": ["mainland-worker-01"], }, "runtime_summary": { "readiness_status": "ready", "readiness_summary": "ok", "phase_label": "running", "phase_detail": "检测任务正常推进", "active_job_code": "detect-001", "progress_percent": 66.0, }, "execution_scene": { "participation_summary": { "effective_online_nodes": 2, "participating_nodes": 2, "dispatch_active_nodes": 2, "recent_only_nodes": 0, "non_participating_nodes": 0, "standby_nodes": 0, "load_syncing_nodes": 0, "dispatch_active_node_codes": ["mainland-worker-01", "mainland-controller-01"], "non_participating_node_codes": [], }, "log_sync": { "enabled": True, "mode": "key", "line_count": 18, "source_node_count": 2, "covered_participating_node_count": 2, "participating_node_count": 2, "missing_participating_nodes": [], "last_at": "2026-04-17 22:20:00", "preview_lines": [ "[2026-04-17 22:19:59] [mainland-worker-01] 开始检测域名: alpha.com", "[2026-04-17 22:20:00] [mainland-controller-01] 域名检测完成: beta.com", ], }, }, "sync_summary": { "enabled": True, "source_region": "mainland", "target_region": "overseas", "projected_batches": 0, "failed_batches": 0, "records_total": 2600, }, "recommendation": { "key": "inspect-participating", "priority": "先看执行现场", "summary": "当前有 2 台节点正在真实参与检测,优先回收它们的标准巡检结果。", "reason": "真正参与检测的节点最接近现场。", "primary_label": "执行标准巡检", "primary_action_code": "run_inspection_participating", "primary_node_codes": ["mainland-worker-01", "mainland-controller-01"], "primary_action_payload": {}, "secondary_label": "打开诊断模板", "secondary_action_code": "open_diagnostics_participating", "secondary_node_codes": ["mainland-worker-01", "mainland-controller-01"], "secondary_action_payload": {}, }, } snapshot = get_ops_link_snapshot() self.assertEqual("ready", snapshot["status"]) self.assertIn("可观测状态", snapshot["headline"]) self.assertIn("覆盖 2/2", snapshot["summary_lines"][4]) self.assertEqual(2, snapshot["log_sync"]["source_node_count"]) self.assertEqual(2, len(snapshot["next_actions"])) self.assertEqual("run_inspection_participating", snapshot["next_actions"][0]["action_code"]) if __name__ == "__main__": unittest.main()