# app/modules/tenancy/tests/unit/test_tenancy_metrics.py """Unit tests for TenancyMetricsProvider.get_merchant_metrics.""" import uuid import pytest from app.modules.tenancy.models import Merchant, Store, StoreUser, User from app.modules.tenancy.services.tenancy_metrics import TenancyMetricsProvider @pytest.fixture def metrics_merchant(db): """Create a merchant owner and merchant for metrics tests.""" from middleware.auth import AuthManager auth = AuthManager() user = User( email=f"metricsowner_{uuid.uuid4().hex[:8]}@test.com", username=f"metricsowner_{uuid.uuid4().hex[:8]}", hashed_password=auth.hash_password("pass123"), role="merchant_owner", is_active=True, ) db.add(user) db.flush() merchant = Merchant( name="Metrics Test Merchant", owner_user_id=user.id, contact_email=user.email, is_active=True, is_verified=True, ) db.add(merchant) db.commit() db.refresh(merchant) return merchant @pytest.fixture def metrics_stores(db, metrics_merchant): """Create 3 stores (2 active, 1 inactive) for the merchant.""" stores = [] for i, active in enumerate([True, True, False]): uid = uuid.uuid4().hex[:8].upper() store = Store( merchant_id=metrics_merchant.id, store_code=f"MSTORE_{uid}", subdomain=f"mstore{uid.lower()}", name=f"Metrics Store {i}", is_active=active, is_verified=True, ) db.add(store) stores.append(store) db.commit() for s in stores: db.refresh(s) return stores @pytest.fixture def metrics_team_members(db, metrics_stores): """Create team members across merchant stores.""" from middleware.auth import AuthManager auth = AuthManager() users = [] for i in range(3): users.append(User( email=f"team_{uuid.uuid4().hex[:8]}@test.com", username=f"team_{uuid.uuid4().hex[:8]}", hashed_password=auth.hash_password("pass123"), role="store_user", is_active=True, )) db.add_all(users) db.flush() # User 0 on store 0 and store 1 (should be counted once) db.add(StoreUser(store_id=metrics_stores[0].id, user_id=users[0].id, is_active=True)) db.add(StoreUser(store_id=metrics_stores[1].id, user_id=users[0].id, is_active=True)) # User 1 on store 0 only db.add(StoreUser(store_id=metrics_stores[0].id, user_id=users[1].id, is_active=True)) # User 2 on store 0 but inactive db.add(StoreUser(store_id=metrics_stores[0].id, user_id=users[2].id, is_active=False)) db.commit() return users @pytest.mark.unit @pytest.mark.tenancy class TestTenancyMetricsProviderMerchant: """Tests for TenancyMetricsProvider.get_merchant_metrics.""" def setup_method(self): self.provider = TenancyMetricsProvider() def test_total_stores(self, db, metrics_merchant, metrics_stores): """Returns correct total store count for merchant.""" metrics = self.provider.get_merchant_metrics(db, metrics_merchant.id) by_key = {m.key: m.value for m in metrics} assert by_key["tenancy.total_stores"] == 3 def test_active_stores(self, db, metrics_merchant, metrics_stores): """Returns correct active store count (excludes inactive).""" metrics = self.provider.get_merchant_metrics(db, metrics_merchant.id) by_key = {m.key: m.value for m in metrics} assert by_key["tenancy.active_stores"] == 2 def test_team_members_distinct(self, db, metrics_merchant, metrics_stores, metrics_team_members): """Counts distinct active team members across stores.""" metrics = self.provider.get_merchant_metrics(db, metrics_merchant.id) by_key = {m.key: m.value for m in metrics} # 2 active distinct users (user 0 on 2 stores counted once, user 1, user 2 inactive) assert by_key["tenancy.team_members"] == 2 def test_no_stores(self, db, metrics_merchant): """Returns zero counts when merchant has no stores.""" metrics = self.provider.get_merchant_metrics(db, metrics_merchant.id) by_key = {m.key: m.value for m in metrics} assert by_key["tenancy.total_stores"] == 0 assert by_key["tenancy.active_stores"] == 0 assert by_key["tenancy.team_members"] == 0 def test_nonexistent_merchant(self, db): """Returns zero counts for a non-existent merchant ID.""" metrics = self.provider.get_merchant_metrics(db, 999999) by_key = {m.key: m.value for m in metrics} assert by_key["tenancy.total_stores"] == 0