import datetime from collections.abc import Callable from typing import Any from unittest import mock import pytest from anydi import Container from dirty_equals import IsDatetime from faker import Faker from fansifter_common.utils import timezone from freezegun import freeze_time from dmp.adapters.aws.s3 import S3Client from dmp.adapters.meta.models import AccessToken, DebugToken, User, UserAdAccount from dmp.config import Settings from dmp.meta.handlers import ConnectMetaUserHandler, ConnectMetaUserRequest from dmp.meta.models import MetaUserConnection from dmp.meta.repositories import MetaUserConnectionRepository from tests.unit.faker import FakerTyped from tests.unit.types import BuildModel, CreateModel MockUserAdAccounts = Callable[[list[UserAdAccount]], None] class TestConnectMetaUserHandler: @pytest.fixture(autouse=True) def mock_valid_debug_token( self, facebook_client_mock: mock.MagicMock, settings: Settings ) -> None: facebook_client_mock.debug_token.return_value = DebugToken( is_valid=True, scopes=settings.meta_user_required_scopes ) @pytest.fixture(autouse=True) def mocked_api_token( self, facebook_client_mock: mock.MagicMock, build_model: BuildModel ) -> AccessToken: api_token = build_model(AccessToken, expires_in=None) facebook_client_mock.get_oauth_access_token.return_value = api_token return api_token @pytest.fixture def mocked_api_user( self, facebook_client_mock: mock.MagicMock, build_model: BuildModel ) -> User: api_user = build_model(User) facebook_client_mock.get_user.return_value = api_user return api_user @pytest.fixture def handler_request( self, identity_id: str, mocked_api_user: User, fake: FakerTyped ) -> ConnectMetaUserRequest: return ConnectMetaUserRequest( identity_id=identity_id, user_id=mocked_api_user.id, access_token=fake.plain_token(), ) @pytest.fixture def mock_user_ad_accounts( self, facebook_client_mock: mock.MagicMock, ) -> MockUserAdAccounts: def fixture(api_ad_accounts: list[UserAdAccount]) -> None: def _get_user_pages(*args: Any, **kwargs: Any) -> list[UserAdAccount]: # noqa: ARG001 return api_ad_accounts facebook_client_mock.get_user_ad_accounts.side_effect = _get_user_pages return fixture @pytest.mark.db def test_connect_new_user( self, container: Container, handler: ConnectMetaUserHandler, handler_request: ConnectMetaUserRequest, user_connection_repository: MetaUserConnectionRepository, build_model: BuildModel, mocked_api_user: User, mock_user_ad_accounts: MockUserAdAccounts, faker: Faker, ) -> None: custom_audience_tos_accepted = True api_ad_account = build_model( UserAdAccount, user_tasks=["MANAGE"], tos_accepted={"custom_audience_tos": custom_audience_tos_accepted}, ) mock_user_ad_accounts([api_ad_account]) s3_client_mock = mock.MagicMock(spec=S3Client) s3_client_mock.put_object_from_url.return_value = faker.url() with container.override(S3Client, s3_client_mock): user_connection_result = handler.handle(handler_request) assert user_connection_result.is_connected assert user_connection_result.ad_accounts assert user_connection_result.ad_accounts[0].external_id == api_ad_account.id assert user_connection_result.ad_accounts[0].name == api_ad_account.name assert ( user_connection_result.ad_accounts[0].business_account_name == api_ad_account.business_account_name ) assert ( user_connection_result.ad_accounts[0].custom_audience_tos_accepted == custom_audience_tos_accepted ) user_connection = user_connection_repository.first() assert user_connection assert user_connection.is_valid assert user_connection.user_id == mocked_api_user.id assert user_connection.user_name == mocked_api_user.name assert user_connection.identity_id == handler_request.identity_id assert user_connection.ad_accounts assert user_connection.ad_accounts[0].external_id == api_ad_account.id @freeze_time("2022-07-20") @pytest.mark.db def test_connect_existing_user( self, handler: ConnectMetaUserHandler, handler_request: ConnectMetaUserRequest, user_connection_repository: MetaUserConnectionRepository, mock_user_ad_accounts: MockUserAdAccounts, mocked_api_user: User, create_model: CreateModel, fake: FakerTyped, ) -> None: create_model( MetaUserConnection, identity_id=handler_request.identity_id, user_id=fake.pystr(), user_name=mocked_api_user.name, updated_at=timezone.now() - datetime.timedelta(days=3), ) mock_user_ad_accounts([]) user_connection_result = handler.handle(handler_request) assert user_connection_result.is_connected assert user_connection_result.ad_accounts_count == 0 assert user_connection_result.user assert user_connection_result.user.id == mocked_api_user.id user_connection = user_connection_repository.first() assert user_connection assert user_connection.updated_at == IsDatetime(approx=timezone.now()) assert not user_connection.ad_accounts assert user_connection.user_id == mocked_api_user.id