app.bettersight.io/backend/tests/repositories/test_real_repositories.py

207 lines
8.3 KiB
Python

"""
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
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_url('https://intrepidtravel.com') == fake.get_first_return
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
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
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.list_for_tenant('t1') == fake.list_return
assert repo.dismiss('m1') == fake.update_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'