from collections.abc import AsyncIterator from datetime import timedelta from typing import Any from unittest import mock import pytest from audience_common import datetimeutc from audience_common.auth.account import AccountAccess from campaigns.auth.dtos import User, UserId from campaigns.connectors.db import Database from campaigns.connectors.facebook.enums import InstagramMediaProductType from campaigns.connectors.facebook.models import ( InstagramBusinessAccountWithId, InstagramMedia, PagePost, ) from campaigns.meta.dtos import CampaignPost from campaigns.meta.handlers import GetCampaignPostsHandler, GetCampaignPostsRequest from campaigns.meta.models import Campaign from campaigns.meta.services import CampaignService, FacebookPageTokenService from tests.unit.types import BuildModel, CreateModel @pytest.fixture def handler( db: Database, facebook_client_mock: mock.MagicMock, campaign_service: CampaignService, facebook_page_token_service: FacebookPageTokenService, ) -> GetCampaignPostsHandler: return GetCampaignPostsHandler( db=db, facebook_client=facebook_client_mock, campaign_service=campaign_service, facebook_page_token_service=facebook_page_token_service, ) async def test_get_campaign_posts( handler: GetCampaignPostsHandler, build_model: BuildModel, create_model: CreateModel, facebook_client_mock: mock.MagicMock, user_id: UserId, ) -> None: campaign = await create_model(Campaign) facebook_post = build_model( PagePost, is_eligible_for_promotion=True, created_time=datetimeutc.now() - timedelta(seconds=75), ) facebook_post_not_eligible = build_model(PagePost, is_eligible_for_promotion=False) instagram_account = build_model(InstagramBusinessAccountWithId) instagram_feed = build_model( InstagramMedia, media_product_type=InstagramMediaProductType.FEED, timestamp=datetimeutc.now() - timedelta(seconds=100), ) instagram_story = build_model( InstagramMedia, media_product_type=InstagramMediaProductType.STORY, timestamp=datetimeutc.now() - timedelta(seconds=50), ) facebook_client_mock.get_published_posts_for_page.return_value = [ facebook_post, facebook_post_not_eligible, ] facebook_client_mock.get_instagram_business_account_for_page.return_value = ( instagram_account ) async def _instagram_media( *args: Any, **kwargs: Any ) -> AsyncIterator[InstagramMedia]: yield instagram_feed facebook_client_mock.get_instagram_media.side_effect = _instagram_media async def _instagram_stories( *args: Any, **kwargs: Any ) -> AsyncIterator[InstagramMedia]: yield instagram_story facebook_client_mock.get_instagram_stories.side_effect = _instagram_stories result = await handler.handle( GetCampaignPostsRequest( user=User( id=user_id, account_access=AccountAccess(accounts=[campaign.account]), ), campaign_id=campaign.id, ), ) assert result == [ CampaignPost.from_api_obj(instagram_story), CampaignPost.from_api_obj(facebook_post), CampaignPost.from_api_obj(instagram_feed), ] async def test_get_campaign_posts_instagram_not_connected( handler: GetCampaignPostsHandler, build_model: BuildModel, create_model: CreateModel, facebook_client_mock: mock.MagicMock, user_id: UserId, ) -> None: campaign = await create_model(Campaign) facebook_post = build_model(PagePost, is_eligible_for_promotion=True) facebook_client_mock.get_published_posts_for_page.return_value = [ facebook_post, ] facebook_client_mock.get_instagram_business_account_for_page.return_value = None result = await handler.handle( GetCampaignPostsRequest( user=User( id=user_id, account_access=AccountAccess(accounts=[campaign.account]), ), campaign_id=campaign.id, ), ) assert result == [ CampaignPost.from_api_obj(facebook_post), ]