Fix the default one-shot install path so empty bundled profile directories no longer win over OCI-backed environment pulls or leave broken cached symlinks behind. Treat cached installs as valid only when the manifest and boot artifacts are all present, repair invalid installs on the next pull, and add human-mode phase markers for env pull and run without changing JSON output. Align the Python lifecycle example and public docs with the current exec_vm/vm_exec auto-clean semantics, and validate the slice with focused pytest coverage, make check, make dist-check, and a real default-path pull/inspect/run smoke.
87 lines
3.2 KiB
Python
87 lines
3.2 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from pyro_mcp.runtime import doctor_report, resolve_runtime_paths, runtime_capabilities
|
|
|
|
|
|
def test_resolve_runtime_paths_default_bundle() -> None:
|
|
paths = resolve_runtime_paths()
|
|
assert paths.firecracker_bin.exists()
|
|
assert paths.jailer_bin.exists()
|
|
assert paths.guest_agent_path is not None
|
|
assert paths.guest_agent_path.exists()
|
|
assert paths.artifacts_dir.exists()
|
|
assert paths.manifest.get("platform") == "linux-x86_64"
|
|
|
|
|
|
def test_resolve_runtime_paths_missing_manifest(
|
|
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
|
) -> None:
|
|
empty_root = tmp_path / "bundle"
|
|
empty_root.mkdir(parents=True, exist_ok=True)
|
|
monkeypatch.setenv("PYRO_RUNTIME_BUNDLE_DIR", str(empty_root))
|
|
with pytest.raises(RuntimeError, match="manifest not found"):
|
|
resolve_runtime_paths()
|
|
|
|
|
|
def test_resolve_runtime_paths_checksum_mismatch(
|
|
monkeypatch: pytest.MonkeyPatch, tmp_path: Path
|
|
) -> None:
|
|
source = resolve_runtime_paths()
|
|
copied_bundle = tmp_path / "bundle"
|
|
copied_platform = copied_bundle / "linux-x86_64"
|
|
copied_platform.mkdir(parents=True, exist_ok=True)
|
|
(copied_bundle / "NOTICE").write_text(
|
|
source.notice_path.read_text(encoding="utf-8"), encoding="utf-8"
|
|
)
|
|
|
|
manifest = json.loads(source.manifest_path.read_text(encoding="utf-8"))
|
|
(copied_platform / "manifest.json").write_text(
|
|
json.dumps(manifest, indent=2),
|
|
encoding="utf-8",
|
|
)
|
|
firecracker_path = copied_platform / "bin" / "firecracker"
|
|
firecracker_path.parent.mkdir(parents=True, exist_ok=True)
|
|
firecracker_path.write_text("tampered\n", encoding="utf-8")
|
|
(copied_platform / "bin" / "jailer").write_bytes(source.jailer_bin.read_bytes())
|
|
guest_agent_path = source.guest_agent_path
|
|
if guest_agent_path is None:
|
|
raise AssertionError("expected guest agent in runtime bundle")
|
|
copied_guest_dir = copied_platform / "guest"
|
|
copied_guest_dir.mkdir(parents=True, exist_ok=True)
|
|
(copied_guest_dir / "pyro_guest_agent.py").write_text(
|
|
guest_agent_path.read_text(encoding="utf-8"),
|
|
encoding="utf-8",
|
|
)
|
|
monkeypatch.setenv("PYRO_RUNTIME_BUNDLE_DIR", str(copied_bundle))
|
|
with pytest.raises(RuntimeError, match="checksum mismatch"):
|
|
resolve_runtime_paths()
|
|
|
|
|
|
def test_doctor_report_has_runtime_fields() -> None:
|
|
report = doctor_report()
|
|
assert "runtime_ok" in report
|
|
assert "kvm" in report
|
|
assert "networking" in report
|
|
if report["runtime_ok"]:
|
|
runtime = report.get("runtime")
|
|
assert isinstance(runtime, dict)
|
|
assert "firecracker_bin" in runtime
|
|
assert "guest_agent_path" in runtime
|
|
assert "component_versions" in runtime
|
|
assert "environments" in runtime
|
|
networking = report["networking"]
|
|
assert isinstance(networking, dict)
|
|
assert "tun_available" in networking
|
|
|
|
|
|
def test_runtime_capabilities_reports_real_bundle_flags() -> None:
|
|
paths = resolve_runtime_paths()
|
|
capabilities = runtime_capabilities(paths)
|
|
assert capabilities.supports_vm_boot is True
|
|
assert capabilities.supports_guest_exec is True
|
|
assert capabilities.supports_guest_network is True
|