254 lines
9.5 KiB
Python
254 lines
9.5 KiB
Python
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"]))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|