"""Tests for loyalty module configuration validators.""" import os import pytest from app.modules.loyalty.config import ModuleConfig @pytest.mark.unit @pytest.mark.loyalty class TestGoogleWalletConfigValidator: """Validator must fail fast when the SA path is set but unreachable.""" def test_unset_path_is_allowed(self, monkeypatch): """Google Wallet config is optional — None passes.""" monkeypatch.delenv("LOYALTY_GOOGLE_SERVICE_ACCOUNT_JSON", raising=False) monkeypatch.delenv("LOYALTY_GOOGLE_ISSUER_ID", raising=False) cfg = ModuleConfig(_env_file=None) assert cfg.google_service_account_json is None assert cfg.is_google_wallet_enabled is False def test_existing_file_passes(self, tmp_path, monkeypatch): """A real file path passes and is returned expanded.""" sa_file = tmp_path / "fake-sa.json" sa_file.write_text("{}") monkeypatch.setenv("LOYALTY_GOOGLE_SERVICE_ACCOUNT_JSON", str(sa_file)) monkeypatch.setenv("LOYALTY_GOOGLE_ISSUER_ID", "1234567890") cfg = ModuleConfig(_env_file=None) assert cfg.google_service_account_json == str(sa_file) assert cfg.is_google_wallet_enabled is True def test_missing_file_raises(self, tmp_path, monkeypatch): """A path that does not exist raises a clear error at import time.""" bogus = tmp_path / "does-not-exist.json" monkeypatch.setenv("LOYALTY_GOOGLE_SERVICE_ACCOUNT_JSON", str(bogus)) with pytest.raises(ValueError, match="no file exists"): ModuleConfig(_env_file=None) def test_unreadable_file_raises(self, tmp_path, monkeypatch): """A path that exists but is not readable raises a clear error.""" sa_file = tmp_path / "no-read.json" sa_file.write_text("{}") os.chmod(sa_file, 0o000) try: monkeypatch.setenv( "LOYALTY_GOOGLE_SERVICE_ACCOUNT_JSON", str(sa_file) ) # Skip if running as root (root bypasses unix file perms) if os.geteuid() == 0: pytest.skip("Cannot test unreadable file as root") with pytest.raises(ValueError, match="not readable"): ModuleConfig(_env_file=None) finally: os.chmod(sa_file, 0o600) def test_tilde_path_is_expanded(self, tmp_path, monkeypatch): """Leading ~ is expanded so deployments can use ~/apps/orion/...""" # Plant the file at $HOME/.../fake-sa.json then reference via ~ home = tmp_path / "home" home.mkdir() sa_dir = home / "apps" / "orion" sa_dir.mkdir(parents=True) sa_file = sa_dir / "fake-sa.json" sa_file.write_text("{}") monkeypatch.setenv("HOME", str(home)) monkeypatch.setenv( "LOYALTY_GOOGLE_SERVICE_ACCOUNT_JSON", "~/apps/orion/fake-sa.json", ) cfg = ModuleConfig(_env_file=None) assert cfg.google_service_account_json == str(sa_file) @pytest.mark.unit @pytest.mark.loyalty class TestAppleWalletEnabledFlag: """is_apple_wallet_enabled is a derived flag for the storefront UI.""" def test_disabled_when_unset(self, monkeypatch): for var in ( "LOYALTY_APPLE_PASS_TYPE_ID", "LOYALTY_APPLE_TEAM_ID", "LOYALTY_APPLE_WWDR_CERT_PATH", "LOYALTY_APPLE_SIGNER_CERT_PATH", "LOYALTY_APPLE_SIGNER_KEY_PATH", ): monkeypatch.delenv(var, raising=False) cfg = ModuleConfig(_env_file=None) assert cfg.is_apple_wallet_enabled is False def test_enabled_when_all_set(self, monkeypatch): monkeypatch.setenv("LOYALTY_APPLE_PASS_TYPE_ID", "pass.com.x.y") monkeypatch.setenv("LOYALTY_APPLE_TEAM_ID", "ABCD1234") monkeypatch.setenv("LOYALTY_APPLE_WWDR_CERT_PATH", "/tmp/wwdr.pem") monkeypatch.setenv("LOYALTY_APPLE_SIGNER_CERT_PATH", "/tmp/signer.pem") monkeypatch.setenv("LOYALTY_APPLE_SIGNER_KEY_PATH", "/tmp/signer.key") cfg = ModuleConfig(_env_file=None) assert cfg.is_apple_wallet_enabled is True