This commit is contained in:
Your Name
2026-04-22 14:13:21 +08:00
parent e0406b5d0e
commit 7cbde2aa78
145 changed files with 23086 additions and 2243 deletions

View File

@@ -0,0 +1,237 @@
import unittest
from unittest.mock import patch
from app.services.dashboard import fetch_overview
class _FakeCursor:
def __init__(self, responses):
self._responses = list(responses)
def execute(self, sql, params=None):
self._last_sql = sql
self._last_params = params
def fetchone(self):
if self._responses:
return self._responses.pop(0)
return (0,)
def __enter__(self):
return self
def __exit__(self, exc_type, exc, tb):
return False
class _FakeConnection:
def __init__(self, responses):
self._cursor = _FakeCursor(responses)
def cursor(self):
return self._cursor
def __enter__(self):
return self
def __exit__(self, exc_type, exc, tb):
return False
class DashboardServiceTests(unittest.TestCase):
@patch("app.services.dashboard._fetch_active_jobs_aggregate")
@patch("app.services.dashboard.get_detect_capacity_plan")
@patch("app.services.dashboard.get_detect_queue_health")
@patch("app.services.dashboard.get_runtime_status")
@patch("app.services.dashboard.get_active_detect_job_summary")
@patch("app.services.dashboard.get_db")
def test_fetch_overview_includes_ops_metrics(
self,
mock_get_db,
mock_get_active_detect_job_summary,
mock_get_runtime_status,
mock_get_detect_queue_health,
mock_get_detect_capacity_plan,
mock_fetch_active_jobs_aggregate,
) -> None:
mock_get_db.return_value = _FakeConnection(
responses=[
(1000,),
(900,),
(10,),
(5,),
(0,),
(1,),
(430,),
(420,),
(17,),
]
)
mock_fetch_active_jobs_aggregate.return_value = {
"active_jobs_total": 3,
"queue": {
"items_total": 5200,
"pending": 4700,
"claimed": 11,
"running": 165,
"completed": 300,
"blacklisted": 12,
"failed": 7,
},
"throughput": {
"processed_recent": 30,
"processed_per_minute": 2.0,
"completed_recent": 20,
"blacklisted_recent": 1,
"failed_recent": 2,
},
"retry_total": 12,
"steps": [
{
"step_code": "detect_register",
"step_name": "注册状态检测",
"items_pending": 185,
"items_running": 3,
"items_claimed": 0,
"items_completed": 7,
"items_blacklisted": 0,
"items_failed": 0,
"processed_recent": 20,
"processed_per_minute": 1.33,
}
],
"nodes": [
{
"node_code": "mainland-controller-01",
"items_running": 120,
"items_claimed": 0,
"processed_recent": 20,
"processed_per_minute": 1.33,
"completed_recent": 15,
"failed_recent": 1,
"blacklisted_recent": 0,
}
],
}
mock_get_active_detect_job_summary.return_value = {
"job_id": 76,
"job_code": "sync-overseas-3612",
"items_pending": 185,
"items_running": 8,
"items_completed": 7,
"items_blacklisted": 0,
"items_failed": 0,
}
mock_get_runtime_status.return_value = {
"worker": {"running": True, "mode": "linux-systemd", "expected_on_this_node": True},
"node": {"region": "overseas", "role": "control"},
"cluster": {"summary": {"online_worker_nodes": 2, "dedicated_online_worker_nodes": 1, "online_control_nodes": 1}},
"detect": {
"backlog": {
"pending_total": 9438,
"claimed_total": 410,
"running_total": 15,
"completed_total": 951,
"blacklisted_total": 0,
"failed_total": 137,
"register_pending": 8487,
"downstream_pending": 951,
}
},
}
mock_get_detect_queue_health.return_value = {
"has_active_job": True,
"job": {"job_id": 76, "job_code": "sync-overseas-3612", "status": "running", "progress_percent": 3.5},
"queue": {
"items_total": 200,
"pending": 185,
"claimed": 0,
"display_claimed": 0,
"running": 8,
"display_running": 165,
"completed": 7,
"blacklisted": 0,
"failed": 0,
},
"throughput": {"processed_recent": 0, "processed_per_minute": 0},
"steps": [
{
"step_code": "detect_register",
"step_name": "注册状态检测",
"items_pending": 185,
"items_running": 165,
"items_claimed": 0,
"items_completed": 7,
"items_blacklisted": 0,
"items_failed": 0,
"processed_recent": 0,
"processed_per_minute": 0.0,
}
],
"runtime_activity": {
"step_stats": {
"detect_360_site": {
"step_code": "detect_360_site",
"started_recent": 269,
"processed_recent": 6,
"completed_recent": 6,
"failed_recent": 0,
"blacklisted_recent": 0,
}
}
},
"nodes": [
{
"node_code": "mainland-controller-01",
"items_running": 165,
"items_claimed": 0,
"processed_recent": 0,
"processed_per_minute": 0.0,
"completed_recent": 0,
"failed_recent": 0,
"blacklisted_recent": 0,
}
],
}
mock_get_detect_capacity_plan.return_value = {
"estimated_hours_remaining": 1.5,
"remaining_items": 193,
"recommended_additional_workers": 1,
}
data = fetch_overview()
self.assertEqual("sync-overseas-3612", data["active_job"]["job_code"])
self.assertEqual(3, data["active_jobs_aggregate"]["active_jobs_total"])
self.assertEqual(9438, data["active_jobs_aggregate"]["queue"]["pending"])
self.assertEqual(410, data["active_jobs_aggregate"]["queue"]["claimed"])
self.assertEqual(15, data["active_jobs_aggregate"]["queue"]["running"])
self.assertEqual(951, data["active_jobs_aggregate"]["queue"]["completed"])
self.assertEqual(137, data["active_jobs_aggregate"]["queue"]["failed"])
self.assertEqual("mainland-controller-01", data["active_jobs_aggregate"]["nodes"][0]["node_code"])
self.assertEqual(900, data["pending_total"])
self.assertEqual(10, data["completed_total"])
self.assertEqual(430, data["registerable_total"])
self.assertEqual(420, data["purchasable_total"])
self.assertEqual(185, data["queue_pending_total"])
self.assertEqual(8, data["queue_running_total"])
self.assertEqual(165, data["queue_display_running_total"])
self.assertEqual(7, data["queue_completed_total"])
self.assertEqual(9438, data["backlog_pending_total"])
self.assertEqual(8487, data["backlog_register_pending_total"])
self.assertEqual(951, data["backlog_downstream_pending_total"])
self.assertEqual(12, data["retry_total"])
self.assertEqual("注册状态检测", data["bottleneck_step"]["step_name"])
self.assertEqual(0.0, data["processed_per_minute"])
self.assertEqual(0, data["processed_recent"])
self.assertEqual(0.0, data["ops_summary"]["processed_per_minute"])
self.assertEqual(1.5, data["ops_summary"]["estimated_hours_remaining"])
self.assertEqual(1, data["active_execution_nodes"])
self.assertEqual(1, data["ops_summary"]["active_execution_nodes"])
self.assertEqual(2, len(data["step_queue"]))
self.assertTrue(any(item["step_code"] == "detect_360_site" for item in data["step_queue"]))
self.assertEqual(1, len(data["node_throughput"]))
if __name__ == "__main__":
unittest.main()