Tussilago/tests/test_host_commands.py
2026-04-27 20:43:26 +02:00

84 lines
2.7 KiB
Python

from __future__ import annotations
import subprocess # noqa: S404
from pathlib import Path
from unittest.mock import patch
import pytest
from control_plane.host_commands import HostCommandError
from control_plane.host_commands import HostCommandResult
from control_plane.host_commands import build_host_command_env
from control_plane.host_commands import run_host_command
def test_run_host_command_rejects_env_without_allowlist() -> None:
"""Environment overrides must use an explicit allowlist."""
with pytest.raises(ValueError, match="allowed_env_keys"):
run_host_command(command=("true",), env_overrides={"SECRET": "value"})
def test_run_host_command_returns_captured_output() -> None:
"""Successful host commands should preserve stdout and stderr."""
completed = subprocess.CompletedProcess(
args=("echo", "ok"),
returncode=0,
stdout="ok\n",
stderr="",
)
with patch(
"control_plane.host_commands.subprocess.run",
return_value=completed,
) as mock_run:
result = run_host_command(
command=("echo", "ok"),
cwd=Path.cwd(),
env_overrides={"UV_PROJECT_ENVIRONMENT": "test"},
allowed_env_keys=frozenset({"UV_PROJECT_ENVIRONMENT"}),
)
assert result == HostCommandResult(
args=("echo", "ok"),
returncode=0,
stdout="ok\n",
stderr="",
)
forwarded_env = mock_run.call_args.kwargs["env"]
assert "DJANGO_SETTINGS_MODULE" not in forwarded_env
assert forwarded_env["UV_PROJECT_ENVIRONMENT"] == "test"
mock_run.assert_called_once()
def test_build_host_command_env_strips_platform_django_settings(
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Tenant child processes must not inherit platform Django settings."""
monkeypatch.setenv("DJANGO_SETTINGS_MODULE", "config.settings")
monkeypatch.setenv("PATH", "/usr/bin")
environment = build_host_command_env()
assert environment["PATH"] == "/usr/bin"
assert "DJANGO_SETTINGS_MODULE" not in environment
def test_run_host_command_wraps_called_process_errors() -> None:
"""Failing host commands should raise a typed exception with captured output."""
error = subprocess.CalledProcessError(
returncode=17,
cmd=("podman", "run"),
output="",
stderr="boom",
)
with (
patch("control_plane.host_commands.subprocess.run", side_effect=error),
pytest.raises(
HostCommandError,
match="Host command failed",
) as exc_info,
):
run_host_command(command=("podman", "run"))
assert exc_info.value.command_args == ("podman", "run")
assert exc_info.value.returncode == 17
assert exc_info.value.stderr == "boom"