"""Conftest file for all tests.""" from unittest.mock import patch import pytest from flexmock import flexmock from owsrequest.constants import headers as owsrequest_headers from owsrequest.context import RequestContext from requests.structures import CaseInsensitiveDict from analytics import config from analytics.logic import permissions VENDOR_GRASS_ACCOUNT_ID = "7123" VENDOR_GRASS_ACCOUNT_TYPE = "vendor" SUBACCOUNT_GRASS_ACCOUNT_ID = "21989" SUBACCOUNT_W_VIDEO_GRASS_ACCOUNT_ID = "22947" SUBACCOUNT_GRASS_ACCOUNT_TYPE = "subaccount" ORCHARD_USER_ID = "alw:66059" ORCHARD_SUBACCOUNT_USER_ID = "alw:41007" ORCHARD_SUBACCOUNT_W_VIDEO_USER_ID = "alw:41879" ORCHARD_PROFILE_ID = "19" ORCHARD_PROFILE_TYPE = "ArtistProfile" ORCHARD_INSIGHTS_PROFILE_ID = "36135" ORCHARD_INSIGHTS_PROFILE_TYPE = "InsightsProfile" ORCHARD_INSIGHTS_EMPLOYEE_PROFILE_ID = "154" ORCHARD_INSIGHTS_EMPLOYEE_PROFILE_TYPE = "InsightsProfile" @pytest.fixture def mock_dev_auth(monkeypatch): """Ignore DEV_AUTH env vars while running unit tests.""" monkeypatch.setattr(config, "DEV_AUTH", None) @pytest.fixture def mock_dev_profile_auth(monkeypatch): """Ignore DEV_PROFILE_AUTH env vars while running unit tests.""" monkeypatch.setattr(config, "DEV_PROFILE_AUTH", None) @pytest.fixture def request_headers(mock_dev_auth, mock_dev_profile_auth): """Mock headers for request.""" return { owsrequest_headers.GRASS_ACCOUNT_ID: VENDOR_GRASS_ACCOUNT_ID, owsrequest_headers.GRASS_ACCOUNT_TYPE: VENDOR_GRASS_ACCOUNT_TYPE, owsrequest_headers.ORCHARD_USER_ID: ORCHARD_USER_ID, owsrequest_headers.ORCHARD_PROFILE_TYPE: None, owsrequest_headers.ORCHARD_PROFILE_ID: None, } @pytest.fixture def insights_request_headers(mock_dev_auth, mock_dev_profile_auth): """Mock headers for request.""" return { owsrequest_headers.ORCHARD_PROFILE_ID: ORCHARD_INSIGHTS_PROFILE_ID, owsrequest_headers.ORCHARD_PROFILE_TYPE: ORCHARD_INSIGHTS_PROFILE_TYPE, } @pytest.fixture def insights_employee_request_headers(mock_dev_auth, mock_dev_profile_auth): """Mock headers for request.""" return { owsrequest_headers.ORCHARD_PROFILE_ID: ORCHARD_INSIGHTS_EMPLOYEE_PROFILE_ID, owsrequest_headers.ORCHARD_PROFILE_TYPE: ORCHARD_INSIGHTS_EMPLOYEE_PROFILE_TYPE, } @pytest.fixture def artist_profiles_request_headers(mock_dev_auth, mock_dev_profile_auth): """Mock headers for request.""" return { owsrequest_headers.GRASS_ACCOUNT_ID: None, owsrequest_headers.GRASS_ACCOUNT_TYPE: None, owsrequest_headers.ORCHARD_USER_ID: None, owsrequest_headers.ORCHARD_PROFILE_TYPE: ORCHARD_PROFILE_TYPE, owsrequest_headers.ORCHARD_PROFILE_ID: ORCHARD_PROFILE_ID, } @pytest.fixture def subaccount_request_headers(mock_dev_auth, mock_dev_profile_auth): """Mock subaccount headers for request.""" return { owsrequest_headers.GRASS_ACCOUNT_ID: SUBACCOUNT_GRASS_ACCOUNT_ID, owsrequest_headers.GRASS_ACCOUNT_TYPE: SUBACCOUNT_GRASS_ACCOUNT_TYPE, owsrequest_headers.ORCHARD_USER_ID: ORCHARD_SUBACCOUNT_USER_ID, owsrequest_headers.ORCHARD_PROFILE_TYPE: None, owsrequest_headers.ORCHARD_PROFILE_ID: None, } @pytest.fixture def subaccount_w_video_request_headers(mock_dev_auth, mock_dev_profile_auth): """Mock subaccount with video access headers for request.""" return { owsrequest_headers.GRASS_ACCOUNT_ID: SUBACCOUNT_W_VIDEO_GRASS_ACCOUNT_ID, owsrequest_headers.GRASS_ACCOUNT_TYPE: SUBACCOUNT_GRASS_ACCOUNT_TYPE, owsrequest_headers.ORCHARD_USER_ID: ORCHARD_SUBACCOUNT_W_VIDEO_USER_ID, owsrequest_headers.ORCHARD_PROFILE_TYPE: None, owsrequest_headers.ORCHARD_PROFILE_ID: None, } @pytest.fixture def account_kwargs_for_label(mock_dev_auth, mock_dev_profile_auth): """Yield a dict with account_type and account_id for a label.""" yield { "account_type": "vendor", "account_id": "7123", "user_id": "alw:1000", "profile_type": None, "profile_id": None, } @pytest.fixture def account_kwargs_for_subaccount(mock_dev_auth, mock_dev_profile_auth): """Yield a dict with account_type and account_id for a label.""" yield { "account_type": "subaccount", "account_id": "456789", "user_id": "alw:1000", "profile_type": None, "profile_id": None, } @pytest.fixture def request_context_for_label(): """Mock request context for a label.""" return RequestContext( CaseInsensitiveDict( { "Grass-Account-Type": "vendor", "Grass-Account-Id": 7123, "Orchard-User-Id": "alw:1000", } ) ) @pytest.fixture def request_context_for_subaccount(): """Mock request context for a subaccount.""" return RequestContext( CaseInsensitiveDict( { "Grass-Account-Type": "subaccount", "Grass-Account-Id": 456789, "Orchard-User-Id": "alw:1000", } ) ) @pytest.fixture def request_context_for_artist(): """Mock request context for an artist.""" return RequestContext( CaseInsensitiveDict( { "Orchard-Profile-Id": 123, "Orchard-Profile-Type": "ArtistProfile", "Orchard-Identity-Id": "abc123", } ) ) @pytest.fixture def permissions_for_label(): """Mock permissions for a label.""" return { "label_ids": [7123], "subaccount_ids": None, "artist_ids": None, "label_participant_ids": None, "feed_ids": [1, 2], } @pytest.fixture def permissions_for_subaccount(): """Mock permissions for a subaccount.""" return { "label_ids": [7123], "subaccount_ids": [456789], "artist_ids": None, "label_participant_ids": None, "feed_ids": [1, 2], } @pytest.fixture def permissions_for_artist(): """Mock permissions for an artist.""" return { "label_ids": None, "subaccount_ids": None, "artist_ids": [917636, 1552280], "label_participant_ids": [474422, 1015359], "feed_ids": [1, 2], } @pytest.fixture def mock_permissions_for_label(request_context_for_label, permissions_for_label): """Perform mocking for returning permissions for a label.""" flexmock(permissions).should_receive("get_permissions_filter").with_args( request_context_for_label ).and_return(permissions_for_label) @pytest.fixture def mock_permissions_for_label_video_endpoint( request_context_for_label, permissions_for_label ): """Perform mocking for returning permissions for a label.""" flexmock(permissions).should_receive("get_permissions_filter").with_args( request_context_for_label, video_endpoint=True ).and_return(permissions_for_label) @pytest.fixture def mock_permissions_for_label_without_feed_ids( request_context_for_label, permissions_for_label ): """Perform mocking for returning permissions for a label.""" flexmock(permissions).should_receive("get_permissions_filter").with_args( request_context_for_label, filter_by_feed_ids=False ).and_return(permissions_for_label) @pytest.fixture def mock_permissions_for_subaccount( request_context_for_subaccount, permissions_for_subaccount ): """Perform mocking for returning permissions for a subaccount.""" flexmock(permissions).should_receive("get_permissions_filter").with_args( request_context_for_subaccount ).and_return(permissions_for_subaccount) @pytest.fixture def mock_permissions_for_subaccount_video_endpoint( request_context_for_subaccount, permissions_for_subaccount ): """Perform mocking for returning permissions for a subaccount.""" flexmock(permissions).should_receive("get_permissions_filter").with_args( request_context_for_subaccount, video_endpoint=True ).and_return(permissions_for_subaccount) @pytest.fixture def mock_permissions_for_subaccount_without_feed_ids( request_context_for_subaccount, permissions_for_subaccount ): """Perform mocking for returning permissions for a subaccount.""" flexmock(permissions).should_receive("get_permissions_filter").with_args( request_context_for_subaccount, filter_by_feed_ids=False ).and_return(permissions_for_subaccount) @pytest.fixture def mock_permissions_for_artist(request_context_for_artist, permissions_for_artist): """Perform mocking for returning permissions for an artist.""" flexmock(permissions).should_receive("get_permissions_filter").with_args( request_context_for_artist ).and_return(permissions_for_artist) @pytest.fixture def mock_permissions_for_artist_video_endpoint( request_context_for_artist, permissions_for_artist ): """Perform mocking for returning permissions for an artist.""" flexmock(permissions).should_receive("get_permissions_filter").with_args( request_context_for_artist, video_endpoint=True ).and_return(permissions_for_artist) @pytest.fixture def mock_permissions_for_artist_without_feed_ids( request_context_for_artist, permissions_for_artist ): """Perform mocking for returning permissions for an artist.""" flexmock(permissions).should_receive("get_permissions_filter").with_args( request_context_for_artist, filter_by_feed_ids=False ).and_return(permissions_for_artist) @pytest.fixture(autouse=True) def mock_feed_ids_pemissions(): """Mock FEED_IDS.""" with patch("analytics.logic.permissions.FEED_IDS", [1, 2, 38]): yield @pytest.fixture(autouse=True) def mock_feed_ids_data_availability(): """Mock FEED_IDS.""" with patch("analytics.config.FEED_IDS", [1, 2]): yield @pytest.fixture(autouse=True) def mock_get_max_available_date(): """Mock data_availability.get_max_available_date.""" with patch( "analytics.utils.data_availability.get_max_available_date" ) as get_max_available_date: get_max_available_date.return_value = "2019-01-01" yield get_max_available_date @pytest.fixture(autouse=True) def mock_get_available_feeds(): """Mock data_availability.get_available_feeds.""" with patch( "analytics.utils.data_availability.get_available_feeds" ) as get_available_feeds: get_available_feeds.return_value = config.FEEDS yield get_available_feeds @pytest.fixture(autouse=True) def mock_is_insights_transfer_product_ownership_enabled(): """Stub the transfer_product_ownership SplitIO flag at every handler import site. Logic functions read the flag via query_params; handlers are the only callers that evaluate the SplitIO check. Tests opt into the True path via patch.object(mock, 'return_value').""" from contextlib import ExitStack targets = [ "analytics.features.is_insights_transfer_product_ownership_enabled", "analytics.account_handlers.is_insights_transfer_product_ownership_enabled", "analytics.handlers.is_insights_transfer_product_ownership_enabled", "analytics.participant_handlers.is_insights_transfer_product_ownership_enabled", "analytics.product_handlers.is_insights_transfer_product_ownership_enabled", "analytics.sound_recording_handlers.is_insights_transfer_product_ownership_enabled", "analytics.tiktok_handlers.is_insights_transfer_product_ownership_enabled", ] with ExitStack() as stack: mocks = [stack.enter_context(patch(t, return_value=False)) for t in targets] yield mocks @pytest.fixture(autouse=True) def mock_is_insights_line_soundcloud_collection_as_active_enabled(): """Stub the insights_line_soundcloud_collection_as_active SplitIO flag (IN-17362) at every handler import site that threads it. Logic functions read the flag via query_params; handlers are the only callers that evaluate the SplitIO check. Defaults to False (SOS reclassification off); tests opt into the True path via patch.object(mock, 'return_value').""" from contextlib import ExitStack targets = [ "analytics.features.is_insights_line_soundcloud_collection_as_active_enabled", "analytics.account_handlers.is_insights_line_soundcloud_collection_as_active_enabled", "analytics.handlers.is_insights_line_soundcloud_collection_as_active_enabled", "analytics.participant_handlers.is_insights_line_soundcloud_collection_as_active_enabled", "analytics.product_handlers.is_insights_line_soundcloud_collection_as_active_enabled", "analytics.sound_recording_handlers.is_insights_line_soundcloud_collection_as_active_enabled", ] with ExitStack() as stack: mocks = [stack.enter_context(patch(t, return_value=False)) for t in targets] yield mocks @pytest.fixture(autouse=True) def mock_is_insights_published_max_available_date_enabled(): """Stub the insights_published_max_available_date SplitIO flag (GO-4885) at every import site: the handlers that thread it into query_params and the data_availability util that picks the max-available-date SQL file. Defaults to False (read the original availability view/table); tests opt into the True path via patch.object(mock, 'return_value').""" from contextlib import ExitStack targets = [ "analytics.features.is_insights_published_max_available_date_enabled", "analytics.account_handlers.is_insights_published_max_available_date_enabled", "analytics.handlers.is_insights_published_max_available_date_enabled", "analytics.participant_handlers.is_insights_published_max_available_date_enabled", "analytics.product_handlers.is_insights_published_max_available_date_enabled", "analytics.utils.data_availability.is_insights_published_max_available_date_enabled", ] with ExitStack() as stack: mocks = [stack.enter_context(patch(t, return_value=False)) for t in targets] yield mocks