complete restructure
This commit is contained in:
@@ -4,6 +4,9 @@ from __future__ import annotations
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def test_config_defaults() -> None:
|
||||
@@ -12,17 +15,14 @@ def test_config_defaults() -> None:
|
||||
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",
|
||||
@@ -39,8 +39,6 @@ def test_config_defaults() -> None:
|
||||
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"
|
||||
@@ -48,12 +46,10 @@ os.environ["PATH"] = "/usr/bin:/bin"
|
||||
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"
|
||||
@@ -78,20 +74,23 @@ print("OK")
|
||||
|
||||
|
||||
def _run_config_check(env_vars: dict[str, str], expected_error: str) -> None:
|
||||
"""Run a subprocess that imports config and checks for expected RuntimeError."""
|
||||
"""Run a subprocess that imports config and calls validate_config().
|
||||
|
||||
The import itself must never raise; only validate_config() may raise the
|
||||
expected RuntimeError for the missing required setting.
|
||||
"""
|
||||
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
|
||||
vibe_bot.config.validate_config()
|
||||
print("NO_ERROR")
|
||||
except RuntimeError as e:
|
||||
print(f"ERROR: {{e}}")
|
||||
@@ -116,12 +115,10 @@ def test_config_missing_discord_token() -> None:
|
||||
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",
|
||||
@@ -134,12 +131,10 @@ def test_config_missing_chat_endpoint() -> None:
|
||||
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",
|
||||
@@ -147,35 +142,15 @@ def test_config_missing_chat_endpoint() -> None:
|
||||
_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",
|
||||
@@ -188,12 +163,10 @@ def test_config_missing_image_edit_endpoint() -> None:
|
||||
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",
|
||||
@@ -206,12 +179,10 @@ def test_config_missing_embedding_endpoint() -> None:
|
||||
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",
|
||||
@@ -224,12 +195,10 @@ def test_config_missing_chat_model() -> None:
|
||||
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",
|
||||
@@ -237,35 +206,15 @@ def test_config_missing_chat_model() -> None:
|
||||
_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",
|
||||
@@ -278,12 +227,10 @@ def test_config_missing_image_edit_model() -> None:
|
||||
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",
|
||||
@@ -296,12 +243,10 @@ def test_config_missing_embedding_model() -> None:
|
||||
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": "",
|
||||
@@ -309,16 +254,64 @@ def test_config_missing_embedding_model() -> None:
|
||||
_run_config_check(env, "EMBEDDING_MODEL required")
|
||||
|
||||
|
||||
REQUIRED_VARS = (
|
||||
"DISCORD_TOKEN",
|
||||
"CHAT_ENDPOINT",
|
||||
"IMAGE_GEN_ENDPOINT",
|
||||
"IMAGE_EDIT_ENDPOINT",
|
||||
"EMBEDDING_ENDPOINT",
|
||||
"CHAT_MODEL",
|
||||
"IMAGE_GEN_MODEL",
|
||||
"IMAGE_EDIT_MODEL",
|
||||
"EMBEDDING_MODEL",
|
||||
)
|
||||
|
||||
|
||||
def test_validate_config_passes_with_full_env() -> None:
|
||||
"""With all required settings present, validate_config() is a no-op."""
|
||||
from vibe_bot import config
|
||||
|
||||
config.validate_config()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("var_name", REQUIRED_VARS)
|
||||
def test_validate_config_missing_var(var_name: str) -> None:
|
||||
"""Blanking any single required setting makes validate_config() raise."""
|
||||
from vibe_bot import config
|
||||
|
||||
with (
|
||||
patch.object(config, var_name, ""),
|
||||
pytest.raises(RuntimeError, match=f"{var_name} required"),
|
||||
):
|
||||
config.validate_config()
|
||||
|
||||
|
||||
def test_import_config_empty_env_no_raise_no_logging() -> None:
|
||||
"""In an empty env the import succeeds and leaves the root logger unconfigured."""
|
||||
code = """
|
||||
import logging
|
||||
import os
|
||||
os.environ.clear()
|
||||
os.environ["PATH"] = "/usr/bin:/bin"
|
||||
import vibe_bot.config
|
||||
handlers = logging.getLogger().handlers
|
||||
assert handlers == [], f"config configured logging: {handlers}"
|
||||
print("OK")
|
||||
"""
|
||||
|
||||
result = subprocess.run( # noqa: PLW1510
|
||||
[sys.executable, "-c", code],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30,
|
||||
)
|
||||
assert result.returncode == 0, f"Subprocess failed: {result.stderr}"
|
||||
assert "OK" in result.stdout
|
||||
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user