Files
Artificial-Sweetener-Simple…/tests/settings/test_settings.py
T

191 lines
6.0 KiB
Python

# SimpleSyrup - workflow-focused ComfyUI extensions for image generation
# Copyright (C) 2026 Artificial Sweetener and contributors
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Tests for SimpleSyrup backend settings persistence."""
from __future__ import annotations
import json
from pathlib import Path
from types import ModuleType
import pytest
from simple_syrup.runtime.settings import (
SimpleSyrupSettings,
SimpleSyrupSettingsError,
)
from simple_syrup.runtime.settings_repository import SimpleSyrupSettingsRepository
def test_default_settings_show_downloadable_models() -> None:
"""Default settings favor low-friction model discovery."""
assert SimpleSyrupSettings().show_downloadable_models is True
assert SimpleSyrupSettings().quant_cache_limit_gib == 20
@pytest.mark.parametrize("value", [0, 2049, 1.5, True, "20"])
def test_settings_reject_invalid_quant_cache_limits(value: object) -> None:
"""The global cache limit is a bounded whole number of GiB."""
with pytest.raises(SimpleSyrupSettingsError, match="quant_cache_limit_gib"):
SimpleSyrupSettings.from_payload(
{
"show_downloadable_models": True,
"quant_cache_limit_gib": value,
}
)
def test_missing_settings_file_returns_defaults(tmp_path: Path) -> None:
"""Missing persisted settings are treated as default settings."""
repository = SimpleSyrupSettingsRepository(tmp_path / "settings.json")
assert repository.load() == SimpleSyrupSettings()
def test_valid_settings_file_is_loaded(tmp_path: Path) -> None:
"""A valid settings file controls the backend setting."""
path = tmp_path / "settings.json"
path.write_text(
json.dumps({"show_downloadable_models": False}),
encoding="utf-8",
)
assert SimpleSyrupSettingsRepository(path).load() == SimpleSyrupSettings(
show_downloadable_models=False
)
def test_invalid_json_file_returns_defaults(tmp_path: Path) -> None:
"""Malformed JSON fails closed to defaults without deleting user data."""
path = tmp_path / "settings.json"
path.write_text("{not-json", encoding="utf-8")
assert SimpleSyrupSettingsRepository(path).load() == SimpleSyrupSettings()
assert path.read_text(encoding="utf-8") == "{not-json"
def test_invalid_schema_returns_defaults(tmp_path: Path) -> None:
"""Malformed settings schema fails closed to defaults."""
path = tmp_path / "settings.json"
path.write_text(
json.dumps({"show_downloadable_models": "false"}),
encoding="utf-8",
)
assert SimpleSyrupSettingsRepository(path).load() == SimpleSyrupSettings()
def test_saving_settings_writes_validated_schema(tmp_path: Path) -> None:
"""Saving settings writes only the known schema."""
path = tmp_path / "nested" / "settings.json"
repository = SimpleSyrupSettingsRepository(path)
repository.save(SimpleSyrupSettings(show_downloadable_models=False))
assert json.loads(path.read_text(encoding="utf-8")) == {
"external_llm": {
"base_url": "",
"cached_models": [],
"default_model": "",
},
"quant_cache_limit_gib": 20,
"show_downloadable_models": False,
}
def test_settings_path_uses_comfy_user_directory(tmp_path: Path) -> None:
"""Settings path resolution uses Comfy's user directory API."""
folder_paths = ModuleType("folder_paths")
folder_paths.get_user_directory = lambda: str(tmp_path) # type: ignore[attr-defined]
repository = SimpleSyrupSettingsRepository(folder_paths_module=folder_paths)
assert repository.settings_path() == (
tmp_path / "default" / "SimpleSyrup" / "settings.json"
)
def test_payload_validation_rejects_non_boolean_value() -> None:
"""Schema validation rejects non-boolean setting values."""
with pytest.raises(SimpleSyrupSettingsError, match="show_downloadable_models"):
SimpleSyrupSettings.from_payload({"show_downloadable_models": 1})
def test_missing_external_llm_settings_loads_defaults(tmp_path: Path) -> None:
"""Existing settings files without external LLM settings remain valid."""
path = tmp_path / "settings.json"
path.write_text(
json.dumps({"show_downloadable_models": False}),
encoding="utf-8",
)
settings = SimpleSyrupSettingsRepository(path).load()
assert settings.show_downloadable_models is False
assert settings.external_llm.base_url == ""
assert settings.external_llm.cached_models == ()
assert settings.external_llm.default_model == ""
def test_valid_external_llm_settings_are_loaded(tmp_path: Path) -> None:
"""External LLM settings are normalized when loaded."""
path = tmp_path / "settings.json"
path.write_text(
json.dumps(
{
"show_downloadable_models": True,
"external_llm": {
"base_url": "https://provider.example/v1/",
"cached_models": ["model-a", "model-a", "model-b"],
"default_model": "model-b",
},
}
),
encoding="utf-8",
)
settings = SimpleSyrupSettingsRepository(path).load()
assert settings.external_llm.base_url == "https://provider.example/v1"
assert settings.external_llm.cached_models == ("model-a", "model-b")
assert settings.external_llm.default_model == "model-b"
def test_invalid_external_llm_settings_fall_back_to_external_defaults(
tmp_path: Path,
) -> None:
"""Malformed external LLM settings do not invalidate other settings."""
path = tmp_path / "settings.json"
path.write_text(
json.dumps(
{
"show_downloadable_models": False,
"external_llm": {
"base_url": "not-a-url",
"cached_models": ["model-a"],
"default_model": "model-a",
},
}
),
encoding="utf-8",
)
settings = SimpleSyrupSettingsRepository(path).load()
assert settings.show_downloadable_models is False
assert settings.external_llm.base_url == ""