feat: add ops center and node onboarding flow

This commit is contained in:
Your Name
2026-04-18 23:52:51 +08:00
parent 246838ae4c
commit b9c29481b5
142 changed files with 89727 additions and 186 deletions

View File

@@ -0,0 +1,256 @@
import unittest
from unittest.mock import patch
from app.services.ops_service import get_ops_node_scene_log
class OpsServiceNodeSceneLogTests(unittest.TestCase):
def _runtime_payload_with_worker_logs(self) -> dict:
return {
"detect": {
"log_sync": {
"enabled": True,
"mode": "key",
"line_count": 2,
"source_node_count": 1,
"source_nodes": ["mainland-worker-01"],
"source_node_summaries": [
{
"node_code": "mainland-worker-01",
"line_count": 2,
"key_line_count": 2,
"full_line_count": 0,
"last_at": "2026-04-18 05:02:00",
"last_line": "[2026-04-18 05:02:00] [mainland-worker-01] 域名检测完成: alpha.com",
}
],
"preview_lines": [
"[2026-04-18 05:00:00] [mainland-worker-01] 开始检测域名: alpha.com",
"[2026-04-18 05:02:00] [mainland-worker-01] 域名检测完成: alpha.com",
],
"last_at": "2026-04-18 05:02:00",
"last_line": "[2026-04-18 05:02:00] [mainland-worker-01] 域名检测完成: alpha.com",
},
"participation_summary": {
"participating_nodes": 1,
"dispatch_active_nodes": 1,
"recent_only_nodes": 0,
"non_participating_nodes": 1,
"standby_nodes": 1,
"load_syncing_nodes": 0,
"effective_online_nodes": 2,
"dedicated_worker_nodes": 2,
"controller_worker_nodes": 0,
"dispatch_active_node_codes": ["mainland-worker-01"],
"recent_only_node_codes": [],
"non_participating_node_codes": ["mainland-worker-02"],
"standby_node_codes": ["mainland-worker-02"],
"load_syncing_node_codes": [],
"summary": "有效执行节点 2 台;正在执行/领任务 1 台;近窗刚有吞吐 0 台;在线但未参与 1 台",
},
"participating_nodes": [
{
"node_code": "mainland-worker-01",
"region": "mainland",
"role": "worker",
"status": "busy",
"current_load": 2,
"last_heartbeat_at": "2026-04-18 05:02:10",
"participation_state": "claimed",
"participation_label": "已领待跑",
"participation_reason": "已领取 2 项任务,等待线程继续执行。",
"is_dispatch_active": True,
}
],
"non_participating_nodes": [
{
"node_code": "mainland-worker-02",
"region": "mainland",
"role": "worker",
"status": "online",
"current_load": 0,
"last_heartbeat_at": "2026-04-18 05:02:11",
"participation_state": "standby",
"participation_label": "在线待命",
"participation_reason": "当前节点在线,但尚未参与本轮检测。",
"is_dispatch_active": False,
}
],
"active_job": {
"job_code": "detect-001",
"status": "running",
"current_cycle_token": "cycle-1",
"current_cycle_events": [
{
"event_type": "worker_log",
"created_at": "2026-04-18 05:02:00",
"node_code": "mainland-worker-01",
"message": "域名检测完成: alpha.com",
"payload": {"cycle_token": "cycle-1", "log_mode": "key"},
},
{
"event_type": "worker_log",
"created_at": "2026-04-18 05:01:00",
"node_code": "mainland-worker-01",
"message": "代理池刷新完成",
"payload": {"cycle_token": "cycle-1", "log_mode": "full"},
},
{
"event_type": "worker_log",
"created_at": "2026-04-18 05:00:00",
"node_code": "mainland-worker-01",
"message": "开始检测域名: alpha.com",
"payload": {"cycle_token": "cycle-1", "log_mode": "key"},
},
{
"event_type": "worker_log",
"created_at": "2026-04-18 04:59:00",
"node_code": "mainland-worker-01",
"message": "旧周期日志",
"payload": {"cycle_token": "cycle-0", "log_mode": "key"},
},
],
},
},
"cluster": {
"nodes": [
{
"node_code": "mainland-worker-01",
"region": "mainland",
"role": "worker",
"status": "busy",
"current_load": 2,
"last_heartbeat_at": "2026-04-18 05:02:10",
},
{
"node_code": "mainland-worker-02",
"region": "mainland",
"role": "worker",
"status": "online",
"current_load": 0,
"last_heartbeat_at": "2026-04-18 05:02:11",
},
]
},
}
@patch("app.services.ops_service.get_runtime_status")
def test_node_scene_log_filters_key_mode_records_for_participating_node(self, mock_get_runtime_status) -> None:
mock_get_runtime_status.return_value = self._runtime_payload_with_worker_logs()
payload = get_ops_node_scene_log("mainland-worker-01", limit=10)
self.assertEqual("mainland-worker-01", payload["node_code"])
self.assertEqual("healthy", payload["status"])
self.assertEqual("关键覆盖", payload["status_label"])
self.assertEqual("key", payload["mode"])
self.assertTrue(payload["log_sync_enabled"])
self.assertTrue(payload["participation"]["detect_participating"])
self.assertEqual(2, payload["records_total"])
self.assertEqual(
[
"开始检测域名: alpha.com",
"域名检测完成: alpha.com",
],
[item["message"] for item in payload["records"]],
)
self.assertEqual(2, payload["source_summary"]["line_count"])
self.assertEqual(2, payload["source_summary"]["key_line_count"])
self.assertEqual(0, payload["source_summary"]["full_line_count"])
self.assertEqual("ops_observability_contract", payload["contract_navigation"]["primary_contract_key"])
@patch("app.services.ops_service.get_runtime_status")
def test_node_scene_log_can_request_full_mode_records(self, mock_get_runtime_status) -> None:
mock_get_runtime_status.return_value = self._runtime_payload_with_worker_logs()
payload = get_ops_node_scene_log("mainland-worker-01", limit=10, mode="full")
self.assertEqual("full_capture", payload["status"])
self.assertEqual("full", payload["mode"])
self.assertEqual(3, payload["records_total"])
self.assertEqual(
[
"开始检测域名: alpha.com",
"代理池刷新完成",
"域名检测完成: alpha.com",
],
[item["message"] for item in payload["records"]],
)
self.assertEqual(3, payload["source_summary"]["line_count"])
self.assertEqual(2, payload["source_summary"]["key_line_count"])
self.assertEqual(1, payload["source_summary"]["full_line_count"])
@patch("app.services.ops_service.get_runtime_status")
def test_node_scene_log_marks_waiting_sample_for_missing_participating_node(self, mock_get_runtime_status) -> None:
mock_get_runtime_status.return_value = {
"detect": {
"log_sync": {
"enabled": True,
"mode": "key",
"line_count": 0,
"source_node_count": 0,
"source_nodes": [],
"source_node_summaries": [],
"preview_lines": [],
"last_at": "",
"last_line": "",
},
"participation_summary": {
"participating_nodes": 1,
"dispatch_active_nodes": 1,
"recent_only_nodes": 0,
"non_participating_nodes": 0,
"standby_nodes": 0,
"load_syncing_nodes": 0,
"effective_online_nodes": 1,
"dedicated_worker_nodes": 1,
"controller_worker_nodes": 0,
"dispatch_active_node_codes": ["mainland-worker-02"],
"recent_only_node_codes": [],
"non_participating_node_codes": [],
"standby_node_codes": [],
"load_syncing_node_codes": [],
"summary": "有效执行节点 1 台;正在执行/领任务 1 台;近窗刚有吞吐 0 台;在线但未参与 0 台",
},
"participating_nodes": [
{
"node_code": "mainland-worker-02",
"region": "mainland",
"role": "worker",
"status": "busy",
"current_load": 1,
"last_heartbeat_at": "2026-04-18 05:05:00",
"participation_state": "running",
"participation_label": "正在执行",
"participation_reason": "当前存在执行中工作负载。",
"is_dispatch_active": True,
}
],
"non_participating_nodes": [],
"active_job": {"job_code": "detect-002", "status": "running", "current_cycle_events": []},
},
"cluster": {
"nodes": [
{
"node_code": "mainland-worker-02",
"region": "mainland",
"role": "worker",
"status": "busy",
"current_load": 1,
"last_heartbeat_at": "2026-04-18 05:05:00",
}
]
},
}
payload = get_ops_node_scene_log("mainland-worker-02")
self.assertEqual("waiting_sample", payload["status"])
self.assertEqual("等待样本", payload["status_label"])
self.assertEqual(0, payload["records_total"])
self.assertTrue(payload["participation"]["detect_participating"])
self.assertIn("现场样本尚未形成", payload["summary"])
if __name__ == "__main__":
unittest.main()