BlossomTune-Orchestrator / tests /test_settings.py
mrs83's picture
Add settings module and initial tests.
e29625a
raw
history blame
5.2 kB
import pytest
import yaml
import json
from unittest.mock import patch
# Import the Settings class specifically to allow for instance management in tests
from blossomtune_gradio.settings import Settings
@pytest.fixture(autouse=True)
def reset_settings_singleton():
"""
Fixture to automatically reset the Settings singleton before each test.
This allows creating a new, clean instance for each test scenario by
directly resetting the internal `_instance` variable.
"""
Settings._instance = None
@pytest.fixture
def valid_config_files(tmp_path):
"""Creates a valid config and schema file in a temporary directory."""
config_dir = tmp_path / "config"
config_dir.mkdir()
config_content = {
"ui": {
"welcome_message_md": "Hello, {{ name }}!",
"error_message_md": "An error occurred.",
}
}
schema_content = {
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"ui": {
"type": "object",
"properties": {
"welcome_message_md": {"type": "string"},
"error_message_md": {"type": "string"},
},
"required": ["welcome_message_md", "error_message_md"],
}
},
"required": ["ui"],
}
config_path = config_dir / "blossomtune.yaml"
schema_path = config_dir / "blossomtune.schema.json"
with open(config_path, "w") as f:
yaml.dump(config_content, f)
with open(schema_path, "w") as f:
json.dump(schema_content, f)
return str(config_path), str(schema_path)
def test_load_valid_config(valid_config_files):
"""Tests successful loading of a valid configuration."""
config_path, schema_path = valid_config_files
settings = Settings(config_path=config_path, schema_path=schema_path)
assert "welcome_message_md" in settings.templates
assert "error_message_md" in settings.templates
rendered_text = settings.get_text("welcome_message_md", name="World")
assert rendered_text == "Hello, World!"
def test_missing_config_file(tmp_path, capsys):
"""Tests handling of a missing configuration file and captures stdout."""
schema_path = tmp_path / "schema.json"
schema_path.touch() # Create an empty schema for the test
settings = Settings(config_path="nonexistent.yaml", schema_path=str(schema_path))
assert not settings.templates
# Check that an error was printed to the console
captured = capsys.readouterr()
assert "Error: Configuration file not found" in captured.out
def test_invalid_yaml_file(tmp_path, capsys):
"""Tests handling of a syntactically incorrect YAML file."""
config_path = tmp_path / "invalid.yaml"
schema_path = tmp_path / "schema.json"
schema_path.touch()
with open(config_path, "w") as f:
f.write("ui: { welcome: 'Hello'") # Malformed YAML
settings = Settings(config_path=str(config_path), schema_path=str(schema_path))
assert not settings.templates
captured = capsys.readouterr()
assert "Error parsing YAML file" in captured.out
def test_schema_validation_failure(tmp_path, capsys):
"""Tests that validation fails if the config doesn't match the schema."""
config_dir = tmp_path / "config"
config_dir.mkdir()
# Config is missing the required 'error_message'
config_content = {"ui": {"welcome_message_md": "Hello!"}}
schema_content = {
"type": "object",
"properties": {"ui": {"type": "object", "required": ["error_message_md"]}},
}
config_path = config_dir / "blossomtune.yaml"
schema_path = config_dir / "blossomtune.schema.json"
with open(config_path, "w") as f:
yaml.dump(config_content, f)
with open(schema_path, "w") as f:
json.dump(schema_content, f)
settings = Settings(config_path=str(config_path), schema_path=str(schema_path))
assert not settings.templates
captured = capsys.readouterr()
assert "Error: YAML configuration is invalid" in captured.out
@patch("blossomtune_gradio.config.BLOSSOMTUNE_CONFIG")
def test_load_from_env_variable(mock_config_env, valid_config_files):
"""Tests loading the config path from an environment variable."""
config_path, schema_path = valid_config_files
mock_config_env = config_path
# By patching the config module, the Settings constructor will pick it up
with patch("blossomtune_gradio.settings.cfg.BLOSSOMTUNE_CONFIG", mock_config_env):
settings = Settings(schema_path=schema_path)
assert settings.config_path == config_path
rendered_text = settings.get_text("welcome_message_md", name="From Env")
assert rendered_text == "Hello, From Env!"
def test_singleton_pattern(valid_config_files):
"""Tests that the same instance of Settings is always returned."""
config_path, schema_path = valid_config_files
s1 = Settings(config_path=config_path, schema_path=schema_path)
s2 = Settings() # Should return the same instance as s1
assert s1 is s2
# Verify s2 is configured, proving it's the same instance
assert "welcome_message_md" in s2.templates