"""Tests for the config module.""" from __future__ import annotations import subprocess import sys def test_config_defaults() -> None: """Test that config loads with expected default values.""" env_str = "" for k, v in { "DISCORD_TOKEN": "test-token", "CHAT_ENDPOINT": "https://chat.example.com/v1", "COMPLETION_ENDPOINT": "https://completion.example.com/v1", "IMAGE_GEN_ENDPOINT": "https://image.example.com/v1", "IMAGE_EDIT_ENDPOINT": "https://image-edit.example.com/v1", "EMBEDDING_ENDPOINT": "https://embedding.example.com/v1", "CHAT_MODEL": "test-chat-model", "COMPLETION_MODEL": "test-completion-model", "IMAGE_GEN_MODEL": "test-image-model", "IMAGE_EDIT_MODEL": "test-image-edit-model", "EMBEDDING_MODEL": "test-embedding-model", "CHAT_ENDPOINT_KEY": "test-key", "COMPLETION_ENDPOINT_KEY": "test-completion-key", "IMAGE_GEN_ENDPOINT_KEY": "test-image-key", "IMAGE_EDIT_ENDPOINT_KEY": "test-image-edit-key", "EMBEDDING_ENDPOINT_KEY": "test-embedding-key", "MAX_COMPLETION_TOKENS": "1000", "MAX_HISTORY_MESSAGES": "1000", "SIMILARITY_THRESHOLD": "0.7", "TOP_K_RESULTS": "5", "TTS_MODEL_PATH": "/tmp/test-model.onnx", "TTS_VOICES_PATH": "/tmp/test-voices.bin", "TTS_VOICE": "af_sarah", "TTS_SPEED": "1.0", "DB_PATH": ":memory:", }.items(): env_str += f'os.environ["{k}"] = "{v}"\n' code = f""" import sys sys.path.insert(0, "/var/home/ducoterra/Projects/vibe_discord_bots") import os os.environ.clear() os.environ["PATH"] = "/usr/bin:/bin" {env_str} import vibe_bot.config assert vibe_bot.config.DISCORD_TOKEN == "test-token" assert vibe_bot.config.CHAT_ENDPOINT == "https://chat.example.com/v1" assert vibe_bot.config.COMPLETION_ENDPOINT == "https://completion.example.com/v1" assert vibe_bot.config.IMAGE_GEN_ENDPOINT == "https://image.example.com/v1" assert vibe_bot.config.IMAGE_EDIT_ENDPOINT == "https://image-edit.example.com/v1" assert vibe_bot.config.EMBEDDING_ENDPOINT == "https://embedding.example.com/v1" assert vibe_bot.config.CHAT_MODEL == "test-chat-model" assert vibe_bot.config.COMPLETION_MODEL == "test-completion-model" assert vibe_bot.config.IMAGE_GEN_MODEL == "test-image-model" assert vibe_bot.config.IMAGE_EDIT_MODEL == "test-image-edit-model" assert vibe_bot.config.EMBEDDING_MODEL == "test-embedding-model" assert vibe_bot.config.MAX_COMPLETION_TOKENS == 1000 assert vibe_bot.config.MAX_HISTORY_MESSAGES == 1000 assert vibe_bot.config.SIMILARITY_THRESHOLD == 0.7 assert vibe_bot.config.TOP_K_RESULTS == 5 assert vibe_bot.config.TTS_MODEL_PATH == "/tmp/test-model.onnx" assert vibe_bot.config.TTS_VOICES_PATH == "/tmp/test-voices.bin" assert vibe_bot.config.TTS_VOICE == "af_sarah" assert vibe_bot.config.TTS_SPEED == 1.0 print("OK") """ result = subprocess.run( # noqa: PLW1510, S603 [sys.executable, "-c", code], capture_output=True, text=True, timeout=30, ) assert result.returncode == 0, f"Subprocess failed: {result.stderr}" def _run_config_check(env_vars: dict[str, str], expected_error: str) -> None: """Run a subprocess that imports config and checks for expected RuntimeError.""" env_str = "" for k, v in env_vars.items(): env_str += f'os.environ["{k}"] = "{v}"\n' code = f""" import sys sys.path.insert(0, "/var/home/ducoterra/Projects/vibe_discord_bots") import os os.environ.clear() os.environ["PATH"] = "/usr/bin:/bin" {env_str} try: import vibe_bot.config print("NO_ERROR") except RuntimeError as e: print(f"ERROR: {{e}}") except Exception as e: print(f"OTHER: {{type(e).__name__}}: {{e}}") """ result = subprocess.run( # noqa: PLW1510, S603 [sys.executable, "-c", code], capture_output=True, text=True, timeout=30, ) output = result.stdout.strip() assert output.startswith("ERROR:") and expected_error in output, ( # noqa: PT018 f"Expected error '{expected_error}' but got: {output}" ) def test_config_missing_discord_token() -> None: """Test that RuntimeError is raised when DISCORD_TOKEN is missing.""" env: dict[str, str] = { "DISCORD_TOKEN": "", "CHAT_ENDPOINT": "https://chat.example.com/v1", "COMPLETION_ENDPOINT": "https://completion.example.com/v1", "IMAGE_GEN_ENDPOINT": "https://image.example.com/v1", "IMAGE_EDIT_ENDPOINT": "https://image-edit.example.com/v1", "EMBEDDING_ENDPOINT": "https://embedding.example.com/v1", "CHAT_MODEL": "test-chat-model", "COMPLETION_MODEL": "test-completion-model", "IMAGE_GEN_MODEL": "test-image-model", "IMAGE_EDIT_MODEL": "test-image-edit-model", "EMBEDDING_MODEL": "test-embedding-model", } _run_config_check(env, "DISCORD_TOKEN required") def test_config_missing_chat_endpoint() -> None: """Test that RuntimeError is raised when CHAT_ENDPOINT is missing.""" env: dict[str, str] = { "DISCORD_TOKEN": "test-token", "CHAT_ENDPOINT": "", "COMPLETION_ENDPOINT": "https://completion.example.com/v1", "IMAGE_GEN_ENDPOINT": "https://image.example.com/v1", "IMAGE_EDIT_ENDPOINT": "https://image-edit.example.com/v1", "EMBEDDING_ENDPOINT": "https://embedding.example.com/v1", "CHAT_MODEL": "test-chat-model", "COMPLETION_MODEL": "test-completion-model", "IMAGE_GEN_MODEL": "test-image-model", "IMAGE_EDIT_MODEL": "test-image-edit-model", "EMBEDDING_MODEL": "test-embedding-model", } _run_config_check(env, "CHAT_ENDPOINT required") def test_config_missing_completion_endpoint() -> None: """Test that RuntimeError is raised when COMPLETION_ENDPOINT is missing.""" env: dict[str, str] = { "DISCORD_TOKEN": "test-token", "CHAT_ENDPOINT": "https://chat.example.com/v1", "COMPLETION_ENDPOINT": "", "IMAGE_GEN_ENDPOINT": "https://image.example.com/v1", "IMAGE_EDIT_ENDPOINT": "https://image-edit.example.com/v1", "EMBEDDING_ENDPOINT": "https://embedding.example.com/v1", "CHAT_MODEL": "test-chat-model", "COMPLETION_MODEL": "test-completion-model", "IMAGE_GEN_MODEL": "test-image-model", "IMAGE_EDIT_MODEL": "test-image-edit-model", "EMBEDDING_MODEL": "test-embedding-model", } _run_config_check(env, "COMPLETION_ENDPOINT required") def test_config_missing_image_gen_endpoint() -> None: """Test that RuntimeError is raised when IMAGE_GEN_ENDPOINT is missing.""" env: dict[str, str] = { "DISCORD_TOKEN": "test-token", "CHAT_ENDPOINT": "https://chat.example.com/v1", "COMPLETION_ENDPOINT": "https://completion.example.com/v1", "IMAGE_GEN_ENDPOINT": "", "IMAGE_EDIT_ENDPOINT": "https://image-edit.example.com/v1", "EMBEDDING_ENDPOINT": "https://embedding.example.com/v1", "CHAT_MODEL": "test-chat-model", "COMPLETION_MODEL": "test-completion-model", "IMAGE_GEN_MODEL": "test-image-model", "IMAGE_EDIT_MODEL": "test-image-edit-model", "EMBEDDING_MODEL": "test-embedding-model", } _run_config_check(env, "IMAGE_GEN_ENDPOINT required") def test_config_missing_image_edit_endpoint() -> None: """Test that RuntimeError is raised when IMAGE_EDIT_ENDPOINT is missing.""" env: dict[str, str] = { "DISCORD_TOKEN": "test-token", "CHAT_ENDPOINT": "https://chat.example.com/v1", "COMPLETION_ENDPOINT": "https://completion.example.com/v1", "IMAGE_GEN_ENDPOINT": "https://image.example.com/v1", "IMAGE_EDIT_ENDPOINT": "", "EMBEDDING_ENDPOINT": "https://embedding.example.com/v1", "CHAT_MODEL": "test-chat-model", "COMPLETION_MODEL": "test-completion-model", "IMAGE_GEN_MODEL": "test-image-model", "IMAGE_EDIT_MODEL": "test-image-edit-model", "EMBEDDING_MODEL": "test-embedding-model", } _run_config_check(env, "IMAGE_EDIT_ENDPOINT required") def test_config_missing_embedding_endpoint() -> None: """Test that RuntimeError is raised when EMBEDDING_ENDPOINT is missing.""" env: dict[str, str] = { "DISCORD_TOKEN": "test-token", "CHAT_ENDPOINT": "https://chat.example.com/v1", "COMPLETION_ENDPOINT": "https://completion.example.com/v1", "IMAGE_GEN_ENDPOINT": "https://image.example.com/v1", "IMAGE_EDIT_ENDPOINT": "https://image-edit.example.com/v1", "EMBEDDING_ENDPOINT": "", "CHAT_MODEL": "test-chat-model", "COMPLETION_MODEL": "test-completion-model", "IMAGE_GEN_MODEL": "test-image-model", "IMAGE_EDIT_MODEL": "test-image-edit-model", "EMBEDDING_MODEL": "test-embedding-model", } _run_config_check(env, "EMBEDDING_ENDPOINT required") def test_config_missing_chat_model() -> None: """Test that RuntimeError is raised when CHAT_MODEL is missing.""" env: dict[str, str] = { "DISCORD_TOKEN": "test-token", "CHAT_ENDPOINT": "https://chat.example.com/v1", "COMPLETION_ENDPOINT": "https://completion.example.com/v1", "IMAGE_GEN_ENDPOINT": "https://image.example.com/v1", "IMAGE_EDIT_ENDPOINT": "https://image-edit.example.com/v1", "EMBEDDING_ENDPOINT": "https://embedding.example.com/v1", "CHAT_MODEL": "", "COMPLETION_MODEL": "test-completion-model", "IMAGE_GEN_MODEL": "test-image-model", "IMAGE_EDIT_MODEL": "test-image-edit-model", "EMBEDDING_MODEL": "test-embedding-model", } _run_config_check(env, "CHAT_MODEL required") def test_config_missing_completion_model() -> None: """Test that RuntimeError is raised when COMPLETION_MODEL is missing.""" env: dict[str, str] = { "DISCORD_TOKEN": "test-token", "CHAT_ENDPOINT": "https://chat.example.com/v1", "COMPLETION_ENDPOINT": "https://completion.example.com/v1", "IMAGE_GEN_ENDPOINT": "https://image.example.com/v1", "IMAGE_EDIT_ENDPOINT": "https://image-edit.example.com/v1", "EMBEDDING_ENDPOINT": "https://embedding.example.com/v1", "CHAT_MODEL": "test-chat-model", "COMPLETION_MODEL": "", "IMAGE_GEN_MODEL": "test-image-model", "IMAGE_EDIT_MODEL": "test-image-edit-model", "EMBEDDING_MODEL": "test-embedding-model", } _run_config_check(env, "COMPLETION_MODEL required") def test_config_missing_image_gen_model() -> None: """Test that RuntimeError is raised when IMAGE_GEN_MODEL is missing.""" env: dict[str, str] = { "DISCORD_TOKEN": "test-token", "CHAT_ENDPOINT": "https://chat.example.com/v1", "COMPLETION_ENDPOINT": "https://completion.example.com/v1", "IMAGE_GEN_ENDPOINT": "https://image.example.com/v1", "IMAGE_EDIT_ENDPOINT": "https://image-edit.example.com/v1", "EMBEDDING_ENDPOINT": "https://embedding.example.com/v1", "CHAT_MODEL": "test-chat-model", "COMPLETION_MODEL": "test-completion-model", "IMAGE_GEN_MODEL": "", "IMAGE_EDIT_MODEL": "test-image-edit-model", "EMBEDDING_MODEL": "test-embedding-model", } _run_config_check(env, "IMAGE_GEN_MODEL required") def test_config_missing_image_edit_model() -> None: """Test that RuntimeError is raised when IMAGE_EDIT_MODEL is missing.""" env: dict[str, str] = { "DISCORD_TOKEN": "test-token", "CHAT_ENDPOINT": "https://chat.example.com/v1", "COMPLETION_ENDPOINT": "https://completion.example.com/v1", "IMAGE_GEN_ENDPOINT": "https://image.example.com/v1", "IMAGE_EDIT_ENDPOINT": "https://image-edit.example.com/v1", "EMBEDDING_ENDPOINT": "https://embedding.example.com/v1", "CHAT_MODEL": "test-chat-model", "COMPLETION_MODEL": "test-completion-model", "IMAGE_GEN_MODEL": "test-image-model", "IMAGE_EDIT_MODEL": "", "EMBEDDING_MODEL": "test-embedding-model", } _run_config_check(env, "IMAGE_EDIT_MODEL required") def test_config_missing_embedding_model() -> None: """Test that RuntimeError is raised when EMBEDDING_MODEL is missing.""" env: dict[str, str] = { "DISCORD_TOKEN": "test-token", "CHAT_ENDPOINT": "https://chat.example.com/v1", "COMPLETION_ENDPOINT": "https://completion.example.com/v1", "IMAGE_GEN_ENDPOINT": "https://image.example.com/v1", "IMAGE_EDIT_ENDPOINT": "https://image-edit.example.com/v1", "EMBEDDING_ENDPOINT": "https://embedding.example.com/v1", "CHAT_MODEL": "test-chat-model", "COMPLETION_MODEL": "test-completion-model", "IMAGE_GEN_MODEL": "test-image-model", "IMAGE_EDIT_MODEL": "test-image-edit-model", "EMBEDDING_MODEL": "", } _run_config_check(env, "EMBEDDING_MODEL required") def test_config_logging_exists() -> None: """Test that logging is configured in config module.""" from vibe_bot.config import logger assert logger is not None assert logger.name == "vibe_bot.config" def test_config_embedding_dimension() -> None: """Test that EMBEDDING_DIMENSION has expected default value.""" from vibe_bot.config import EMBEDDING_DIMENSION assert EMBEDDING_DIMENSION == 2048