"""Tests for ``ci_orchestrator monitor disk`` and ``monitor runner``.""" from __future__ import annotations import json import shutil from datetime import UTC, datetime from pathlib import Path from typing import Any import pytest from click.testing import CliRunner import ci_orchestrator.commands.monitor as mon from ci_orchestrator.__main__ import cli @pytest.fixture(autouse=True) def _no_event_log_or_webhook(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr(mon, "_write_windows_event", lambda *_a, **_kw: True) monkeypatch.setattr(mon, "_post_webhook", lambda *_a, **_kw: True) # ── monitor disk ─────────────────────────────────────────────────────────── def _fake_usage(free_gb: float, total_gb: float = 1000.0) -> shutil._ntuple_diskusage: gb = 1024 ** 3 return shutil._ntuple_diskusage(int(total_gb * gb), int((total_gb - free_gb) * gb), int(free_gb * gb)) def test_disk_ok_exits_zero(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr(mon.shutil, "disk_usage", lambda _p: _fake_usage(free_gb=200)) result = CliRunner().invoke(cli, ["monitor", "disk", "--min-free-gb", "50"]) assert result.exit_code == 0, result.output assert "OK" in result.output def test_disk_alert_exits_one(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr(mon.shutil, "disk_usage", lambda _p: _fake_usage(free_gb=10)) result = CliRunner().invoke(cli, ["monitor", "disk", "--min-free-gb", "50"]) assert result.exit_code == 1 assert "below" in result.output or "WARNING" in result.output def test_disk_drive_not_found(monkeypatch: pytest.MonkeyPatch) -> None: def _raise(_p: Any) -> Any: raise FileNotFoundError("nope") monkeypatch.setattr(mon.shutil, "disk_usage", _raise) result = CliRunner().invoke(cli, ["monitor", "disk", "--drive-letter", "Z"]) assert result.exit_code == 2 assert "not found" in result.output def test_disk_json_output_ok(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr(mon.shutil, "disk_usage", lambda _p: _fake_usage(free_gb=200)) result = CliRunner().invoke( cli, ["monitor", "disk", "--min-free-gb", "50", "--json"] ) assert result.exit_code == 0 payload = json.loads(result.output.strip()) assert payload["status"] == "ok" assert payload["free_gb"] == 200.0 def test_disk_webhook_invoked_on_alert(monkeypatch: pytest.MonkeyPatch) -> None: calls: list[tuple[str, str]] = [] monkeypatch.setattr(mon, "_post_webhook", lambda url, content, **_kw: calls.append((url, content)) or True) monkeypatch.setattr(mon.shutil, "disk_usage", lambda _p: _fake_usage(free_gb=10)) result = CliRunner().invoke( cli, [ "monitor", "disk", "--min-free-gb", "50", "--webhook-url", "https://example.invalid/hook", ], ) assert result.exit_code == 1 assert calls and calls[0][0] == "https://example.invalid/hook" # ── monitor runner ───────────────────────────────────────────────────────── def test_runner_running_exits_zero(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: monkeypatch.setattr(mon, "_service_status", lambda _s: "Running") result = CliRunner().invoke( cli, ["monitor", "runner", "--state-dir", str(tmp_path)], ) assert result.exit_code == 0 assert "Running" in result.output def test_runner_not_installed_exits_two(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: monkeypatch.setattr(mon, "_service_status", lambda _s: None) result = CliRunner().invoke( cli, ["monitor", "runner", "--state-dir", str(tmp_path)] ) assert result.exit_code == 2 assert "not found" in result.output def test_runner_maintenance_flag_skips(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: flag = tmp_path / "runner-maintenance.flag" flag.write_text("") result = CliRunner().invoke( cli, ["monitor", "runner", "--state-dir", str(tmp_path)] ) assert result.exit_code == 0 assert "maintenance mode" in result.output def test_runner_restart_attempted_when_stopped( monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: statuses = iter(["Stopped", "Running"]) monkeypatch.setattr(mon, "_service_status", lambda _s: next(statuses)) monkeypatch.setattr(mon, "_restart_service", lambda _s: True) result = CliRunner().invoke( cli, ["monitor", "runner", "--state-dir", str(tmp_path)] ) assert result.exit_code == 0 assert "restarted" in result.output assert (tmp_path / "runner-restart-log.json").is_file() def test_runner_rate_limit_exits_one( monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: # Pre-fill the cooldown log with recent restarts up to the limit. recent = [datetime.now(tz=UTC).isoformat()] * 3 (tmp_path / "runner-restart-log.json").write_text(json.dumps(recent)) monkeypatch.setattr(mon, "_service_status", lambda _s: "Stopped") monkeypatch.setattr(mon, "_restart_service", lambda _s: True) result = CliRunner().invoke( cli, [ "monitor", "runner", "--state-dir", str(tmp_path), "--max-restarts", "3", ], ) assert result.exit_code == 1 assert "limit" in result.output