from __future__ import annotations from pathlib import Path from unittest.mock import patch import pytest def _write_env(tmp_path: Path, body: str) -> Path: env = tmp_path / ".env" env.write_text(body) return env def test_load_settings_reads_env_and_creates_runtime_dirs( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: _write_env( tmp_path, "ANTHROPIC_API_KEY=sk-ant-test\nANTHROPIC_MODEL=claude-haiku-4-5-20251001\nNTFY_TOPIC=topictopic12\n", ) monkeypatch.setattr("relay.config.REPO_ROOT", tmp_path) monkeypatch.setattr("relay.config.ENV_FILE", tmp_path / ".env") monkeypatch.setattr("relay.config.CONFIG_FILE", tmp_path / "config.yaml") from relay.config import load_settings # import after monkeypatch s = load_settings() assert s.api_key == "sk-ant-test" assert s.model == "claude-haiku-4-5-20251001" assert s.ntfy_topic == "topictopic12" for d in (s.queue_dir, s.dispatch_dir, s.state_dir, s.logs_dir): assert d.exists() def test_load_settings_generates_ntfy_topic_when_blank( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: _write_env(tmp_path, "ANTHROPIC_API_KEY=sk-ant-test\nNTFY_TOPIC=\n") monkeypatch.setattr("relay.config.REPO_ROOT", tmp_path) monkeypatch.setattr("relay.config.ENV_FILE", tmp_path / ".env") monkeypatch.setattr("relay.config.CONFIG_FILE", tmp_path / "config.yaml") from relay.config import load_settings with patch("relay.config._generate_ntfy_topic", return_value="generatedtopic1"): s = load_settings() assert s.ntfy_topic == "generatedtopic1" # Persisted back to .env env_after = (tmp_path / ".env").read_text() assert "NTFY_TOPIC=generatedtopic1" in env_after def test_load_settings_treats_inline_hash_comment_as_blank( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: """Defensive: dotenv parses 'KEY= # comment' as 'KEY' = ' # comment'. The settings loader must recognise that as effectively blank so a fresh topic is generated. """ _write_env(tmp_path, "ANTHROPIC_API_KEY=sk-ant-test\nNTFY_TOPIC= # generated on first run\n") monkeypatch.setattr("relay.config.REPO_ROOT", tmp_path) monkeypatch.setattr("relay.config.ENV_FILE", tmp_path / ".env") monkeypatch.setattr("relay.config.CONFIG_FILE", tmp_path / "config.yaml") from relay.config import load_settings with patch("relay.config._generate_ntfy_topic", return_value="newtopic"): s = load_settings() assert s.ntfy_topic == "newtopic" def test_missing_api_key_raises(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: _write_env(tmp_path, "ANTHROPIC_MODEL=claude-opus-4-7\n") monkeypatch.setattr("relay.config.REPO_ROOT", tmp_path) monkeypatch.setattr("relay.config.ENV_FILE", tmp_path / ".env") monkeypatch.setattr("relay.config.CONFIG_FILE", tmp_path / "config.yaml") # Also ensure env var doesn't leak in monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False) from relay.config import load_settings with pytest.raises(RuntimeError, match="ANTHROPIC_API_KEY"): load_settings() def test_default_config_yaml_is_seeded_when_missing( tmp_path: Path, monkeypatch: pytest.MonkeyPatch ) -> None: _write_env(tmp_path, "ANTHROPIC_API_KEY=sk-ant-test\nNTFY_TOPIC=t1234\n") monkeypatch.setattr("relay.config.REPO_ROOT", tmp_path) monkeypatch.setattr("relay.config.ENV_FILE", tmp_path / ".env") monkeypatch.setattr("relay.config.CONFIG_FILE", tmp_path / "config.yaml") from relay.config import load_settings s = load_settings() cfg_path = tmp_path / "config.yaml" assert cfg_path.exists() assert any(sess.session_id == "session-1" for sess in s.sessions)