#!/usr/bin/env python3 import importlib.util import sys import tempfile from pathlib import Path MODULE_PATH = Path(__file__).with_name("aw-slo-monitor.py") SPEC = importlib.util.spec_from_file_location("aw_slo_monitor", MODULE_PATH) MODULE = importlib.util.module_from_spec(SPEC) sys.modules[SPEC.name] = MODULE SPEC.loader.exec_module(MODULE) class FakeHeaders: def __init__(self, values): self.values = values def get(self, key, default=""): return self.values.get(key, default) class FakeResponse: def __init__(self, body, status=200, content_type="text/plain"): self.body = body self.status = status self.headers = FakeHeaders({"Content-Type": content_type}) def __enter__(self): return self def __exit__(self, exc_type, exc, tb): return False def read(self): return self.body def test_summarize_window_calculates_9997_budget(): now = MODULE.parse_ts("2026-05-30T12:00:00Z") samples = [ {"ts": "2026-05-30T11:58:00Z", "ok": True}, {"ts": "2026-05-30T11:59:00Z", "ok": False}, {"ts": "2026-05-30T12:00:00Z", "ok": True}, ] summary = MODULE.summarize_window( samples, now=now, window_seconds=86400, sample_interval_seconds=60, target_percent=99.97, ) assert summary["samples"] == 3 assert summary["good_samples"] == 2 assert summary["bad_samples"] == 1 assert summary["availability_percent"] == 66.66667 assert summary["budget_seconds"] == 25 assert summary["budget_remaining_seconds"] == -35 assert summary["status"] == "burning" def test_summarize_window_status_uses_remaining_error_budget_for_partial_window(): now = MODULE.parse_ts("2026-05-30T12:00:00Z") samples = [ {"ts": "2026-05-30T11:59:30Z", "ok": False}, {"ts": "2026-05-30T11:59:45Z", "ok": True}, {"ts": "2026-05-30T12:00:00Z", "ok": True}, ] summary = MODULE.summarize_window( samples, now=now, window_seconds=86400, sample_interval_seconds=15, target_percent=99.97, ) assert summary["availability_percent"] == 66.66667 assert summary["budget_seconds"] == 25 assert summary["budget_remaining_seconds"] == 10 assert summary["status"] == "ok" def test_append_and_trim_sample_keeps_retention_window(): with tempfile.TemporaryDirectory() as tmp: path = Path(tmp) / "samples.jsonl" path.write_text( '{"ts":"2026-05-01T00:00:00Z","ok":true}\n' '{"ts":"2026-05-30T11:59:00Z","ok":true}\n', encoding="utf-8", ) sample = {"ts": "2026-05-30T12:00:00Z", "ok": False} samples = MODULE.append_and_trim_sample(path, sample, retention_seconds=3600) assert [item["ts"] for item in samples] == [ "2026-05-30T11:59:00Z", "2026-05-30T12:00:00Z", ] assert "2026-05-01T00:00:00Z" not in path.read_text(encoding="utf-8") def test_load_samples_treats_unreadable_file_as_empty(monkeypatch, tmp_path): path = tmp_path / "samples.jsonl" path.write_text('{"ts":"2026-05-30T12:00:00Z","ok":true}\n', encoding="utf-8") original_read_text = MODULE.Path.read_text def denied(self, *args, **kwargs): if self == path: raise PermissionError("denied") return original_read_text(self, *args, **kwargs) monkeypatch.setattr(MODULE.Path, "read_text", denied) assert MODULE.load_samples(path, MODULE.parse_ts("2026-05-30T11:00:00Z")) == [] def test_render_summary_text_includes_budget_remaining(): summary = { "generated_at_utc": "2026-05-30T12:00:00Z", "target_percent": 99.97, "current_sample": { "ok": True, "probes": {"worktime_today_csv": {"ok": True, "status": 200}}, }, "windows": { "24h": { "status": "ok", "availability_percent": 100.0, "samples": 10, "bad_samples": 0, "observed_bad_seconds": 0, "budget_remaining_seconds": 25, } }, } text = MODULE.render_summary_text(summary) assert "Target: 99.97%" in text assert "24h: ok availability=100.00000%" in text assert "budget_remaining_seconds=25" in text assert "- worktime_today_csv: OK 200" in text def test_html_probe_requires_non_empty_html_with_markers(monkeypatch): body = b'