# tests/unit/middleware/test_merchant_domain_resolution.py """ Unit tests for merchant domain resolution in platform and store context middleware. Tests cover: - PlatformContextManager.get_platform_from_context() with merchant domain - StoreContextManager.get_store_from_context() with merchant domain - Priority: StoreDomain > MerchantDomain - Fallthrough when MerchantDomain not found or inactive/unverified """ import uuid from datetime import UTC, datetime import pytest from app.modules.tenancy.models import Store, StoreDomain from app.modules.tenancy.models.merchant_domain import MerchantDomain from middleware.platform_context import PlatformContextManager from middleware.store_context import StoreContextManager # ============================================================================= # PLATFORM CONTEXT - MERCHANT DOMAIN RESOLUTION # ============================================================================= @pytest.mark.unit @pytest.mark.middleware class TestPlatformContextMerchantDomain: """Test PlatformContextManager.get_platform_from_context() with merchant domains.""" def test_resolves_platform_from_merchant_domain(self, db, test_merchant, test_platform): """Test that platform is resolved from MerchantDomain.platform_id.""" unique_id = str(uuid.uuid4())[:8] md = MerchantDomain( merchant_id=test_merchant.id, platform_id=test_platform.id, domain=f"mplatform{unique_id}.lu", is_primary=True, is_active=True, is_verified=True, verified_at=datetime.now(UTC), verification_token=f"mpt_{unique_id}", ) db.add(md) db.commit() context = { "domain": f"mplatform{unique_id}.lu", "detection_method": "domain", "host": f"mplatform{unique_id}.lu", "original_path": "/", } platform = PlatformContextManager.get_platform_from_context(db, context) assert platform is not None assert platform.id == test_platform.id def test_falls_through_when_merchant_domain_not_found(self, db): """Test that None is returned when no MerchantDomain matches.""" context = { "domain": "nonexistent.lu", "detection_method": "domain", "host": "nonexistent.lu", "original_path": "/", } platform = PlatformContextManager.get_platform_from_context(db, context) assert platform is None def test_falls_through_when_merchant_domain_inactive(self, db, test_merchant, test_platform): """Test that inactive MerchantDomain is skipped.""" unique_id = str(uuid.uuid4())[:8] md = MerchantDomain( merchant_id=test_merchant.id, platform_id=test_platform.id, domain=f"inactive{unique_id}.lu", is_primary=True, is_active=False, is_verified=True, verified_at=datetime.now(UTC), verification_token=f"ipt_{unique_id}", ) db.add(md) db.commit() context = { "domain": f"inactive{unique_id}.lu", "detection_method": "domain", "host": f"inactive{unique_id}.lu", "original_path": "/", } platform = PlatformContextManager.get_platform_from_context(db, context) assert platform is None def test_falls_through_when_merchant_domain_unverified(self, db, test_merchant, test_platform): """Test that unverified MerchantDomain is skipped.""" unique_id = str(uuid.uuid4())[:8] md = MerchantDomain( merchant_id=test_merchant.id, platform_id=test_platform.id, domain=f"unverified{unique_id}.lu", is_primary=True, is_active=True, is_verified=False, verification_token=f"upt_{unique_id}", ) db.add(md) db.commit() context = { "domain": f"unverified{unique_id}.lu", "detection_method": "domain", "host": f"unverified{unique_id}.lu", "original_path": "/", } platform = PlatformContextManager.get_platform_from_context(db, context) assert platform is None def test_store_domain_takes_priority_over_merchant_domain( self, db, test_store, test_merchant, test_platform ): """Test that StoreDomain is checked before MerchantDomain.""" unique_id = str(uuid.uuid4())[:8] domain_name = f"priority{unique_id}.lu" # Create a StoreDomain with this domain sd = StoreDomain( store_id=test_store.id, platform_id=test_platform.id, domain=domain_name, is_primary=True, is_active=True, is_verified=True, verified_at=datetime.now(UTC), verification_token=f"sdp_{unique_id}", ) db.add(sd) db.commit() context = { "domain": domain_name, "detection_method": "domain", "host": domain_name, "original_path": "/", } platform = PlatformContextManager.get_platform_from_context(db, context) assert platform is not None assert platform.id == test_platform.id # ============================================================================= # STORE CONTEXT - MERCHANT DOMAIN RESOLUTION # ============================================================================= @pytest.mark.unit @pytest.mark.middleware class TestStoreContextMerchantDomain: """Test StoreContextManager.get_store_from_context() with merchant domains.""" def test_resolves_to_merchants_first_active_store( self, db, test_merchant, test_store ): """Test that merchant domain resolves to merchant's first active store.""" unique_id = str(uuid.uuid4())[:8] md = MerchantDomain( merchant_id=test_merchant.id, domain=f"mstore{unique_id}.lu", is_primary=True, is_active=True, is_verified=True, verified_at=datetime.now(UTC), verification_token=f"mst_{unique_id}", ) db.add(md) db.commit() context = { "domain": f"mstore{unique_id}.lu", "detection_method": "custom_domain", "host": f"mstore{unique_id}.lu", "original_host": f"mstore{unique_id}.lu", } store = StoreContextManager.get_store_from_context(db, context) assert store is not None assert store.merchant_id == test_merchant.id assert context.get("merchant_domain") is True assert context.get("merchant_id") == test_merchant.id def test_store_domain_takes_priority_over_merchant_domain( self, db, test_store, test_merchant ): """Test that StoreDomain takes priority over MerchantDomain.""" unique_id = str(uuid.uuid4())[:8] domain_name = f"storepri{unique_id}.lu" # Create StoreDomain for this store sd = StoreDomain( store_id=test_store.id, domain=domain_name, is_primary=True, is_active=True, is_verified=True, verified_at=datetime.now(UTC), verification_token=f"sdpri_{unique_id}", ) db.add(sd) db.commit() context = { "domain": domain_name, "detection_method": "custom_domain", "host": domain_name, "original_host": domain_name, } store = StoreContextManager.get_store_from_context(db, context) assert store is not None assert store.id == test_store.id # merchant_domain should NOT be set because StoreDomain resolved first assert context.get("merchant_domain") is None def test_falls_through_when_no_active_stores(self, db, other_merchant): """Test that None is returned when merchant has no active stores.""" unique_id = str(uuid.uuid4())[:8] # Create inactive store for the merchant inactive = Store( merchant_id=other_merchant.id, store_code=f"INACTIVE_{unique_id.upper()}", subdomain=f"inactive{unique_id.lower()}", name="Inactive Store", is_active=False, ) db.add(inactive) md = MerchantDomain( merchant_id=other_merchant.id, domain=f"noactive{unique_id}.lu", is_primary=True, is_active=True, is_verified=True, verified_at=datetime.now(UTC), verification_token=f"nat_{unique_id}", ) db.add(md) db.commit() context = { "domain": f"noactive{unique_id}.lu", "detection_method": "custom_domain", "host": f"noactive{unique_id}.lu", "original_host": f"noactive{unique_id}.lu", } store = StoreContextManager.get_store_from_context(db, context) assert store is None def test_falls_through_when_merchant_domain_inactive(self, db, test_merchant): """Test that inactive MerchantDomain is not resolved to a store.""" unique_id = str(uuid.uuid4())[:8] md = MerchantDomain( merchant_id=test_merchant.id, domain=f"inactivem{unique_id}.lu", is_primary=True, is_active=False, is_verified=True, verified_at=datetime.now(UTC), verification_token=f"im_{unique_id}", ) db.add(md) db.commit() context = { "domain": f"inactivem{unique_id}.lu", "detection_method": "custom_domain", "host": f"inactivem{unique_id}.lu", "original_host": f"inactivem{unique_id}.lu", } store = StoreContextManager.get_store_from_context(db, context) assert store is None