"""Unit tests for streams utility functions.""" import datetime import pytest from analytics.constants.streams import STREAMS_SOS_COLUMNS from analytics.utils import streams as streams_util class TestGetStreamsForStore(object): """Test Get Streams for Store.""" def test_get_streams_for_store(self): """Test if result matches expected result.""" streams = [ { "date": datetime.date(2018, 10, 15), "streams": 1, "store_id": 286, "skips": 1, "streams_with_skips": 1, "saves": 1, }, { "date": datetime.date(2018, 10, 15), "streams": 2, "store_id": 1, "skips": None, "streams_with_skips": 0, "saves": None, }, { "date": datetime.date(2018, 10, 16), "streams": 2, "store_id": 1, "skips": 2, "streams_with_skips": 2, "saves": 2, }, { "date": datetime.date(2018, 10, 20), "streams": 40, "store_id": 286, "skips": 20, "streams_with_skips": 20, "saves": 10, }, ] result = streams_util.get_streams_for_store( streams, 1, datetime.date(2018, 10, 15), datetime.date(2018, 10, 21) ) expected = [ { "date": "2018-10-15", "streams": 2, "streams_with_skips": 0, "skips": None, "skip_rate": None, "saves": None, }, { "date": "2018-10-16", "streams": 2, "streams_with_skips": 2, "skips": 2, "skip_rate": 0.5, "saves": 2, }, { "date": "2018-10-17", "streams": 0, "streams_with_skips": 0, "skips": None, "skip_rate": None, "saves": None, }, { "date": "2018-10-18", "streams": 0, "streams_with_skips": 0, "skips": None, "skip_rate": None, "saves": None, }, { "date": "2018-10-19", "streams": 0, "streams_with_skips": 0, "skips": None, "skip_rate": None, "saves": None, }, { "date": "2018-10-20", "streams": 0, "streams_with_skips": 0, "skips": None, "skip_rate": None, "saves": None, }, { "date": "2018-10-21", "streams": 0, "streams_with_skips": 0, "skips": None, "skip_rate": None, "saves": None, }, ] assert result == expected class TestGetEmptyStreamsForPeriod(object): """Test Get Empty Streams for Period.""" def test_get_empty_streams_for_period(self): """Test if result matches expected result.""" result = streams_util.get_empty_streams_for_period( datetime.date(2018, 10, 15), datetime.date(2018, 10, 16) ) expected = [ { "date": "2018-10-15", "streams": 0, "streams_with_skips": 0, "skips": None, "skip_rate": None, "saves": None, }, { "date": "2018-10-16", "streams": 0, "streams_with_skips": 0, "skips": None, "skip_rate": None, "saves": None, }, ] assert result == expected class TestCalcSkipRate(object): """Test Calc Skip Rate.""" def test_calc_date_skip_rate(self): """Test if result matches expected result.""" result = streams_util.calc_date_skip_rate( { "date": datetime.date(2018, 10, 16), "streams": 4, "store_id": 1, "skips": 2, "streams_with_skips": 2, "saves": 2, } ) assert result == 0.5 class TestStreamsByStore(object): """Test get_streams_by_store.""" def test_get_streams_by_store(self): """Test if result matches expected result.""" streams = [ { "date": datetime.date(2018, 10, 15), "streams": 2, "store_id": 1, "skips": None, "streams_with_skips": 0, "saves": None, }, { "date": datetime.date(2018, 10, 16), "streams": 2, "store_id": 1, "skips": 2, "streams_with_skips": 2, "saves": 2, }, ] result = streams_util.get_streams_by_store( streams, datetime.date(2018, 10, 15), datetime.date(2018, 10, 16) ) expected = [ { "id": 1, "name": "Apple Music", "items": [ { "date": "2018-10-15", "streams": 2, "streams_with_skips": 0, "skips": None, "skip_rate": None, "saves": None, }, { "date": "2018-10-16", "streams": 2, "streams_with_skips": 2, "skips": 2, "skip_rate": 0.5, "saves": 2, }, ], } ] assert result == expected def test_get_streams_by_store_all_time(self): """Test if result matches expected result.""" streams = [ { "date": datetime.date(2018, 10, 15), "streams": 2, "store_id": 1, "skips": None, "streams_with_skips": 0, "saves": None, }, { "date": datetime.date(2018, 10, 16), "streams": 2, "store_id": 1, "skips": 2, "streams_with_skips": 2, "saves": 2, }, ] result = streams_util.get_streams_by_store( streams, "ALL_TIME", datetime.date(2018, 10, 16) ) expected = [ { "id": 1, "name": "Apple Music", "items": [ { "date": "2018-10-15", "streams": 2, "streams_with_skips": 0, "skips": None, "skip_rate": None, "saves": None, }, { "date": "2018-10-16", "streams": 2, "streams_with_skips": 2, "skips": 2, "skip_rate": 0.5, "saves": 2, }, ], } ] assert result == expected class TestCheckStoreIdsForSos(object): """Test check_store_ids_for_sos""" def test_check_store_ids_for_sos(self): """Test if result matches expected result.""" store_ids = ["286", "1"] result = streams_util.check_store_ids_for_sos(store_ids) expected = ["286", "1"] assert result == expected def test_check_store_ids_for_sos_error(self): """Test if result matches expected result.""" store_ids = ["789"] with pytest.raises(ValueError) as exc: streams_util.check_store_ids_for_sos(store_ids) assert ( str(exc.value) == "extended SOS only supported for Amazon (187), Apple (1), Spotify (286) and Youtube (453)" ) class TestGetStreamsSosColumns(object): """Test get_streams_sos_columns""" def test_get_streams_sos_columns(self): """Test if result matches expected result.""" store_ids = ["286"] result = streams_util.get_streams_sos_columns(store_ids) expected = [ "streams_sos_spotify_collection", "streams_sos_spotify_playqueue", "streams_sos_spotify_albumpage", "streams_sos_spotify_artistpage", "streams_sos_spotify_search", "streams_sos_spotify_playlists", "streams_sos_spotify_releaseradar", "streams_sos_spotify_discoverweekly", "streams_sos_spotify_radio", "streams_sos_spotify_dailymix", "streams_sos_spotify_chart", "streams_sos_spotify_other", ] assert result == expected def test_check_store_ids_for_sos_store_not_supported(self): """Test if result matches expected result.""" store_ids = ["789"] with pytest.raises(KeyError) as exc: streams_util.get_streams_sos_columns(store_ids) def test_get_streams_sos_columns_empty_store_ids(self): """Test that empty store_ids returns all SOS columns.""" result = streams_util.get_streams_sos_columns([]) assert result == STREAMS_SOS_COLUMNS class TestCleanUpDatesFromLag(object): """Test clean_up_dates_from_lag""" def test_clean_up_dates_with_lag_dimension_sos(self): """Test missing date gets added to show missing data.""" timeseries_to_update = [ {"date": "2025-11-14", "value": 19202}, {"date": "2025-11-15", "value": 18813}, {"date": "2025-11-16", "value": 16524}, {"date": "2025-11-17", "value": 16654}, ] dates_with_no_data_to_add = {"2025-11-18"} query_params = {"dimension": "SOS", "store_ids": [453]} missing_dates_by_store = [{"date": "2025-11-18", "id": 453}] result = streams_util.clean_up_dates_from_lag( timeseries_to_update, None, dates_with_no_data_to_add, query_params, missing_dates_by_store, ) expected = [ {"date": "2025-11-14", "value": 19202}, {"date": "2025-11-15", "value": 18813}, {"date": "2025-11-16", "value": 16524}, {"date": "2025-11-17", "value": 16654}, {"date": "2025-11-18", "value": 0, "has_missing_data": True}, ] assert result == expected def test_clean_up_dates_with_no_lag_dimension_sos(self): """Test missing date gets added to show no missing data.""" timeseries_to_update = [ {"date": "2025-11-14", "value": 19202}, {"date": "2025-11-15", "value": 18813}, {"date": "2025-11-16", "value": 16524}, {"date": "2025-11-17", "value": 16654}, ] dates_with_no_data_to_add = {"2025-11-18"} query_params = {"dimension": "SOS", "store_ids": [453]} missing_dates_by_store = [] result = streams_util.clean_up_dates_from_lag( timeseries_to_update, None, dates_with_no_data_to_add, query_params, missing_dates_by_store, ) expected = [ {"date": "2025-11-14", "value": 19202}, {"date": "2025-11-15", "value": 18813}, {"date": "2025-11-16", "value": 16524}, {"date": "2025-11-17", "value": 16654}, {"date": "2025-11-18", "value": 0, "has_missing_data": False}, ] assert result == expected def test_clean_up_dates_with_lag_dimension_store(self): """Test missing date gets added to show missing data.""" timeseries_to_update = [ {"date": "2025-11-14", "value": 19202}, {"date": "2025-11-15", "value": 18813}, {"date": "2025-11-16", "value": 16524}, {"date": "2025-11-17", "value": 16654}, ] dates_with_no_data_to_add = {"2025-11-18"} query_params = {"dimension": "STORE", "store_ids": [453]} missing_dates_by_store = [{"date": "2025-11-18", "id": 453}] result = streams_util.clean_up_dates_from_lag( timeseries_to_update, "Youtube", dates_with_no_data_to_add, query_params, missing_dates_by_store, ) expected = [ {"date": "2025-11-14", "value": 19202}, {"date": "2025-11-15", "value": 18813}, {"date": "2025-11-16", "value": 16524}, {"date": "2025-11-17", "value": 16654}, {"date": "2025-11-18", "value": 0, "has_missing_data": True}, ] assert result == expected def test_clean_up_dates_with_no_lag_dimension_store(self): """Test missing date gets added to show no missing data.""" timeseries_to_update = [ {"date": "2025-11-14", "value": 19202}, {"date": "2025-11-15", "value": 18813}, {"date": "2025-11-16", "value": 16524}, {"date": "2025-11-17", "value": 16654}, ] dates_with_no_data_to_add = {"2025-11-18"} query_params = {"dimension": "STORE", "store_ids": [453]} missing_dates_by_store = [] result = streams_util.clean_up_dates_from_lag( timeseries_to_update, "Youtube", dates_with_no_data_to_add, query_params, missing_dates_by_store, ) expected = [ {"date": "2025-11-14", "value": 19202}, {"date": "2025-11-15", "value": 18813}, {"date": "2025-11-16", "value": 16524}, {"date": "2025-11-17", "value": 16654}, {"date": "2025-11-18", "value": 0, "has_missing_data": False}, ] assert result == expected