"""Unit tests for the streams breakdown logic layer.""" import datetime from unittest.mock import patch import pytest from oto import response as oto_response from sound_recordings.api import app from sound_recordings.logic import demographics @pytest.fixture def mock_get_demographics_model_payload(): """Mock payload for streams breakdown model.""" return { "_17": 5214236, "_18_22": 18016044, "_23_27": 11165474, "_28_34": 5969109, "_35_44": 2942418, "_45_59": 1606414, "_60_": 436636, "UA": 77677, "M": 8273548, "F": 34247706, "UG": 2906754, } @pytest.fixture def mock_get_demographics_model_payload_zero_streams(): """Mock payload for streams breakdown model.""" return { "_17": 0, "_18_22": 0, "_23_27": 0, "_28_34": 0, "_35_44": 0, "_45_59": 0, "_60_": 0, "UA": 0, "M": 0, "F": 0, "UG": 0, } @pytest.fixture def expected_payload(): """Return expected payload from logic.""" return { "isrc": "TEST", "demographics": { "age": { "_17": 5214236, "_18_22": 18016044, "_23_27": 11165474, "_28_34": 5969109, "_35_44": 2942418, "_45_59": 1606414, "_60_": 436636, "UA": 77677, }, "gender": {"M": 8273548, "F": 34247706, "UG": 2906754}, }, "sources": [{"id": 286, "name": "Spotify"}, {"id": 1, "name": "Apple Music"}], } @pytest.fixture def expected_payload_zero_streams(): """Return expected payload from logic.""" return { "isrc": "TEST", "demographics": { "age": { "_17": 0, "_18_22": 0, "_23_27": 0, "_28_34": 0, "_35_44": 0, "_45_59": 0, "_60_": 0, "UA": 0, }, "gender": {"M": 0, "F": 0, "UG": 0}, }, "sources": [{"id": 286, "name": "Spotify"}, {"id": 1, "name": "Apple Music"}], } @pytest.fixture def mock_add_outage_error_to_stores(): """Mock add_outage_error_to_stores.""" with patch( "sound_recordings.logic.demographics.add_outage_error_to_stores" ) as add_outage_error_to_stores: add_outage_error_to_stores.return_value = [ {"id": 286, "name": "Spotify"}, {"id": 1, "name": "Apple Music"}, ] yield add_outage_error_to_stores @pytest.fixture def mock_get_demographics_success( mock_get_demographics_model_payload, mock_add_outage_error_to_stores ): """Mock successful get_demographics model response.""" with patch( "sound_recordings.models.demographics.get_demographics" ) as get_demographics: get_demographics.return_value = oto_response.Response( mock_get_demographics_model_payload ) with app.test_request_context(): yield get_demographics @pytest.fixture def mock_get_demographics_success_zero_streams( mock_get_demographics_model_payload_zero_streams, mock_add_outage_error_to_stores ): """Mock successful get_demographics response with zero streams.""" with patch( "sound_recordings.models.demographics.get_demographics" ) as get_demographics: get_demographics.return_value = oto_response.Response( mock_get_demographics_model_payload_zero_streams ) with app.test_request_context(): yield get_demographics @pytest.fixture def mock_get_demographics_failure(mock_add_outage_error_to_stores): """Mock failure demographics model response.""" with patch( "sound_recordings.models.demographics.get_demographics" ) as get_demographics: get_demographics.return_value = oto_response.Response(None) with app.test_request_context(): yield get_demographics @pytest.fixture def mock_store_availability(): """Mock store_availability.""" with patch( "sound_recordings.models.demographics.store_availability" ) as store_availability: store_availability.get_sources.return_value = [ {"id": 286, "name": "Spotify"}, {"id": 1, "name": "Apple Music"}, ] yield store_availability @pytest.fixture def mock_get_max_available_date_success(): """Mock successful get_max_available_date model response.""" with patch( "sound_recordings.models.data_availability.get_max_available_date" ) as get_max_available_date: get_max_available_date.return_value = "2018-07-06" yield get_max_available_date @pytest.fixture def get_demographics_response( mock_add_outage_error_to_stores, mock_get_max_available_date_success, request_context_for_label, mock_permissions_for_label, ): """Return response from get_demographics.""" return demographics.get_demographics( request_context_for_label, "TEST", [], [], None, None, ["theorchard"] ) @pytest.fixture def get_demographics_response_with_start_and_end_date( mock_add_outage_error_to_stores, request_context_for_label, mock_permissions_for_label, ): """Return response from get_demographics.""" return demographics.get_demographics( request_context_for_label, "TEST", [], [], "2019-11-01", "2019-12-01", ["theorchard"], ) @pytest.fixture def get_demographics_response_with_countries( mock_add_outage_error_to_stores, mock_get_max_available_date_success, request_context_for_label, mock_permissions_for_label, ): """Return response from get_demographics.""" return demographics.get_demographics( request_context_for_label, "TEST", ["DE", "NO", "US"], [], datetime.date(2018, 7, 6) - datetime.timedelta(days=28 - 1), datetime.date(2018, 7, 6), ["theorchard"], ) @pytest.fixture def get_demographics_response_with_store_ids( mock_add_outage_error_to_stores, mock_get_max_available_date_success, request_context_for_label, mock_permissions_for_label, ): """Return response from get_demographics.""" return demographics.get_demographics( request_context_for_label, "TEST", [], [1], datetime.date(2018, 7, 6) - datetime.timedelta(days=28 - 1), datetime.date(2018, 7, 6), ["theorchard"], ) def test_get_demographics_model_called( mock_get_demographics_success, permissions_for_label, get_demographics_response, mock_add_outage_error_to_stores, ): """Test model layer called from logic.""" mock_get_demographics_success.assert_called_once_with( permissions_for_label, "TEST", [], [], datetime.date(2018, 7, 6) - datetime.timedelta(days=28 - 1), datetime.date(2018, 7, 6), ["theorchard"], ) def test_get_demographics_model_called_with_start_and_end_date( mock_get_demographics_success, permissions_for_label, get_demographics_response_with_start_and_end_date, mock_add_outage_error_to_stores, ): """Test model layer called from logic.""" mock_get_demographics_success.assert_called_once_with( permissions_for_label, "TEST", [], [], "2019-11-01", "2019-12-01", ["theorchard"], ) def test_get_demographics_model_called_with_countries( mock_get_demographics_success, permissions_for_label, get_demographics_response_with_countries, mock_add_outage_error_to_stores, ): """Test model layer called from logic.""" mock_get_demographics_success.assert_called_once_with( permissions_for_label, "TEST", ["DE", "NO", "US"], [], datetime.date(2018, 7, 6) - datetime.timedelta(days=28 - 1), datetime.date(2018, 7, 6), ["theorchard"], ) def test_get_demographics_model_called_with_store_ids( mock_get_demographics_success, permissions_for_label, get_demographics_response_with_store_ids, mock_add_outage_error_to_stores, ): """Test model layer called from logic.""" mock_get_demographics_success.assert_called_once_with( permissions_for_label, "TEST", [], [1], datetime.date(2018, 7, 6) - datetime.timedelta(days=28 - 1), datetime.date(2018, 7, 6), ["theorchard"], ) def test_get_demographics_success( mock_get_demographics_success, expected_payload, get_demographics_response, mock_add_outage_error_to_stores, ): """Test successful response.""" assert get_demographics_response.status == 200 assert get_demographics_response.message == expected_payload def test_get_demographics_success_with_start_and_end_date( mock_get_demographics_success, expected_payload, get_demographics_response_with_start_and_end_date, mock_add_outage_error_to_stores, ): """Test successful response.""" assert get_demographics_response_with_start_and_end_date.status == 200 assert get_demographics_response_with_start_and_end_date.message == expected_payload def test_get_demographics_success_with_countries( mock_get_demographics_success, expected_payload, get_demographics_response_with_countries, mock_add_outage_error_to_stores, ): """Test successful response.""" assert get_demographics_response_with_countries.status == 200 assert get_demographics_response_with_countries.message == expected_payload def test_get_demographics_success_with_store_ids( mock_get_demographics_success, expected_payload, get_demographics_response_with_store_ids, mock_add_outage_error_to_stores, ): """Test successful response.""" assert get_demographics_response_with_store_ids.status == 200 assert get_demographics_response_with_store_ids.message == expected_payload def test_get_demographics_success_zero_streams( mock_get_demographics_success_zero_streams, expected_payload_zero_streams, get_demographics_response, mock_add_outage_error_to_stores, ): """Test successful response.""" assert get_demographics_response.status == 200 assert get_demographics_response.message == expected_payload_zero_streams def test_get_demographics_failure( mock_get_demographics_failure, get_demographics_response, mock_add_outage_error_to_stores, expected_payload, ): """Test get_demographics when model fails.""" assert get_demographics_response.status == 200 expected_payload["demographics"]["gender"] = {} expected_payload["demographics"]["age"] = {} assert get_demographics_response.message == expected_payload def test_get_demographics_failure_with_start_and_end_date( mock_get_demographics_failure, get_demographics_response_with_start_and_end_date, mock_add_outage_error_to_stores, expected_payload, ): """Test get_demographics when model fails.""" assert get_demographics_response_with_start_and_end_date.status == 200 expected_payload["demographics"]["gender"] = {} expected_payload["demographics"]["age"] = {} assert get_demographics_response_with_start_and_end_date.message == expected_payload def test_get_demographics_failure_with_countries( mock_get_demographics_failure, get_demographics_response_with_countries, mock_add_outage_error_to_stores, expected_payload, ): """Test get_demographics when model fails.""" assert get_demographics_response_with_countries.status == 200 expected_payload["demographics"]["gender"] = {} expected_payload["demographics"]["age"] = {} assert get_demographics_response_with_countries.message == expected_payload def test_get_demographics_failure_with_store_ids( mock_get_demographics_failure, get_demographics_response_with_store_ids, mock_add_outage_error_to_stores, expected_payload, ): """Test get_demographics when model fails.""" assert get_demographics_response_with_store_ids.status == 200 expected_payload["demographics"]["gender"] = {} expected_payload["demographics"]["age"] = {} assert get_demographics_response_with_store_ids.message == expected_payload