import unittest from unittest.mock import patch from app.services.ops_policy_service import preview_ops_job_policy class OpsPolicyServiceTests(unittest.TestCase): @patch("app.services.ops_policy_service.get_cluster_snapshot") def test_node_bootstrap_preview_requires_control_plane(self, mock_cluster_snapshot) -> None: mock_cluster_snapshot.return_value = { "nodes": [ { "node_code": "mainland-worker-01", "region": "mainland", "role": "worker", "status": "online", "current_load": 0, "is_effective_worker": True, "detect_participating": False, } ], "summary": { "online_worker_nodes": 2, "dedicated_online_worker_nodes": 1, "online_control_nodes": 1, "busy_nodes": [], }, } preview = preview_ops_job_policy( { "action": "node.bootstrap", "target_type": "node", "target_node_code": "mainland-worker-01", "execution_mode": "remote-agent", "payload": {}, } ) self.assertEqual("critical", preview["risk_level"]) self.assertTrue(preview["blocked"]) self.assertTrue(preview["approval_required"]) self.assertIn("node.bootstrap 仅支持 control-plane", " ".join(preview["blocking_reasons"])) @patch("app.services.ops_policy_service.get_cluster_snapshot") def test_deploy_release_batch_preview_summarizes_node_risks(self, mock_cluster_snapshot) -> None: mock_cluster_snapshot.return_value = { "nodes": [ { "node_code": "mainland-controller-01", "region": "mainland", "role": "control", "status": "busy", "current_load": 3, "is_effective_worker": True, "detect_participating": False, }, { "node_code": "mainland-worker-01", "region": "mainland", "role": "worker", "status": "online", "current_load": 0, "is_effective_worker": True, "detect_participating": False, }, ], "summary": { "online_worker_nodes": 2, "dedicated_online_worker_nodes": 1, "online_control_nodes": 1, "busy_nodes": ["mainland-controller-01"], }, } preview = preview_ops_job_policy( { "action": "deploy.release", "target_type": "batch", "target_node_codes": ["mainland-controller-01", "mainland-worker-01"], "execution_mode": "remote-agent", "payload": { "release_version": "2026.04.18-rc1", "artifact_url": "https://example.com/release.tar.gz", }, } ) self.assertEqual("batch", preview["target_type"]) self.assertTrue(preview["blocked"]) self.assertTrue(preview["approval_required"]) self.assertEqual(2, preview["target_summary"]["nodes_total"]) self.assertEqual(1, preview["target_summary"]["blocked_nodes"]) self.assertEqual(1, preview["target_summary"]["approval_nodes"]) self.assertEqual(1, preview["target_summary"]["warning_nodes"]) self.assertEqual(2, len(preview["target_nodes"])) controller_row = next(item for item in preview["target_nodes"] if item["node_code"] == "mainland-controller-01") self.assertTrue(controller_row["blocked"]) self.assertTrue(controller_row["approval_required"]) @patch("app.services.ops_policy_service.get_cluster_snapshot") def test_deploy_release_preview_blocks_missing_artifact_and_wrong_execution_mode(self, mock_cluster_snapshot) -> None: mock_cluster_snapshot.return_value = { "nodes": [ { "node_code": "mainland-worker-01", "region": "mainland", "role": "worker", "status": "online", "current_load": 0, "is_effective_worker": True, "detect_participating": False, } ], "summary": { "online_worker_nodes": 2, "dedicated_online_worker_nodes": 1, "online_control_nodes": 1, "busy_nodes": [], }, } preview = preview_ops_job_policy( { "action": "deploy.release", "target_type": "node", "target_node_code": "mainland-worker-01", "execution_mode": "local-runtime", "payload": { "release_version": "2026.04.18-rc1", "artifact_url": "", }, } ) self.assertTrue(preview["blocked"]) self.assertIn("deploy.release 缺少 artifact_url", " ".join(preview["blocking_reasons"])) self.assertIn("deploy.release 仅支持 remote-agent 或 ssh", " ".join(preview["blocking_reasons"])) @patch("app.services.ops_policy_service.get_cluster_snapshot") def test_deploy_release_preview_allows_ssh_execution_mode(self, mock_cluster_snapshot) -> None: mock_cluster_snapshot.return_value = { "nodes": [ { "node_code": "mainland-worker-01", "region": "mainland", "role": "worker", "status": "online", "current_load": 0, "is_effective_worker": True, "detect_participating": False, } ], "summary": { "online_worker_nodes": 2, "dedicated_online_worker_nodes": 1, "online_control_nodes": 1, "busy_nodes": [], }, } preview = preview_ops_job_policy( { "action": "deploy.release", "target_type": "node", "target_node_code": "mainland-worker-01", "execution_mode": "ssh", "payload": { "release_version": "2026.04.18-rc1", "artifact_url": "https://example.com/release.tar.gz", }, } ) self.assertFalse(any("仅支持 remote-agent 或 ssh" in item for item in preview["blocking_reasons"])) self.assertTrue(preview["approval_required"]) @patch("app.services.ops_policy_service.get_cluster_snapshot") def test_service_status_preview_blocks_control_plane_execution_mode(self, mock_cluster_snapshot) -> None: mock_cluster_snapshot.return_value = { "nodes": [ { "node_code": "mainland-worker-01", "region": "mainland", "role": "worker", "status": "online", "current_load": 0, "is_effective_worker": True, "detect_participating": False, } ], "summary": { "online_worker_nodes": 2, "dedicated_online_worker_nodes": 1, "online_control_nodes": 1, "busy_nodes": [], }, } preview = preview_ops_job_policy( { "action": "service.status", "target_type": "node", "target_node_code": "mainland-worker-01", "execution_mode": "control-plane", "payload": {"service_name": "domaincheck-worker"}, } ) self.assertTrue(preview["blocked"]) self.assertIn("service.status 当前不支持 control-plane 执行方式", " ".join(preview["blocking_reasons"])) @patch("app.services.ops_policy_service.get_cluster_snapshot") def test_logs_collect_preview_blocks_local_runtime_on_remote_node(self, mock_cluster_snapshot) -> None: mock_cluster_snapshot.return_value = { "nodes": [ { "node_code": "mainland-worker-01", "region": "mainland", "role": "worker", "status": "online", "current_load": 0, "is_effective_worker": True, "detect_participating": False, } ], "summary": { "online_worker_nodes": 2, "dedicated_online_worker_nodes": 1, "online_control_nodes": 1, "busy_nodes": [], }, } preview = preview_ops_job_policy( { "action": "logs.collect", "target_type": "node", "target_node_code": "mainland-worker-01", "execution_mode": "local-runtime", "payload": { "service_name": "domaincheck-worker", "lines": 120, }, } ) self.assertTrue(preview["blocked"]) self.assertIn("local-runtime 仅支持当前控制面本机节点", " ".join(preview["blocking_reasons"])) @patch("app.services.ops_policy_service.get_cluster_snapshot") def test_runtime_reset_lab_state_is_critical_and_requires_approval(self, mock_cluster_snapshot) -> None: mock_cluster_snapshot.return_value = { "nodes": [ { "node_code": "mainland-controller-01", "region": "mainland", "role": "control", "status": "online", "current_load": 0, "is_effective_worker": True, "detect_participating": False, } ], "summary": { "online_worker_nodes": 2, "dedicated_online_worker_nodes": 1, "online_control_nodes": 2, "busy_nodes": [], }, } preview = preview_ops_job_policy( { "action": "runtime.reset_lab_state", "target_type": "node", "target_node_code": "mainland-controller-01", "execution_mode": "remote-agent", "payload": {"clear_database": True, "clear_redis": True}, } ) self.assertEqual("critical", preview["risk_level"]) self.assertTrue(preview["approval_required"]) self.assertFalse(preview["blocked"]) if __name__ == "__main__": unittest.main()