from __future__ import annotations from types import SimpleNamespace import unittest from sqlalchemy import create_engine from sqlalchemy.orm import Session from govoplan_access.backend.db.models import Account, Group, User from govoplan_core.auth import ApiPrincipal from govoplan_core.core.access import PrincipalRef from govoplan_core.core.change_sequence import ChangeSequenceEntry from govoplan_core.core.events import EventObjectRef, EventTenantRef, PlatformEvent from govoplan_core.core.search import ( SearchAuthorizationRequest, SearchBackfillRequest, SearchResourceReference, ) from govoplan_core.db.base import Base from govoplan_files.backend.db.models import FileAsset, FileFolder, FileShare from govoplan_files.backend.search_source import ( FilesSearchSource, PROVIDER_ID, ) class FilesSearchSourceTests(unittest.TestCase): def setUp(self) -> None: self.engine = create_engine("sqlite://") Base.metadata.create_all( self.engine, tables=( Account.__table__, User.__table__, Group.__table__, FileAsset.__table__, FileFolder.__table__, FileShare.__table__, ChangeSequenceEntry.__table__, ), ) self.session = Session(self.engine) self.session.add_all( ( Account( id="account-1", email="one@example.test", normalized_email="one@example.test", ), User( id="user-1", tenant_id="tenant-1", account_id="account-1", email="one@example.test", ), FileAsset( id="file-1", tenant_id="tenant-1", owner_type="user", owner_user_id="user-1", display_path="records/permit.pdf", filename="permit.pdf", description="Monthly permit evidence", ), FileAsset( id="file-other", tenant_id="tenant-2", owner_type="user", display_path="other.pdf", filename="other.pdf", ), ) ) self.session.commit() self.source = FilesSearchSource() def tearDown(self) -> None: self.session.close() self.engine.dispose() def test_backfill_and_authorization_are_tenant_bounded(self) -> None: page = self.source.backfill( self.session, request=SearchBackfillRequest( tenant_id="tenant-1", provider_id=PROVIDER_ID, resource_type="file", rebuild_id="rebuild-1", ), ) self.assertEqual(("file-1",), tuple(doc.resource_id for doc in page.documents)) reference = SearchResourceReference( tenant_id="tenant-1", module_id="files", resource_type="file", resource_id="file-1", ) request = SearchAuthorizationRequest(reference=reference, source_revision="1") self.assertTrue( self.source.authorize( self.session, _principal({"files:file:read"}), requests=(request,), )[reference.key] ) self.assertFalse( self.source.authorize( self.session, _principal(set()), requests=(request,), )[reference.key] ) def test_committed_file_event_produces_authoritative_upsert(self) -> None: event = PlatformEvent( type="files.file.updated", module_id="files", tenant=EventTenantRef(id="tenant-1"), resource=EventObjectRef(type="file", id="file-1"), ) changes = self.source.index_changes_for_event( self.session, event=event, delivery_key="delivery-1", ) self.assertEqual(1, len(changes)) self.assertEqual("upsert", changes[0].kind) self.assertEqual(event.event_id, changes[0].cursor) def _principal(scopes: set[str]) -> ApiPrincipal: return ApiPrincipal( principal=PrincipalRef( account_id="account-1", membership_id="user-1", tenant_id="tenant-1", scopes=frozenset(scopes), ), account=SimpleNamespace(id="account-1"), user=SimpleNamespace(id="user-1"), ) if __name__ == "__main__": unittest.main()