generated from coulomb/repo-seed
Add workspace checkpoint API with SnapshotStore, extension hooks on compose-ssh and saas-stub, manager orchestration, CLI/HTTP surface, profile.compose-checkpoint, and docs/tests.
97 lines
3.0 KiB
Python
97 lines
3.0 KiB
Python
"""Compose command configuration and snapshot hooks."""
|
|
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
from sandboxer.extensions.compose_ssh import ComposeSSHExtension
|
|
from sandboxer.models import Profile
|
|
|
|
|
|
def _profile() -> Profile:
|
|
return Profile.model_validate(
|
|
{
|
|
"id": "profile.compose-checkpoint",
|
|
"version": "1.0.0",
|
|
"extension": "ext.compose-ssh",
|
|
}
|
|
)
|
|
|
|
|
|
def test_compose_cmd_from_config() -> None:
|
|
ext = ComposeSSHExtension({"compose_cmd": "podman-compose"})
|
|
assert ext._compose_bin() == "podman-compose"
|
|
|
|
|
|
def test_compose_cmd_env_override(monkeypatch) -> None:
|
|
monkeypatch.setenv("SANDBOXER_COMPOSE_CMD", "nerdctl compose")
|
|
ext = ComposeSSHExtension({"compose_cmd": "docker compose"})
|
|
assert ext._compose_bin() == "nerdctl compose"
|
|
|
|
|
|
def test_supports_snapshots() -> None:
|
|
ext = ComposeSSHExtension()
|
|
assert ext.supports_snapshots() is True
|
|
|
|
|
|
def test_snapshot_creates_remote_tarball() -> None:
|
|
ext = ComposeSSHExtension({"base_dir": "/tmp/sandboxer"})
|
|
handle = {
|
|
"sandbox_id": "abc12345",
|
|
"host": "coulombcore",
|
|
"remote_dir": "/tmp/sandboxer/abc12345",
|
|
"compose_file": "docker-compose.yml",
|
|
"compose_project": "sbx-e2e-abc12345",
|
|
"ssh_user": "root",
|
|
}
|
|
|
|
def fake_run(cmd, *, timeout=60):
|
|
if "tar czf" in cmd:
|
|
return 0, ""
|
|
if "stat" in cmd:
|
|
return 0, "2048"
|
|
return 0, ""
|
|
|
|
with patch.object(ext, "_ssh_for_handle") as ssh_factory:
|
|
ssh = ssh_factory.return_value
|
|
ssh.run.side_effect = fake_run
|
|
meta = ext.snapshot(handle)
|
|
|
|
assert meta["artifact_path"].endswith(".tar.gz")
|
|
assert meta["snapshot_id"]
|
|
assert meta["size_bytes"] == "2048"
|
|
|
|
|
|
def test_restore_from_snapshot_extracts_and_compose_up() -> None:
|
|
ext = ComposeSSHExtension({"base_dir": "/tmp/sandboxer"})
|
|
snapshot_meta = {
|
|
"snapshot_id": "snap12345678",
|
|
"artifact_path": "/tmp/sandboxer/snapshots/snap12345678.tar.gz",
|
|
"host": "coulombcore",
|
|
"compose_file": "docker-compose.yml",
|
|
"ssh_user": "root",
|
|
}
|
|
|
|
with patch("sandboxer.extensions.compose_ssh.SSHConfig.from_env") as ssh_factory:
|
|
ssh = ssh_factory.return_value
|
|
ssh.run.return_value = (0, "")
|
|
ssh.user = "root"
|
|
handle = ext.restore_from_snapshot(_profile(), snapshot_meta, {}, "coulombcore")
|
|
|
|
assert handle["sandbox_id"]
|
|
assert handle["remote_dir"].endswith(handle["sandbox_id"])
|
|
calls = [c.args[0] for c in ssh.run.call_args_list]
|
|
assert any("tar xzf" in c for c in calls)
|
|
assert any("up -d" in c for c in calls)
|
|
|
|
|
|
def test_restore_cross_host_not_supported() -> None:
|
|
ext = ComposeSSHExtension()
|
|
snapshot_meta = {
|
|
"snapshot_id": "snap1",
|
|
"artifact_path": "/tmp/snap.tar.gz",
|
|
"host": "host-a",
|
|
"compose_file": "docker-compose.yml",
|
|
}
|
|
with pytest.raises(NotImplementedError, match="cross-host"):
|
|
ext.restore_from_snapshot(_profile(), snapshot_meta, {}, "host-b") |