"""Tests for the Phase 4 alerts framework.""" from __future__ import annotations import os import tempfile from pathlib import Path import pytest import atocore.config as _config @pytest.fixture(autouse=True) def isolated_env(monkeypatch): """Isolate alerts sinks per test.""" tmpdir = tempfile.mkdtemp() log_file = Path(tmpdir) / "alerts.log" monkeypatch.setenv("ATOCORE_ALERT_LOG", str(log_file)) monkeypatch.delenv("ATOCORE_ALERT_WEBHOOK", raising=False) # Data dir for any state writes monkeypatch.setenv("ATOCORE_DATA_DIR", tmpdir) _config.settings = _config.Settings() from atocore.models.database import init_db init_db() yield {"tmpdir": tmpdir, "log_file": log_file} def test_emit_alert_writes_log_file(isolated_env): from atocore.observability.alerts import emit_alert emit_alert("warning", "test title", "test message body", context={"count": 5}) content = isolated_env["log_file"].read_text(encoding="utf-8") assert "test title" in content assert "test message body" in content assert "WARNING" in content assert '"count": 5' in content def test_emit_alert_invalid_severity_falls_back_to_info(isolated_env): from atocore.observability.alerts import emit_alert emit_alert("made-up-severity", "t", "m") content = isolated_env["log_file"].read_text(encoding="utf-8") assert "INFO" in content def test_emit_alert_fails_open_on_log_write_error(monkeypatch, isolated_env): """An unwritable log path should not crash the emit.""" from atocore.observability.alerts import emit_alert monkeypatch.setenv("ATOCORE_ALERT_LOG", "/nonexistent/path/that/definitely/is/not/writable/alerts.log") # Must not raise emit_alert("info", "t", "m")