256 lines
10 KiB
Python
256 lines
10 KiB
Python
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from app.services.ops_service import execute_ops_runbook_sequence, resolve_ops_runbook_sequence
|
|
|
|
|
|
class OpsServiceRunbookSequenceTests(unittest.TestCase):
|
|
@patch("app.services.ops_service.get_ops_runbook")
|
|
def test_resolve_ops_runbook_sequence_uses_primary_action(self, mock_get_ops_runbook) -> None:
|
|
mock_get_ops_runbook.return_value = {
|
|
"control_sequences": [
|
|
{
|
|
"key": "release_progression",
|
|
"title": "版本发布与放量",
|
|
"status": "ready",
|
|
"status_label": "可发 Worker 灰度",
|
|
"summary": "可以直接发布。",
|
|
"reason": "launchpad 已就绪",
|
|
"target_scope_label": "Release / Launchpad / 2026.04.18",
|
|
"step_titles": ["确认发布包", "发灰度"],
|
|
"target_node_codes": ["mainland-worker-01"],
|
|
"focus_ref": {
|
|
"kind": "release_hub",
|
|
"release_id": 12,
|
|
"section": "release_launchpad",
|
|
},
|
|
"primary_label": "直接发 Worker 灰度",
|
|
"primary_action_code": "publish_latest_worker",
|
|
"primary_action_payload": {
|
|
"channel": "stable",
|
|
"release_id": 12,
|
|
},
|
|
"primary_focus_ref": {
|
|
"kind": "release_hub",
|
|
"release_id": 12,
|
|
"section": "release_launchpad",
|
|
"mode": "worker",
|
|
},
|
|
}
|
|
]
|
|
}
|
|
|
|
ok, message, data = resolve_ops_runbook_sequence(
|
|
"release_progression",
|
|
{
|
|
"requested_by": "test",
|
|
},
|
|
)
|
|
|
|
self.assertTrue(ok, message)
|
|
self.assertEqual("标准作业路径解析成功", message)
|
|
self.assertEqual("publish_latest_worker", data["driver_action_code"])
|
|
self.assertEqual("直接发 Worker 灰度", data["driver_action_label"])
|
|
self.assertEqual(["mainland-worker-01"], data["driver_node_codes"])
|
|
self.assertEqual("test/runbook/release_progression", data["driver_requested_by"])
|
|
self.assertEqual("Release / Launchpad / 2026.04.18", data["sequence"]["target_scope_label"])
|
|
self.assertEqual(["确认发布包", "发灰度"], data["sequence"]["step_titles"])
|
|
self.assertEqual("release_launchpad", data["sequence"]["focus_ref"]["section"])
|
|
self.assertEqual("worker", data["sequence"]["action_focus_ref"]["mode"])
|
|
self.assertEqual("worker", data["driver_action_payload"]["focus_ref"]["mode"])
|
|
|
|
@patch("app.services.ops_service.get_ops_runbook")
|
|
def test_resolve_ops_runbook_sequence_uses_secondary_action_and_allows_payload_override(
|
|
self,
|
|
mock_get_ops_runbook,
|
|
) -> None:
|
|
mock_get_ops_runbook.return_value = {
|
|
"control_sequences": [
|
|
{
|
|
"key": "node_onboarding",
|
|
"title": "纳管新节点",
|
|
"status": "warning",
|
|
"status_label": "有待接管节点",
|
|
"summary": "先补接入。",
|
|
"reason": "新增节点需要先纳管。",
|
|
"target_node_codes": ["mainland-worker-01"],
|
|
"secondary_label": "跑接管验收",
|
|
"secondary_action_code": "run_acceptance",
|
|
"secondary_action_payload": {
|
|
"node_code": "mainland-worker-01",
|
|
},
|
|
}
|
|
]
|
|
}
|
|
|
|
ok, message, data = resolve_ops_runbook_sequence(
|
|
"node_onboarding",
|
|
{
|
|
"secondary": True,
|
|
"requested_by": "test",
|
|
"node_codes": ["mainland-worker-02"],
|
|
"action_payload": {
|
|
"auto_approve": True,
|
|
},
|
|
},
|
|
)
|
|
|
|
self.assertTrue(ok, message)
|
|
self.assertEqual("标准作业路径解析成功", message)
|
|
self.assertEqual("run_acceptance", data["driver_action_code"])
|
|
self.assertEqual("跑接管验收", data["driver_action_label"])
|
|
self.assertEqual(["mainland-worker-02"], data["driver_node_codes"])
|
|
self.assertTrue(data["sequence"]["secondary"])
|
|
self.assertEqual(
|
|
{
|
|
"node_code": "mainland-worker-01",
|
|
"auto_approve": True,
|
|
},
|
|
data["driver_action_payload"],
|
|
)
|
|
|
|
@patch("app.services.ops_service.execute_driver_action")
|
|
@patch("app.services.ops_service.get_ops_runbook")
|
|
def test_execute_ops_runbook_sequence_uses_primary_action(
|
|
self,
|
|
mock_get_ops_runbook,
|
|
mock_execute_driver_action,
|
|
) -> None:
|
|
mock_get_ops_runbook.return_value = {
|
|
"control_sequences": [
|
|
{
|
|
"key": "release_progression",
|
|
"title": "版本发布与放量",
|
|
"status": "ready",
|
|
"status_label": "可发 Worker 灰度",
|
|
"summary": "可以直接发布。",
|
|
"reason": "launchpad 已就绪",
|
|
"target_node_codes": ["mainland-worker-01"],
|
|
"primary_action_code": "publish_latest_worker",
|
|
"primary_action_payload": {
|
|
"channel": "stable",
|
|
"release_id": 12,
|
|
},
|
|
"secondary_action_code": "focus_release_hub",
|
|
"secondary_action_payload": {
|
|
"release_id": 12,
|
|
},
|
|
}
|
|
]
|
|
}
|
|
mock_execute_driver_action.return_value = (
|
|
True,
|
|
"Release rollout 已创建",
|
|
{
|
|
"handled": True,
|
|
"mode": "smart-release-rollout",
|
|
},
|
|
)
|
|
|
|
ok, message, data = execute_ops_runbook_sequence(
|
|
"release_progression",
|
|
{
|
|
"requested_by": "test",
|
|
},
|
|
)
|
|
|
|
self.assertTrue(ok, message)
|
|
self.assertEqual("Release rollout 已创建", message)
|
|
self.assertTrue(data["handled"])
|
|
self.assertEqual("publish_latest_worker", data["driver_action_code"])
|
|
self.assertEqual(["mainland-worker-01"], data["driver_node_codes"])
|
|
self.assertEqual("release_progression", data["sequence_key"])
|
|
self.assertEqual("版本发布与放量", data["sequence"]["title"])
|
|
mock_execute_driver_action.assert_called_once_with(
|
|
{
|
|
"action_code": "publish_latest_worker",
|
|
"node_codes": ["mainland-worker-01"],
|
|
"action_payload": {
|
|
"channel": "stable",
|
|
"release_id": 12,
|
|
},
|
|
"requested_by": "test/runbook/release_progression",
|
|
}
|
|
)
|
|
|
|
@patch("app.services.ops_service.execute_driver_action")
|
|
@patch("app.services.ops_service.get_ops_runbook")
|
|
def test_execute_ops_runbook_sequence_uses_secondary_action_and_allows_payload_override(
|
|
self,
|
|
mock_get_ops_runbook,
|
|
mock_execute_driver_action,
|
|
) -> None:
|
|
mock_get_ops_runbook.return_value = {
|
|
"control_sequences": [
|
|
{
|
|
"key": "node_onboarding",
|
|
"title": "纳管新节点",
|
|
"status": "warning",
|
|
"status_label": "有待接管节点",
|
|
"summary": "先补接入。",
|
|
"reason": "新增节点需要先纳管。",
|
|
"target_node_codes": ["mainland-worker-01"],
|
|
"primary_action_code": "bootstrap_run",
|
|
"primary_action_payload": {
|
|
"node_code": "mainland-worker-01",
|
|
},
|
|
"secondary_action_code": "run_acceptance",
|
|
"secondary_action_payload": {
|
|
"node_code": "mainland-worker-01",
|
|
},
|
|
}
|
|
]
|
|
}
|
|
mock_execute_driver_action.return_value = (
|
|
True,
|
|
"",
|
|
{
|
|
"handled": True,
|
|
"mode": "ui-intent",
|
|
},
|
|
)
|
|
|
|
ok, message, data = execute_ops_runbook_sequence(
|
|
"node_onboarding",
|
|
{
|
|
"secondary": True,
|
|
"requested_by": "test",
|
|
"node_codes": ["mainland-worker-02"],
|
|
"action_payload": {
|
|
"auto_approve": True,
|
|
},
|
|
},
|
|
)
|
|
|
|
self.assertTrue(ok, message)
|
|
self.assertEqual("", message)
|
|
self.assertTrue(data["handled"])
|
|
self.assertEqual("run_acceptance", data["driver_action_code"])
|
|
self.assertEqual(["mainland-worker-02"], data["driver_node_codes"])
|
|
self.assertTrue(data["sequence"]["secondary"])
|
|
mock_execute_driver_action.assert_called_once_with(
|
|
{
|
|
"action_code": "run_acceptance",
|
|
"node_codes": ["mainland-worker-02"],
|
|
"action_payload": {
|
|
"node_code": "mainland-worker-01",
|
|
"auto_approve": True,
|
|
},
|
|
"requested_by": "test/runbook/node_onboarding",
|
|
}
|
|
)
|
|
|
|
@patch("app.services.ops_service.get_ops_runbook")
|
|
def test_execute_ops_runbook_sequence_returns_error_when_sequence_missing(self, mock_get_ops_runbook) -> None:
|
|
mock_get_ops_runbook.return_value = {"control_sequences": []}
|
|
|
|
ok, message, data = execute_ops_runbook_sequence("missing-sequence", {})
|
|
|
|
self.assertFalse(ok)
|
|
self.assertEqual("标准作业路径不存在", message)
|
|
self.assertEqual("missing-sequence", data["sequence_key"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|