"""供本地测试和预演使用的 fake action runner。""" from __future__ import annotations from typing import Any from .models import ActionResult class FakeActionRunner: """返回确定性 action 结果,避免测试触碰真实 PAM 环境。""" def __init__(self, fixtures: dict[str, dict[str, Any]] | None = None) -> None: """保存可覆盖默认行为的测试 fixture,并记录调用历史。""" self.fixtures = fixtures or {} self.calls: list[tuple[str, dict[str, Any]]] = [] def run(self, action: str, *, params: dict[str, Any], **kwargs: Any) -> ActionResult: """执行 fake action,优先使用 fixture,否则使用内置默认结果。""" self.calls.append((action, kwargs)) values = self._fixture_for(action, kwargs) if not values: values = self._default_values(action, kwargs) ok = not values.pop("_fail", False) return ActionResult( action=action, backend="fake", tool_name=f"fake:{action}", ok=ok, values=values, exit_code=0 if ok else 1, raw_output=str(values), error_summary="" if ok else str(values.get("MESSAGE", "fake action 执行失败")), ) def _default_values(self, action: str, kwargs: dict[str, Any]) -> dict[str, Any]: """为常见部署 action 构造稳定的默认返回值。""" if action == "get-token": return {"ACTION": action, "TOKEN": "***"} if action == "upload-package": return {"ACTION": action, "HASH_CODE": "fake-hash"} if action == "get-node-url": return {"ACTION": action, "NODE_URL": "https://fake-node.local"} if action == "get-online-ips": return {"ACTION": action, "COUNT": "2", "IP": ["192.168.1.10", "192.168.1.11"]} if action == "upgrade-ip": return {"ACTION": action, "IP": kwargs.get("ip", ""), "RESULT": "TASK_CREATED"} if action == "poll-upgrade-progress": return { "ACTION": action, "IP": kwargs.get("ip", ""), "STEP": "DONE", "RATE_OF_PROGRESS": "100", "MESSAGE": "success", } if action == "start-ip": return {"ACTION": action, "IP": kwargs.get("ip", ""), "RESULT": "OK"} if action == "verify-ip": return {"ACTION": action, "IP": kwargs.get("ip", ""), "SUCCESS": "true", "MESSAGE": "ok"} if action == "download-log": return {"ACTION": action, "IP": kwargs.get("ip", ""), "LOG_FILE": "logs/fake.zip"} return {"ACTION": action, "RESULT": "OK"} def _fixture_for(self, action: str, kwargs: dict[str, Any]) -> dict[str, Any]: """按 action 或 action:ip 查找测试 fixture。""" ip = kwargs.get("ip") ip_key = f"{action}:{ip}" if ip else "" if ip_key and ip_key in self.fixtures: return self.fixtures[ip_key].copy() return self.fixtures.get(action, {}).copy()