"""Unit tests for sound recording streams_all logic layer.""" import datetime from unittest.mock import patch import pytest from analytics.api import app from analytics.logic.streams import get_streams_all MOCK_STORE_IDS = [1, 286] @pytest.fixture(autouse=True) def mock_context(): """Mock successful context.""" with app.test_request_context(): yield @pytest.fixture(autouse=True) def no_cache(): """Mock out caching of response.""" with patch("analytics.connectors.redis.client.get") as get: get.return_value = None yield get @pytest.fixture(autouse=True) def mock_store_availability(mocker): """Mock store_availability.""" mocker.patch( "analytics.logic.streams.store_availability.get_store_ids", return_value=MOCK_STORE_IDS, ) mocker.patch( "analytics.logic.streams.store_availability.get_store_names", return_value={1: "Apple Music", 286: "Spotify"}, ) @pytest.fixture def permissions(): """Return permissions with label access.""" return { "permission_label_ids": [7123], "permission_artist_ids": None, "permission_subaccount_ids": None, "permission_label_participant_ids": None, "permission_feed_ids": [1, 2], } @pytest.fixture def subaccount_permissions(): """Return permissions with subaccount access.""" return { "permission_label_ids": None, "permission_artist_ids": None, "permission_subaccount_ids": [345], "permission_label_participant_ids": None, "permission_feed_ids": [1, 2], } @pytest.fixture def mock_streams_all_query_result(): """Mock query result for streams all (simulates SQLAlchemy Row objects).""" return [ { "date": datetime.date(2018, 6, 28), "streams": 500, "streams_with_skips": 0, "skips": None, "saves": None, }, { "date": datetime.date(2018, 6, 29), "streams": 2000, "streams_with_skips": 1000, "skips": 200, "saves": 400, }, ] @pytest.fixture def expected_payload_streams_all(): """Return expected payload from get_streams_all logic.""" return { "isrc": "isrc", "items": [ { "streams": 500, "saves": None, "skip_rate": None, "date": "2018-06-28T00:00:00Z", }, { "streams": 2000, "saves": 400, "skip_rate": 0.16666666666666666, "date": "2018-06-29T00:00:00Z", }, ], } class TestGetStreamsAllWithSubaccount: """Test get_streams_all with Subaccount.""" isrc = "isrc" start_date = datetime.date(2018, 6, 28) end_date = datetime.date(2018, 6, 29) def _query_params(self, countries=None): return { "isrc": self.isrc, "distributors": ["theorchard", "sme", "awal"], "country_ids": countries or [], "store_ids": [], "start_date": self.start_date, "end_date": self.end_date, } def test_get_streams_all_success( self, mocker, subaccount_permissions, mock_streams_all_query_result, expected_payload_streams_all, ): """Test successful response.""" mocker.patch( "analytics.logic.streams.StreamsAll.execute", return_value=mock_streams_all_query_result, ) response = get_streams_all( self._query_params(countries=["GB", "US"]), subaccount_permissions, ) assert response.status == 200 assert response.message == expected_payload_streams_all def test_get_streams_all_failure(self, mocker, subaccount_permissions): """Test failure response when query returns empty.""" mocker.patch( "analytics.logic.streams.StreamsAll.execute", return_value=[], ) response = get_streams_all( self._query_params(countries=["GB", "US"]), subaccount_permissions, ) assert response.status == 200 assert response.message == {"isrc": self.isrc, "items": []} class TestGetStreamsAllWithLabel: """Test get_streams_all with Label.""" isrc = "isrc" start_date = datetime.date(2018, 6, 28) end_date = datetime.date(2018, 6, 29) def _query_params(self): return { "isrc": self.isrc, "distributors": ["theorchard", "sme", "awal"], "country_ids": [], "store_ids": [], "start_date": self.start_date, "end_date": self.end_date, } def test_get_streams_all_success( self, mocker, permissions, mock_streams_all_query_result, expected_payload_streams_all, ): """Test successful response.""" mocker.patch( "analytics.logic.streams.StreamsAll.execute", return_value=mock_streams_all_query_result, ) response = get_streams_all( self._query_params(), permissions, ) assert response.status == 200 assert response.message == expected_payload_streams_all def test_get_streams_all_failure(self, mocker, permissions): """Test failure response when query returns empty.""" mocker.patch( "analytics.logic.streams.StreamsAll.execute", return_value=[], ) response = get_streams_all( self._query_params(), permissions, ) assert response.status == 200 assert response.message == {"isrc": self.isrc, "items": []} class TestGetStreamsAllHistoricalOwnershipFlag: """Verify the flag is threaded into the StreamsAll jinjasql query input.""" isrc = "isrc" start_date = datetime.date(2018, 6, 28) end_date = datetime.date(2018, 6, 29) def _query_params(self): return { "isrc": self.isrc, "distributors": ["theorchard"], "country_ids": [], "store_ids": [], "start_date": self.start_date, "end_date": self.end_date, } def _permissions(self): return { "permission_label_ids": [7123], "permission_artist_ids": None, "permission_subaccount_ids": None, "permission_label_participant_ids": None, "permission_feed_ids": [1, 2], } def test_flag_off_by_default(self, mocker, mock_streams_all_query_result): mock_query = mocker.patch("analytics.logic.streams.StreamsAll") mock_query.return_value.execute.return_value = mock_streams_all_query_result get_streams_all(self._query_params(), self._permissions()) (query_input,), _ = mock_query.call_args assert query_input["transfer_product_ownership_enabled"] is False def test_flag_threaded_when_enabled( self, mocker, mock_streams_all_query_result, ): mock_query = mocker.patch("analytics.logic.streams.StreamsAll") mock_query.return_value.execute.return_value = mock_streams_all_query_result params = {**self._query_params(), "transfer_product_ownership_enabled": True} get_streams_all(params, self._permissions()) (query_input,), _ = mock_query.call_args assert query_input["transfer_product_ownership_enabled"] is True