shopstack / tests /test_config.py
pranaysuyash's picture
Sync ShopStack HEAD 6f8adfc
d999bba verified
Raw
History Blame Contribute Delete
5.38 kB
from __future__ import annotations
from shopstack.config import Settings
class TestSettings:
def test_defaults(self, monkeypatch):
monkeypatch.delenv("SHOPSTACK_OFF_THE_GRID", raising=False)
s = Settings(_env_file=None)
assert s.off_the_grid is True
assert s.db_path
assert s.app_port == 7860
def test_env_override(self, monkeypatch):
monkeypatch.setenv("SHOPSTACK_DB_PATH", "/tmp/test.db")
monkeypatch.setenv("SHOPSTACK_APP_PORT", "8080")
monkeypatch.setenv("SHOPSTACK_OFF_THE_GRID", "false")
s = Settings(_env_file=None)
assert s.db_path == "/tmp/test.db"
assert s.app_port == 8080
assert s.off_the_grid is False
def test_cost_budget_default(self, monkeypatch):
"""Default budget is $1.00 USD per session."""
monkeypatch.delenv("SHOPSTACK_COST_BUDGET_LIMIT", raising=False)
s = Settings(_env_file=None)
assert s.cost_budget_limit == 1.00
def test_cost_budget_env_override(self, monkeypatch):
"""SHELLCK_COST_BUDGET_LIMIT env var overrides the default."""
monkeypatch.setenv("SHOPSTACK_COST_BUDGET_LIMIT", "5.50")
s = Settings(_env_file=None)
assert s.cost_budget_limit == 5.50
def test_cost_budget_field_exists(self, monkeypatch):
"""The cost_budget_limit field is required for planner/engine to read it.
This regression-pins the fix: the field was added because
planner/engine.py reads settings.cost_budget_limit, and removing
the field would crash at import time.
"""
s = Settings(_env_file=None)
assert hasattr(s, "cost_budget_limit")
def test_provider_backends_default(self, monkeypatch):
monkeypatch.delenv("SHOPSTACK_OFF_THE_GRID", raising=False)
# conftest.py sets these to "mock" via os.environ.setdefault so the
# session-scoped app import doesn't bootstrap heavy providers. Clear
# them so we actually test the Settings defaults here.
for var in (
"SHOPSTACK_PLANNER_BACKEND", "SHOPSTACK_STT_BACKEND",
"SHOPSTACK_TTS_BACKEND", "SHOPSTACK_VISION_BACKEND",
"SHOPSTACK_OCR_BACKEND", "SHOPSTACK_SEGMENTATION_BACKEND",
"SHOPSTACK_EMBEDDINGS_BACKEND",
):
monkeypatch.delenv(var, raising=False)
s = Settings(_env_file=None)
assert s.stt_backend == "sensevoice"
assert s.tts_backend == "kokoro"
assert s.vision_backend == "qwen3vl"
assert s.segmentation_backend == "birefnet"
assert s.promptable_segmentation_backend == "mobile_sam"
assert s.planner_backend == "local"
assert s.ocr_backend == "glm_ocr"
def test_openbmb_model_stack_preset(self, monkeypatch):
# Clear env vars that could interfere with preset application
monkeypatch.delenv("SHOPSTACK_PLANNER_BACKEND", raising=False)
monkeypatch.delenv("SHOPSTACK_VISION_BACKEND", raising=False)
monkeypatch.delenv("SHOPSTACK_SEGMENTATION_BACKEND", raising=False)
monkeypatch.delenv("SHOPSTACK_OCR_BACKEND", raising=False)
monkeypatch.delenv("SHOPSTACK_EMBEDDINGS_BACKEND", raising=False)
monkeypatch.delenv("SHOPSTACK_PROMPTABLE_SEGMENTATION_BACKEND", raising=False)
monkeypatch.delenv("SHOPSTACK_STT_BACKEND", raising=False)
monkeypatch.delenv("SHOPSTACK_TTS_BACKEND", raising=False)
monkeypatch.delenv("SHOPSTACK_GROUNDING_BACKEND", raising=False)
monkeypatch.delenv("SHOPSTACK_IMAGE_GEN_BACKEND", raising=False)
monkeypatch.delenv("SHOPSTACK_TOOL_CALL_PARSER_BACKEND", raising=False)
s = Settings(_env_file=None, model_stack="openbmb_local")
assert s.planner_backend == "minicpm5"
assert s.vision_backend == "qwen3vl"
assert s.ocr_backend == "glm_ocr"
# The openbmb_local preset only overrides planner + ocr; other
# backends keep their defaults (nomic embeddings, minicpm5 parser,
# sensevoice STT). Earlier revisions of the preset pinned more
# fields, but those have since become the defaults.
assert s.embeddings_backend == "nomic"
# Phase 11 #1.7: was "minicpm5" but MiniCPM5Provider does not
# declare ``tool_call_parser`` in its capabilities set.
# The default is now "mock" so the registry resolves
# immediately to MockToolCallParser.
assert s.tool_call_parser_backend == "mock"
assert s.stt_backend == "sensevoice"
def test_provider_backends_compat_alias(self):
s = Settings(_env_file=None, stt_backend="mock", tts_backend="mock", vision_backend="mock", ocr_backend="mock")
assert s.provider_backends["stt"] == "mock"
assert s.provider_backends["tts"] == "mock"
assert s.provider_backends["vision"] == "mock"
def test_database_path_alias(self, monkeypatch):
monkeypatch.delenv("SHOPSTACK_OFF_THE_GRID", raising=False)
s = Settings(_env_file=None, db_path="/tmp/legacy.db")
assert s.database_path == "/tmp/legacy.db"
def test_legacy_env_database_path_alias(self, monkeypatch):
monkeypatch.setenv("SHOPSTACK_DATABASE_PATH", "/tmp/legacy-env.db")
monkeypatch.delenv("SHOPSTACK_DB_PATH", raising=False)
s = Settings(_env_file=None)
assert s.db_path == "/tmp/legacy-env.db"