import importlib import importlib.util from pathlib import Path from fastapi.testclient import TestClient def load_app_module(): try: return importlib.import_module("app") except ModuleNotFoundError: app_path = Path("/app/app.py") spec = importlib.util.spec_from_file_location("app", app_path) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) return mod # ============================================================ # /containers/{action}/{name} # ============================================================ def test_container_action_invalid_action_contract(): app_mod = load_app_module() client = TestClient(app_mod.app) r = client.post("/containers/invalid/dummy") # Freeze whatever baseline currently is body = r.json() # Must be JSON and deterministic structure assert isinstance(body, (dict, list)) # If dict variant if isinstance(body, dict): assert set(body.keys()) == {"error"} assert body["error"] == "Invalid action" def test_container_action_failure_shape_contract(): app_mod = load_app_module() client = TestClient(app_mod.app) r = client.post("/containers/start/nonexistent_container_12345") body = r.json() # Freeze exact variant structure if isinstance(body, dict) and body.get("method") == "podman": assert "name" in body assert "cmd" in body assert "status_code" in body else: # Any other baseline variant must still be JSON assert isinstance(body, (dict, list)) # ============================================================ # /actions/{action}/{name} # ============================================================ def test_legacy_actions_invalid_action_contract(): app_mod = load_app_module() client = TestClient(app_mod.app) r = client.post("/actions/invalid/dummy") body = r.json() assert isinstance(body, dict) assert set(body.keys()) == {"status"} assert body["status"] == "unknown" # ============================================================ # /pods/actions/{action}/{podname} # ============================================================ def test_pods_action_invalid_action_contract(): app_mod = load_app_module() client = TestClient(app_mod.app) r = client.post("/pods/actions/invalid/dummy") body = r.json() # Baseline may return tuple-style 400 or JSON assert isinstance(body, (dict, list)) if isinstance(body, dict) and "error" in body: assert body["error"] == "Invalid action" def test_pods_action_variant_shape_contract(): app_mod = load_app_module() client = TestClient(app_mod.app) r = client.post("/pods/actions/start/nonexistent_pod_12345") body = r.json() # Freeze possible baseline variants if isinstance(body, dict): if body.get("method") == "systemd_then_podman": assert set(body.keys()) == {"method", "note", "systemd", "podman"} assert body["note"] == "systemd failed; falling back to podman" elif body.get("method") == "podman": assert set(body.keys()) == {"method", "result"} else: assert isinstance(body, list) # ============================================================ # /{action}/{unit} # ============================================================ def test_systemctl_wrapper_invalid_action_contract(): app_mod = load_app_module() client = TestClient(app_mod.app) r = client.post("/invalid/dummy.service") body = r.json() assert set(body.keys()) == {"detail"} assert body["detail"] == "Invalid action" def test_systemctl_wrapper_status_shape_contract(): app_mod = load_app_module() client = TestClient(app_mod.app) r = client.post("/status/nonexistent.service") body = r.json() # allowlist may cause 403 if r.status_code == 403: assert set(body.keys()) == {"detail"} else: assert set(body.keys()) == {"cmd", "exit", "output"} # ============================================================ # /api// # ============================================================ def test_legacy_api_invalid_action_contract(): app_mod = load_app_module() client = TestClient(app_mod.app) r = client.post("/api/invalid/dummy.service") body = r.json() # Baseline: HTTPException 400 with {"detail": "..."} assert r.status_code == 400 assert set(body.keys()) == {"detail"} def test_legacy_api_status_shape_contract(): app_mod = load_app_module() client = TestClient(app_mod.app) r = client.post("/api/status/nonexistent.service") body = r.json() if r.status_code == 403: assert set(body.keys()) == {"detail"} else: assert set(body.keys()) == {"cmd", "exit", "output"}