import json from pathlib import Path from typing import Any from unittest import mock import pytest import redis from anydi import Container from confluent_kafka import Producer from fansifter_common.adapters.db import Database from app.config import Settings from app.connectors.aws.s3 import S3Client from app.connectors.db.repositories.account_to_fan_response_email_address_mapping import ( AccountToFanResponseEmailAddressMappingRepository, ) from app.connectors.ows_preference_center import OwsPreferenceCenterClient from app.connectors.sendgrid import SendgridClient from app.handlers import SendgridWebhooksReplyHandler, SendgridWebhooksUnsubHandler from app.modules import container as global_container from tests.unit.module import TestModule @pytest.fixture(scope="session") def container() -> Container: global_container.register_module(TestModule) return global_container @pytest.fixture(scope="session") def settings(container: Container) -> Settings: return container.resolve(Settings) @pytest.fixture(scope="function") def s3_client_mock() -> mock.MagicMock: return mock.MagicMock(spec=S3Client) @pytest.fixture(scope="function") def kafka_producer_mock() -> mock.MagicMock: return mock.MagicMock(spec=Producer) @pytest.fixture(scope="function") def db_mock() -> mock.MagicMock: return mock.MagicMock(spec=Database) @pytest.fixture(scope="function") def repository_mock() -> mock.MagicMock: return mock.MagicMock(spec=AccountToFanResponseEmailAddressMappingRepository) @pytest.fixture(scope="function") def sendgrid_client_mock() -> mock.MagicMock: return mock.MagicMock(spec=SendgridClient) @pytest.fixture(scope="function") def redis_client_mock() -> mock.MagicMock: redis_client = mock.MagicMock(spec=redis.Redis) redis_client.incr.return_value = 1 return redis_client @pytest.fixture(scope="function") def ows_preference_center_client_mock() -> mock.MagicMock: return mock.MagicMock(spec=OwsPreferenceCenterClient) @pytest.fixture(scope="session") def test_failed_events_s3_bucket(settings: Settings) -> str: return settings.failed_events_s3_bucket @pytest.fixture(scope="function") def test_unsub_handler( kafka_producer_mock: mock.MagicMock, s3_client_mock: mock.MagicMock, test_failed_events_s3_bucket: str, settings: Settings, ows_preference_center_client_mock: mock.MagicMock, ) -> SendgridWebhooksUnsubHandler: return SendgridWebhooksUnsubHandler( kafka_producer=kafka_producer_mock, kafka_sendgrid_inbound_topic=settings.kafka_sendgrid_inbound_topic, s3_client=s3_client_mock, failed_events_s3_bucket=test_failed_events_s3_bucket, ows_preference_center=ows_preference_center_client_mock, ) @pytest.fixture(scope="function") def test_reply_handler( kafka_producer_mock: mock.MagicMock, s3_client_mock: mock.MagicMock, db_mock: mock.MagicMock, repository_mock: mock.MagicMock, sendgrid_client_mock: mock.MagicMock, redis_client_mock: mock.MagicMock, test_failed_events_s3_bucket: str, settings: Settings, ) -> SendgridWebhooksReplyHandler: return SendgridWebhooksReplyHandler( kafka_producer=kafka_producer_mock, kafka_sendgrid_reply_topic=settings.kafka_sendgrid_reply_topic, db=db_mock, repository=repository_mock, sendgrid_client=sendgrid_client_mock, redis_client=redis_client_mock, cache_key_template=settings.reply_redis_cache_key_template, requests_count_limit=settings.reply_requests_count_limit, requests_count_reset_seconds=settings.reply_requests_count_reset_seconds, s3_client=s3_client_mock, failed_events_s3_bucket=test_failed_events_s3_bucket, default_forward_email=settings.default_forward_email, from_email_template=settings.from_email_template, accounts_to_forward_on_qa_env=settings.accounts_to_forward_on_qa_env, env=settings.environment, ) @pytest.fixture(scope="session") def test_data_dir() -> Path: return Path(__file__).parent / "data" @pytest.fixture(scope="session") def test_event(test_data_dir: Path) -> Any: return json.loads((test_data_dir / "event.json").read_text()) @pytest.fixture(scope="session") def test_event_v2_campaign(test_data_dir: Path) -> Any: return json.loads((test_data_dir / "event_v2_campaign.json").read_text()) @pytest.fixture(scope="session") def test_event_v2_automated(test_data_dir: Path) -> Any: return json.loads((test_data_dir / "event_v2_automated.json").read_text()) @pytest.fixture(scope="session") def test_event_display_name(test_data_dir: Path) -> Any: return json.loads((test_data_dir / "event_display_name.json").read_text()) @pytest.fixture(scope="session") def test_event_v2_campaign_recipient_display_name(test_data_dir: Path) -> Any: return json.loads( (test_data_dir / "event_v2_campaign_recipient_display_name.json").read_text() ) @pytest.fixture(scope="session") def test_reply_event(test_data_dir: Path) -> Any: return json.loads((test_data_dir / "reply_event.json").read_text()) @pytest.fixture(scope="session") def test_reply_event_recipient_display_name(test_data_dir: Path) -> Any: return json.loads( (test_data_dir / "reply_event_recipient_display_name.json").read_text() ) @pytest.fixture(scope="session") def test_reply_event_with_html(test_data_dir: Path) -> Any: return json.loads((test_data_dir / "reply_event_with_html.json").read_text()) @pytest.fixture(scope="session") def test_reply_event_invalid_signature(test_data_dir: Path) -> Any: return json.loads( (test_data_dir / "reply_event_invalid_signature.json").read_text() ) @pytest.fixture(scope="session") def test_reply_event_latin1(test_data_dir: Path) -> Any: return json.loads((test_data_dir / "reply_event_latin1.json").read_text())