""" Every Real*Repository class is a thin wrapper over pb_client. These tests instantiate the real classes directly (bypassing the Mock* selection that USE_MOCK_REPOSITORIES otherwise activates) and patch each module's `pb_client` reference with a recording fake, verifying correct collection names and call delegation without needing a live PocketBase instance. """ from repositories.tenant_repository import TenantRepository from repositories.seat_repository import SeatRepository from repositories.competitor_repository import CompetitorRepository from repositories.product_repository import ProductRepository from repositories.scrape_repository import ScrapeRepository from repositories.proxy_repository import ProxyRepository from repositories.alert_repository import AlertRepository from repositories.battlecard_repository import BattlecardRepository from repositories.comparable_repository import ComparableRepository from repositories.brief_repository import BriefRepository from repositories.monitoring_repository import MonitoringRepository from repositories.price_history_repository import PriceHistoryRepository from repositories.client_trips_repository import ClientTripsRepository class _FakePbClient: """Records every call made to it and returns canned values.""" def __init__(self): self.calls = [] self.list_return = [] self.get_first_return = {'id': 'rec1'} self.get_one_return = {'id': 'rec1'} self.create_return = {'id': 'rec1'} self.update_return = {'id': 'rec1', 'updated': True} def list(self, collection, filter_str=None, sort=None, page=1, per_page=50): self.calls.append(('list', collection, filter_str, sort)) return self.list_return def get_first(self, collection, filter_str): self.calls.append(('get_first', collection, filter_str)) return self.get_first_return def get_one(self, collection, record_id): self.calls.append(('get_one', collection, record_id)) return self.get_one_return def create(self, collection, data): self.calls.append(('create', collection, data)) return self.create_return def update(self, collection, record_id, data): self.calls.append(('update', collection, record_id, data)) return self.update_return def delete(self, collection, record_id): self.calls.append(('delete', collection, record_id)) return True def test_tenant_repository_delegates_correctly(monkeypatch): fake = _FakePbClient() monkeypatch.setattr('repositories.tenant_repository.pb_client', fake) repo = TenantRepository() assert repo.get_by_domain('gadventures.com') == fake.get_first_return assert repo.get_by_id('t1') == fake.get_one_return assert repo.get_by_stripe_customer_id('cus_123') == fake.get_first_return assert repo.create({'name': 'x'}) == fake.create_return assert repo.update('t1', {'name': 'y'}) == fake.update_return assert fake.calls[0] == ('get_first', 'tenants', 'domain = "gadventures.com"') def test_seat_repository_delegates_correctly(monkeypatch): fake = _FakePbClient() fake.list_return = [{'id': 's1'}, {'id': 's2'}] monkeypatch.setattr('repositories.seat_repository.pb_client', fake) repo = SeatRepository() assert repo.get_active('t1', 'pm@gadventures.com') == fake.get_first_return assert repo.count_active('t1') == 2 assert repo.list_for_tenant('t1') == fake.list_return assert repo.create({'email': 'x'}) == fake.create_return repo.update_last_accessed('s1') assert repo.delete('s1') is True def test_competitor_repository_delegates_correctly(monkeypatch): fake = _FakePbClient() fake.list_return = [{'id': 'c1', 'website': 'https://intrepidtravel.com'}] monkeypatch.setattr('repositories.competitor_repository.pb_client', fake) repo = CompetitorRepository() assert repo.get_by_domain('t1', 'intrepidtravel.com') == fake.list_return[0] assert repo.get_by_id('c1') == fake.get_one_return assert repo.list_for_tenant('t1') == fake.list_return assert repo.create({'name': 'x'}) == fake.create_return assert repo.update('c1', {'active': False}) == fake.update_return def test_product_repository_delegates_correctly(monkeypatch): fake = _FakePbClient() fake.list_return = [{'id': 'p1', 'last_seen': '2026-01-01'}] monkeypatch.setattr('repositories.product_repository.pb_client', fake) repo = ProductRepository() assert repo.get_latest_for_competitor('c1') == fake.list_return assert repo.list_for_tenant('t1') == fake.list_return assert repo.create({'trip_name': 'x'}) == fake.create_return assert repo.update('p1', {'majority_price_usd': 100}) == fake.update_return assert repo.get_by_competitor_and_name('c1', 'Peru Classic') == fake.get_first_return def test_product_repository_get_by_competitor_and_name_none_without_trip_name(monkeypatch): fake = _FakePbClient() monkeypatch.setattr('repositories.product_repository.pb_client', fake) repo = ProductRepository() assert repo.get_by_competitor_and_name('c1', None) is None assert repo.get_by_competitor_and_name('c1', '') is None def test_scrape_repository_delegates_correctly(monkeypatch): fake = _FakePbClient() fake.list_return = [{'id': 'r1'}] monkeypatch.setattr('repositories.scrape_repository.pb_client', fake) repo = ScrapeRepository() assert repo.create({'status': 'pending'}) == fake.create_return assert repo.update('r1', {'status': 'complete'}) == fake.update_return assert repo.get_by_id('r1') == fake.get_one_return assert repo.list_recent_for_tenant('t1') == fake.list_return assert repo.get_latest_complete_for_tenant('t1') == fake.list_return[0] def test_scrape_repository_get_latest_complete_returns_none_when_no_runs(monkeypatch): fake = _FakePbClient() fake.list_return = [] monkeypatch.setattr('repositories.scrape_repository.pb_client', fake) repo = ScrapeRepository() assert repo.get_latest_complete_for_tenant('t1') is None def test_scrape_repository_get_last_hash_for_url_returns_hash(monkeypatch): fake = _FakePbClient() fake.list_return = [{'id': 'r1', 'content_hash': 'abc123'}] monkeypatch.setattr('repositories.scrape_repository.pb_client', fake) repo = ScrapeRepository() assert repo.get_last_hash_for_url('c1') == 'abc123' def test_scrape_repository_get_last_hash_for_url_returns_none_when_never_hashed(monkeypatch): fake = _FakePbClient() fake.list_return = [] monkeypatch.setattr('repositories.scrape_repository.pb_client', fake) repo = ScrapeRepository() assert repo.get_last_hash_for_url('c1') is None def test_proxy_repository_delegates_correctly(monkeypatch): fake = _FakePbClient() monkeypatch.setattr('repositories.proxy_repository.pb_client', fake) repo = ProxyRepository() assert repo.get_by_domain('intrepidtravel.com') == fake.get_first_return assert repo.create({'domain': 'x'}) == fake.create_return assert repo.update('o1', {'provider': 'brightdata'}) == fake.update_return def test_alert_repository_delegates_correctly(monkeypatch): fake = _FakePbClient() fake.list_return = [{'id': 'a1'}] monkeypatch.setattr('repositories.alert_repository.pb_client', fake) repo = AlertRepository() assert repo.create({'alert_type': 'price_change'}) == fake.create_return assert repo.list_unread('t1') == fake.list_return assert repo.list_recent('t1') == fake.list_return assert repo.mark_read('a1') == fake.update_return def test_battlecard_repository_upsert_creates_when_absent(monkeypatch): fake = _FakePbClient() fake.get_first_return = None monkeypatch.setattr('repositories.battlecard_repository.pb_client', fake) repo = BattlecardRepository() assert repo.get_for_competitor('c1') is None result = repo.upsert('c1', {'content': 'x'}) assert result == fake.create_return assert fake.calls[-1][0] == 'create' def test_battlecard_repository_upsert_updates_when_present(monkeypatch): fake = _FakePbClient() fake.get_first_return = {'id': 'b1', 'competitor_id': 'c1'} monkeypatch.setattr('repositories.battlecard_repository.pb_client', fake) repo = BattlecardRepository() result = repo.upsert('c1', {'content': 'updated'}) assert result == fake.update_return assert fake.calls[-1][0] == 'update' assert repo.list_for_tenant('t1') == fake.list_return def test_comparable_repository_delegates_correctly(monkeypatch): fake = _FakePbClient() fake.list_return = [{'id': 'm1'}] monkeypatch.setattr('repositories.comparable_repository.pb_client', fake) repo = ComparableRepository() assert repo.create({'similarity_score': 0.8}) == fake.create_return assert repo.update('m1', {'similarity_score': 0.9}) == fake.update_return assert repo.get_by_client_and_competitor_product('t1', 'Inca Trail', 'p1') == fake.get_first_return assert repo.list_for_tenant('t1') == fake.list_return assert repo.dismiss('m1') == fake.update_return def test_client_trips_repository_delegates_correctly(monkeypatch): fake = _FakePbClient() fake.list_return = [{'id': 'ct1'}] monkeypatch.setattr('repositories.client_trips_repository.pb_client', fake) repo = ClientTripsRepository() assert repo.create({'trip_name': 'Inca Trail'}) == fake.create_return assert repo.update('ct1', {'destination': 'Peru'}) == fake.update_return assert repo.get_by_tenant_and_name('t1', 'Inca Trail') == fake.get_first_return assert repo.list_for_tenant('t1') == fake.list_return def test_brief_repository_get_weekly_data_aggregates_collections(monkeypatch): fake = _FakePbClient() fake.get_one_return = {'email': 'pm@gadventures.com', 'name': 'G Adventures'} fake.list_return = [{'id': 'x'}] monkeypatch.setattr('repositories.brief_repository.pb_client', fake) repo = BriefRepository() data = repo.get_weekly_data('t1') assert data['admin_email'] == 'pm@gadventures.com' assert data['tenant_name'] == 'G Adventures' assert data['price_changes'] == [{'id': 'x'}] assert data['new_products'] == [{'id': 'x'}] assert data['battlecard_updates'] == [{'id': 'x'}] log = repo.log_digest('t1', 'weekly', recipient_email='pm@gadventures.com') assert log == fake.create_return def test_monitoring_repository_delegates_correctly(monkeypatch): fake = _FakePbClient() monkeypatch.setattr('repositories.monitoring_repository.pb_client', fake) repo = MonitoringRepository() result = repo.log_event('queue_depth', 'warning', value=6, threshold=5, message='busy', alert_sent=True) assert result == fake.create_return assert fake.calls[0][1] == 'monitoring_events' def test_price_history_repository_delegates_correctly(monkeypatch): fake = _FakePbClient() fake.list_return = [{'id': 'ph1'}] monkeypatch.setattr('repositories.price_history_repository.pb_client', fake) repo = PriceHistoryRepository() assert repo.create({'majority_price_usd': 2190}) == fake.create_return assert repo.list_for_product('p1') == fake.list_return assert fake.calls[-1][1] == 'price_history'