generated from coulomb/repo-seed
Implement SAND-WP-0008: host telemetry and self-canary
Add profile.sandbox-canary, HostSnapshot/inventory/stale schemas, SSH collectors, before/after provision deltas, telemetry export to State Hub and local JSON, default `sandboxer create` self-deploy, inspect/reap-stale CLI, runbook, and CoulombCore verification (26 tests pass).
This commit is contained in:
87
tests/test_telemetry.py
Normal file
87
tests/test_telemetry.py
Normal file
@@ -0,0 +1,87 @@
|
||||
"""Telemetry parsing and introspection tests."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from sandboxer.defaults import resolve_create_defaults
|
||||
from sandboxer.profiles.loader import load_profile
|
||||
from sandboxer.telemetry.host_snapshot import (
|
||||
parse_container_count,
|
||||
parse_df_root,
|
||||
parse_loadavg,
|
||||
)
|
||||
from sandboxer.telemetry.introspection import profile_wants_telemetry
|
||||
from sandboxer.telemetry.models import HostSnapshot, SandboxInventory
|
||||
|
||||
|
||||
def test_parse_loadavg() -> None:
|
||||
assert parse_loadavg("0.52 0.48 0.45 1/234 999") == (0.52, 0.48, 0.45)
|
||||
|
||||
|
||||
def test_parse_df_root() -> None:
|
||||
line = "Filesystem Size Used Avail Use% Mounted\n/dev/sda1 100G 40G 55G 43% /"
|
||||
used, avail = parse_df_root(line)
|
||||
assert used == 43.0
|
||||
assert avail == 55.0
|
||||
|
||||
|
||||
def test_parse_container_count() -> None:
|
||||
assert parse_container_count("abc\ndef\n") == 2
|
||||
|
||||
|
||||
def test_profile_wants_telemetry_canary() -> None:
|
||||
profile = load_profile("profile.sandbox-canary")
|
||||
assert profile_wants_telemetry(profile) is True
|
||||
|
||||
|
||||
def test_profile_wants_telemetry_compose_e2e() -> None:
|
||||
profile = load_profile("profile.compose-e2e")
|
||||
assert profile_wants_telemetry(profile) is False
|
||||
|
||||
|
||||
def test_resolve_create_defaults_no_args() -> None:
|
||||
profile, inputs = resolve_create_defaults(None, {})
|
||||
assert profile == "profile.sandbox-canary"
|
||||
assert "repo" in inputs
|
||||
assert Path(inputs["repo"]).name == "sand-boxer"
|
||||
|
||||
|
||||
def test_resolve_create_defaults_explicit_repo() -> None:
|
||||
profile, inputs = resolve_create_defaults(None, {"repo": "/tmp/foo"})
|
||||
assert profile == "profile.compose-e2e"
|
||||
assert inputs["repo"] == "/tmp/foo"
|
||||
|
||||
|
||||
def test_build_introspection_report_mocked(tmp_path: Path) -> None:
|
||||
from sandboxer.lifecycle.store import SandboxStore
|
||||
from sandboxer.telemetry.introspection import build_introspection_report
|
||||
|
||||
now = datetime.now(UTC)
|
||||
snap = HostSnapshot(collected_at=now, host="h1", load_1m=1.0, mem_available_mb=1000)
|
||||
snap2 = HostSnapshot(collected_at=now, host="h1", load_1m=1.5, mem_available_mb=900)
|
||||
profile = load_profile("profile.sandbox-canary")
|
||||
store = SandboxStore(path=tmp_path / "sandboxes.json")
|
||||
|
||||
with patch("sandboxer.telemetry.introspection.HostInventoryScanner") as scanner_cls:
|
||||
scanner = scanner_cls.return_value
|
||||
scanner.scan_inventory.return_value = SandboxInventory(
|
||||
host="h1", base_dir="/tmp/sandboxer", collected_at=now, entries=[]
|
||||
)
|
||||
scanner.find_stale.return_value = []
|
||||
report = build_introspection_report(
|
||||
host="h1",
|
||||
sandbox_id="abc",
|
||||
profile=profile,
|
||||
provision_before=snap,
|
||||
provision_after=snap2,
|
||||
store=store,
|
||||
)
|
||||
|
||||
assert report.provision_delta is not None
|
||||
assert report.provision_delta.load_1m_delta == pytest.approx(0.5)
|
||||
assert report.provision_delta.mem_available_mb_delta == -100
|
||||
Reference in New Issue
Block a user