# Configure application database BEFORE any imports from datetime import datetime from os.path import abspath, dirname, join, pardir from typing import Any, AsyncGenerator, Callable, Coroutine import pytest # Load .env to get INTEGRATION_DB_* values - use same path as application config from environs import Env from jwtauth.testing import ( JwtAuthSecretsManager, SecretLookupInfo, ) from pydantic import UUID4 from product_staging.api.datasources import datasources_lifespan from tests.integration.client import OwsProductStaging from tests.integration.constants import VENDOR_UUID_KITTY_WIZARD from tests.integration.seed import ( create_asset_transfer_job, create_bulk_session_asset_file, create_bulk_session_ingestion, create_bulk_session_ingestion_product, create_bulk_session_metadata_file, create_bulk_session_with_asset_s3_filename, create_bulk_session_with_metadata_json_s3_filename, create_session_with_metadata, ) env_loader = Env() dotenv_path = abspath(join(dirname(__file__), pardir, pardir, ".env")) env_loader.read_env(dotenv_path, recurse=False) pytest_plugins = ["jwtauth.testing.pytest_plugin"] @pytest.fixture(scope="session", autouse=True) def anyio_backend() -> str: """Return AnyIO backend.""" return "asyncio" @pytest.fixture(scope="session", autouse=True) async def init_datasources(anyio_backend: str) -> AsyncGenerator[Any, Any]: """Initialize shared datasources (DATA_SOURCES) for in-process logic calls made by seed helpers.""" async with datasources_lifespan(None): yield @pytest.fixture(scope="session") def jwt( generate_bearer_token: Callable[..., str], jwtauth_secrets_manager: JwtAuthSecretsManager, ) -> str: """ Generate a JWT for integration tests. """ return generate_bearer_token( get_user_creds_args=SecretLookupInfo( environment="qa", service_name="ows-product-staging-integration-test", secret_name="OWS_PRODUCT_STAGING_INTEGRATION_TEST_USER_CREDENTIALS", ), get_auth0_creds_args=SecretLookupInfo( environment="qa", service_name="ows-product-staging-integration-test", secret_name="OWS_PRODUCT_STAGING_INTEGRATION_TEST_APP_AUTH0_CREDENTIALS", ), secrets_manager=jwtauth_secrets_manager, ) @pytest.fixture(scope="session") def subaccount_jwt( generate_bearer_token: Callable[..., str], jwtauth_secrets_manager: JwtAuthSecretsManager, ) -> str: """ Generate a JWT for a subaccount-only user for integration tests. """ return generate_bearer_token( get_user_creds_args=SecretLookupInfo( environment="qa", service_name="ows-product-staging-integration-test", secret_name="OWS_PRODUCT_STAGING_INTEGRATION_TEST_SUBACCOUNT_USER_CREDENTIALS", ), get_auth0_creds_args=SecretLookupInfo( environment="qa", service_name="ows-product-staging-integration-test", secret_name="OWS_PRODUCT_STAGING_INTEGRATION_TEST_APP_AUTH0_CREDENTIALS", ), secrets_manager=jwtauth_secrets_manager, ) @pytest.fixture(scope="session") def content_ccm_digital_audio_bulk_create_jwt( generate_bearer_token: Callable[..., str], jwtauth_secrets_manager: JwtAuthSecretsManager, ) -> str: """ Generate a JWT for employee with content_ccm_digital_audio_can_bulk_create. """ return generate_bearer_token( get_user_creds_args=SecretLookupInfo( environment="qa", service_name="ows-product-staging-integration-test", secret_name="OWS_PRODUCT_STAGING_INTEGRATION_TEST_PP_CONTENT_BULK_CREATE_USER_CREDENTIALS", ), get_auth0_creds_args=SecretLookupInfo( environment="qa", service_name="ows-product-staging-integration-test", secret_name="OWS_PRODUCT_STAGING_INTEGRATION_TEST_APP_AUTH0_CREDENTIALS", ), secrets_manager=jwtauth_secrets_manager, ) @pytest.fixture(scope="session") def content_ccm_digital_audio_bulk_create_subaccount_jwt( generate_bearer_token: Callable[..., str], jwtauth_secrets_manager: JwtAuthSecretsManager, ) -> str: """ Generate a JWT for a subaccount-only user with content_ccm_digital_audio_can_bulk_create role. """ return generate_bearer_token( get_user_creds_args=SecretLookupInfo( environment="qa", service_name="ows-product-staging-integration-test", secret_name="OWS_PRODUCT_STAGING_INTEGRATION_TEST_PP_CONTENT_BULK_CREATE_SUBACCOUNT_USER_CREDENTIALS", ), get_auth0_creds_args=SecretLookupInfo( environment="qa", service_name="ows-product-staging-integration-test", secret_name="OWS_PRODUCT_STAGING_INTEGRATION_TEST_APP_AUTH0_CREDENTIALS", ), secrets_manager=jwtauth_secrets_manager, ) @pytest.fixture(scope="session") def no_access_jwt( generate_bearer_token: Callable[..., str], jwtauth_secrets_manager: JwtAuthSecretsManager, ) -> str: """ Generate a JWT for integration tests. """ return generate_bearer_token( get_user_creds_args=SecretLookupInfo( environment="qa", service_name="ows-product-staging-integration-test", secret_name="OWS_PRODUCT_STAGING_INTEGRATION_TEST_NO_ACCESS_USER_CREDENTIALS", ), get_auth0_creds_args=SecretLookupInfo( environment="qa", service_name="ows-product-staging-integration-test", secret_name="OWS_PRODUCT_STAGING_INTEGRATION_TEST_APP_AUTH0_CREDENTIALS", ), secrets_manager=jwtauth_secrets_manager, ) @pytest.fixture(scope="session") def client(jwt: str) -> OwsProductStaging: return OwsProductStaging(jwt=jwt) @pytest.fixture(scope="session") def subaccount_client(subaccount_jwt: str) -> OwsProductStaging: return OwsProductStaging(jwt=subaccount_jwt) @pytest.fixture(scope="session") def content_ccm_digital_audio_bulk_create_client( content_ccm_digital_audio_bulk_create_jwt: str, ) -> OwsProductStaging: """content_ccm_digital_audio_bulk_create_client can be used to test ows-product-staging. All its requests are authenticated as a user that represents an Employee with content_ccm_digital_audio_can_bulk_create for both parent company tenants """ return OwsProductStaging(jwt=content_ccm_digital_audio_bulk_create_jwt) @pytest.fixture(scope="session") def content_ccm_digital_audio_bulk_create_subaccount_client( content_ccm_digital_audio_bulk_create_subaccount_jwt: str, ) -> OwsProductStaging: """content_ccm_digital_audio_bulk_create_subaccount_client can be used to test ows-product-staging. All its requests are authenticated as a user that has content_ccm_digital_audio_can_bulk_create for a single subaccount tenant """ return OwsProductStaging(jwt=content_ccm_digital_audio_bulk_create_subaccount_jwt) @pytest.fixture(scope="session") def no_access_client( no_access_jwt: str, ) -> OwsProductStaging: """no_access_client can be used to test ows-product-staging. All its requests are authenticated as a user with no access - no PP roles, no profiles. """ return OwsProductStaging(jwt=no_access_jwt) @pytest.fixture(scope="session") def vendor_uuid() -> str: return VENDOR_UUID_KITTY_WIZARD @pytest.fixture(scope="session") def identity_uuid() -> str: # ows-product-staging-integration-test user identity UUID return "ca764155-7bd3-4e6c-a6e6-8369ec3ca553" @pytest.fixture() def seed_bulk_session( init_datasources: None, identity_uuid: str, ) -> Callable[..., Coroutine[None, None, UUID4]]: """Factory fixture to seed a bulk session for a given vendor UUID.""" async def _create(*, vendor_uuid: str, created_on: datetime | None = None) -> UUID4: # Allow overriding the `created_on` timestamp to avoid timestamp collisions # on `resolve_bulk_session_slug` in the integration tests. return await create_session_with_metadata( vendor_uuid, identity_uuid, created_on=created_on ) return _create @pytest.fixture() def seed_asset_transfer_job( init_datasources: None, identity_uuid: str, ) -> Callable[..., Coroutine[None, None, UUID4]]: """Factory fixture to seed an asset transfer job for a given bulk session.""" async def _create(*, bulk_session_id: UUID4) -> UUID4: return await create_asset_transfer_job(bulk_session_id, identity_uuid) return _create @pytest.fixture() def seed_bulk_session_asset_file( init_datasources: None, identity_uuid: str, ) -> Callable[..., Coroutine[None, None, tuple[UUID4, UUID4]]]: """Factory fixture to seed a bulk session with an asset file for a given vendor UUID.""" async def _create(*, vendor_uuid: str) -> tuple[UUID4, UUID4]: return await create_bulk_session_asset_file(vendor_uuid, identity_uuid) return _create @pytest.fixture() def seed_bulk_session_metadata_file( init_datasources: None, identity_uuid: str, ) -> Callable[..., Coroutine[None, None, tuple[UUID4, UUID4]]]: """Factory fixture to seed a bulk session with a metadata file for a given vendor UUID.""" async def _create(*, vendor_uuid: str) -> tuple[UUID4, UUID4]: return await create_bulk_session_metadata_file(vendor_uuid, identity_uuid) return _create @pytest.fixture() def seed_bulk_session_ingestion( init_datasources: None, identity_uuid: str, ) -> Callable[..., Coroutine[None, None, tuple[UUID4, UUID4]]]: """Factory fixture to seed a bulk session with an ingestion record for a given vendor UUID.""" async def _create(*, vendor_uuid: str) -> tuple[UUID4, UUID4]: return await create_bulk_session_ingestion(vendor_uuid, identity_uuid) return _create @pytest.fixture() def seed_bulk_session_ingestion_product( init_datasources: None, identity_uuid: str, ) -> Callable[..., Coroutine[None, None, tuple[UUID4, UUID4, UUID4, str]]]: """Factory fixture to seed a bulk session ingestion product for a given vendor UUID.""" async def _create(*, vendor_uuid: str) -> tuple[UUID4, UUID4, UUID4, str]: return await create_bulk_session_ingestion_product(vendor_uuid, identity_uuid) return _create @pytest.fixture() def seed_bulk_session_for_update_asset( init_datasources: None, identity_uuid: str, ) -> Callable[..., Coroutine[None, None, tuple[UUID4, str]]]: """Factory fixture to seed a bulk session with an asset file for update_asset tests. Returns (bulk_session_id, s3_filename). """ async def _create(*, vendor_uuid: str) -> tuple[UUID4, str]: return await create_bulk_session_with_asset_s3_filename( vendor_uuid, identity_uuid ) return _create @pytest.fixture() def seed_bulk_session_for_metadata_hydration( init_datasources: None, identity_uuid: str, ) -> Callable[..., Coroutine[None, None, tuple[UUID4, str, str]]]: """Factory fixture to seed a bulk session with a finalized metadata JSON file in S3 and a matching ingestion execution row for hydrate_metadata_json tests. Returns (bulk_session_id, json_s3_filename, execution_arn). """ async def _create(*, vendor_uuid: str) -> tuple[UUID4, str, str]: return await create_bulk_session_with_metadata_json_s3_filename( vendor_uuid, identity_uuid ) return _create @pytest.fixture(scope="session", autouse=True) async def bulk_session_ingestion_id( init_datasources: None, # Ensures datasources are initialized before this fixture runs vendor_uuid: str, identity_uuid: str, client: OwsProductStaging, ) -> UUID4: bulk_session_id = await create_session_with_metadata(vendor_uuid, identity_uuid) bulk_session_ingestion_id = client.ingest_bulk_session( bulk_session_id=bulk_session_id, assets_required=False, submit=True ) return bulk_session_ingestion_id