from __future__ import annotations import fcntl import importlib.util import subprocess import sys from pathlib import Path SCRIPT_ROOT = Path(__file__).resolve().parents[1] EXPORTER_PATH = SCRIPT_ROOT / "systemd-units-textfile-exporter.py" def load_exporter(): spec = importlib.util.spec_from_file_location("systemd_units_textfile_exporter", EXPORTER_PATH) assert spec and spec.loader module = importlib.util.module_from_spec(spec) sys.modules[spec.name] = module spec.loader.exec_module(module) return module def test_stops_probe_after_systemctl_timeout_budget(monkeypatch) -> None: exporter = load_exporter() monkeypatch.setattr(exporter, "UNIT_NAMES", ["runner-a.service", "runner-b.service", "runner-c.service"]) monkeypatch.setenv("AIOPS_SYSTEMD_MAX_TIMEOUTS", "1") calls: list[str] = [] def fake_show_unit(unit: str) -> dict[str, str]: calls.append(unit) raise subprocess.TimeoutExpired(cmd=["systemctl", "show", unit], timeout=2) monkeypatch.setattr(exporter, "_show_unit", fake_show_unit) metrics = exporter.collect() assert calls == ["runner-a.service"] assert 'unit="runner-a.service",active_state="scrape_error",sub_state="timeout"' in metrics assert ( 'unit="runner-b.service",active_state="scrape_skipped",' 'sub_state="systemctl_timeout_budget_exhausted"' ) in metrics assert ( 'unit="runner-c.service",active_state="scrape_skipped",' 'sub_state="systemctl_timeout_budget_exhausted"' ) in metrics assert "Command '['" not in metrics assert "systemd_unit_exporter_timeout_budget_exhausted" in metrics assert metrics.rstrip().endswith(" 1") def test_main_returns_when_exporter_lock_is_busy(tmp_path: Path, monkeypatch) -> None: exporter = load_exporter() lock_path = tmp_path / "systemd_units.prom.lock" output_dir = tmp_path / "textfiles" monkeypatch.setattr(exporter, "LOCK_PATH", lock_path) monkeypatch.setattr(exporter, "TEXTFILE_DIR", output_dir) monkeypatch.setattr(exporter, "UNIT_NAMES", ["runner-a.service"]) lock_path.parent.mkdir(parents=True, exist_ok=True) with lock_path.open("w") as lock_handle: fcntl.flock(lock_handle, fcntl.LOCK_EX | fcntl.LOCK_NB) exporter.main() assert not (output_dir / exporter.OUTPUT_NAME).exists()