feat: add ops center and node onboarding flow
This commit is contained in:
256
domain-api/tests/test_ops_service_node_scene_log.py
Normal file
256
domain-api/tests/test_ops_service_node_scene_log.py
Normal 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()
|
||||
Reference in New Issue
Block a user