generated from coulomb/repo-seed
Implement SAND-WP-0002 meta-framework foundation (T01–T09)
Add meta-framework spec, pydantic schemas, profile/extension YAML, extension registry, ext.compose-ssh backend, SandboxManager with State Hub events, CLI commands, integration docs, capability registry entry, and compose-e2e runbook. Nine unit tests pass. T10 remote smoke test remains for operator.
This commit is contained in:
84
tests/test_manager.py
Normal file
84
tests/test_manager.py
Normal file
@@ -0,0 +1,84 @@
|
||||
"""SandboxManager unit tests with mocked backend."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from sandboxer.core.manager import SandboxManager
|
||||
from sandboxer.lifecycle.store import SandboxStore
|
||||
from sandboxer.models import ActorType, Consumer, SandboxCreateRequest, SandboxState, SandboxStatus
|
||||
|
||||
|
||||
class FakeBackend:
|
||||
def provision(self, profile, inputs, host):
|
||||
return {
|
||||
"sandbox_id": "test1234",
|
||||
"host": host,
|
||||
"remote_dir": "/tmp/sandboxer/test1234",
|
||||
"compose_project": "sbx-e2e-test1234",
|
||||
"compose_file": "docker-compose.yml",
|
||||
"ssh_user": "root",
|
||||
}
|
||||
|
||||
def wait_ready(self, handle):
|
||||
return {
|
||||
"ssh": f"root@{handle['host']}",
|
||||
"remote_dir": handle["remote_dir"],
|
||||
"compose_project": handle["compose_project"],
|
||||
"host": handle["host"],
|
||||
}
|
||||
|
||||
def teardown(self, handle):
|
||||
return {
|
||||
"compose_removed": "True",
|
||||
"remote_dir_removed": "True",
|
||||
"remote_dir": handle["remote_dir"],
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def store(tmp_path: Path) -> SandboxStore:
|
||||
return SandboxStore(path=tmp_path / "sandboxes.json")
|
||||
|
||||
|
||||
def test_create_and_destroy(store: SandboxStore) -> None:
|
||||
manager = SandboxManager(store=store)
|
||||
request = SandboxCreateRequest(
|
||||
profile="profile.compose-e2e",
|
||||
inputs={"repo": "/tmp/repo"},
|
||||
consumer=Consumer(actor=ActorType.ADM, project="sand-boxer"),
|
||||
)
|
||||
|
||||
with (
|
||||
patch("sandboxer.core.manager.resolve_backend", return_value=FakeBackend()),
|
||||
patch("sandboxer.core.manager.emit_lifecycle_event", return_value=None),
|
||||
patch("sandboxer.core.manager.resolve_host", return_value="coulombcore"),
|
||||
):
|
||||
status = manager.create(request)
|
||||
assert status.state == SandboxState.READY
|
||||
assert status.sandbox_id == "test1234"
|
||||
|
||||
destroyed = manager.destroy(status.sandbox_id)
|
||||
assert destroyed.state == SandboxState.DESTROYED
|
||||
|
||||
|
||||
def test_destroy_idempotent(store: SandboxStore) -> None:
|
||||
now = datetime.now(UTC)
|
||||
status = SandboxStatus(
|
||||
sandbox_id="gone1234",
|
||||
profile_id="profile.compose-e2e",
|
||||
extension_id="ext.compose-ssh",
|
||||
state=SandboxState.DESTROYED,
|
||||
consumer=Consumer(actor=ActorType.ADM, project="sand-boxer"),
|
||||
created_at=now,
|
||||
updated_at=now,
|
||||
destroyed_at=now,
|
||||
)
|
||||
store.save(status)
|
||||
manager = SandboxManager(store=store)
|
||||
result = manager.destroy("gone1234")
|
||||
assert result.state == SandboxState.DESTROYED
|
||||
Reference in New Issue
Block a user