import uuid import pytest from sqlalchemy.ext.asyncio import AsyncSession from src.infrastructure.postgres.repositories import ingestion_jobs as jobs_repo from src.infrastructure.postgres.repositories import source_files as source_files_repo from tests.support.factories import create_tenant pytestmark = [ pytest.mark.integration, pytest.mark.postgres, pytest.mark.asyncio(loop_scope="session"), ] async def test_source_files_get_by_id_is_tenant_scoped(db_session: AsyncSession) -> None: owner = await create_tenant(db_session) other = await create_tenant(db_session) source_file_id = uuid.uuid4() source_files_repo.create( db_session, source_file_id=source_file_id, tenant_id=owner.id, domain="general", source_filename="report.csv", source_type="csv", content_sha256="a" * 64, byte_size=10, storage_uri="tenants/x/source-files/y/original", created_by_api_key_id=None, ) await db_session.commit() found_for_owner = await source_files_repo.get_by_id( db_session, tenant_id=owner.id, source_file_id=source_file_id ) found_for_other = await source_files_repo.get_by_id( db_session, tenant_id=other.id, source_file_id=source_file_id ) assert found_for_owner is not None assert found_for_other is None async def test_source_files_find_active_by_content_hash_matches_tenant_domain_hash( db_session: AsyncSession, ) -> None: tenant = await create_tenant(db_session) source_files_repo.create( db_session, source_file_id=uuid.uuid4(), tenant_id=tenant.id, domain="general", source_filename="report.csv", source_type="csv", content_sha256="b" * 64, byte_size=10, storage_uri="tenants/x/source-files/y/original", created_by_api_key_id=None, ) await db_session.commit() found = await source_files_repo.find_active_by_content_hash( db_session, tenant_id=tenant.id, domain="general", content_sha256="b" * 64 ) not_found_other_domain = await source_files_repo.find_active_by_content_hash( db_session, tenant_id=tenant.id, domain="other", content_sha256="b" * 64 ) assert found is not None assert not_found_other_domain is None async def test_ingestion_jobs_mark_terminal_rejects_non_running_job( db_session: AsyncSession, ) -> None: """A job already in a terminal state must not be re-marked (ADR-0017).""" tenant = await create_tenant(db_session) source_file_id = uuid.uuid4() source_files_repo.create( db_session, source_file_id=source_file_id, tenant_id=tenant.id, domain="general", source_filename="report.csv", source_type="csv", content_sha256="c" * 64, byte_size=10, storage_uri="tenants/x/source-files/y/original", created_by_api_key_id=None, ) await db_session.flush() job = jobs_repo.create_running( db_session, tenant_id=tenant.id, source_file_id=source_file_id, requested_by_api_key_id=None, chunking_strategy="fixed_size", ) await db_session.commit() first = await jobs_repo.mark_terminal( db_session, tenant_id=tenant.id, ingestion_job_id=job.id, status="succeeded" ) await db_session.commit() second = await jobs_repo.mark_terminal( db_session, tenant_id=tenant.id, ingestion_job_id=job.id, status="failed" ) assert first is not None assert first.status == "succeeded" assert second is None