diff --git a/app/wizard/tiers.py b/app/wizard/tiers.py index fa1310d..a9a9e3c 100644 --- a/app/wizard/tiers.py +++ b/app/wizard/tiers.py @@ -81,6 +81,9 @@ BYOK_UNLOCKABLE: frozenset[str] = frozenset({ # Demo mode flag — read from environment at module load time. # Allows demo toolbar to override tier without accessing st.session_state (thread-safe). +# _DEMO_MODE is immutable after import for the process lifetime. +# DEMO_MODE must be set in the environment before the process starts (e.g., via +# Docker Compose environment:). Runtime toggling is not supported. _DEMO_MODE = _os.environ.get("DEMO_MODE", "").lower() in ("1", "true", "yes") # Free integrations (not in FEATURES): diff --git a/tests/test_wizard_tiers.py b/tests/test_wizard_tiers.py index 3c33ea2..d064d7e 100644 --- a/tests/test_wizard_tiers.py +++ b/tests/test_wizard_tiers.py @@ -1,5 +1,7 @@ import sys from pathlib import Path +from unittest.mock import patch + sys.path.insert(0, str(Path(__file__).parent.parent)) from app.wizard.tiers import can_use, tier_label, TIERS, FEATURES, BYOK_UNLOCKABLE @@ -129,43 +131,24 @@ def test_vue_ui_beta_premium_tier(): def test_can_use_demo_tier_overrides_real_tier(): - # demo_tier kwarg substitutes for the real tier when provided and DEMO_MODE is set - import os - os.environ["DEMO_MODE"] = "true" - # Need to reload the module to pick up the new DEMO_MODE value - import importlib - import app.wizard.tiers as tiers_module - importlib.reload(tiers_module) - try: - assert tiers_module.can_use("free", "company_research", demo_tier="paid") is True - finally: - # Cleanup: restore original state - os.environ.pop("DEMO_MODE", None) - importlib.reload(tiers_module) + # demo_tier="paid" overrides real tier "free" when DEMO_MODE is active + with patch('app.wizard.tiers._DEMO_MODE', True): + assert can_use("free", "company_research", demo_tier="paid") is True def test_can_use_demo_tier_free_restricts(): - # demo_tier="free" should restrict access even if real tier is "paid" - import os - os.environ["DEMO_MODE"] = "true" - import importlib - import app.wizard.tiers as tiers_module - importlib.reload(tiers_module) - try: - assert tiers_module.can_use("paid", "model_fine_tuning", demo_tier="free") is False - finally: - os.environ.pop("DEMO_MODE", None) - importlib.reload(tiers_module) + # demo_tier="free" restricts access even if real tier is "paid" + with patch('app.wizard.tiers._DEMO_MODE', True): + assert can_use("paid", "model_fine_tuning", demo_tier="free") is False def test_can_use_demo_tier_none_falls_back_to_real(): - # demo_tier=None means no override — real tier is used - assert can_use("paid", "company_research", demo_tier=None) is True + # demo_tier=None means no override regardless of DEMO_MODE + with patch('app.wizard.tiers._DEMO_MODE', True): + assert can_use("paid", "company_research", demo_tier=None) is True def test_can_use_demo_tier_does_not_affect_non_demo(): - # demo_tier is only applied when DEMO_MODE env var is set; - # in tests DEMO_MODE is False by default, so demo_tier is ignored - import os - os.environ.pop("DEMO_MODE", None) - assert can_use("free", "company_research", demo_tier="paid") is False + # When _DEMO_MODE is False, demo_tier is ignored + with patch('app.wizard.tiers._DEMO_MODE', False): + assert can_use("free", "company_research", demo_tier="paid") is False