"""Unit tests for the ows_notifications util module.""" import json import time from unittest.mock import MagicMock from ddtrace import tracer as ddtracer from owsrequest import request import pytest import requests from activity_detector import base_config from activity_detector.utils import ows_notifications, sentry DEFAULT_ERROR = {'code': 'code', 'message': 'ERROR'} JSON_EMPTY_EXCEPTION = json.decoder.JSONDecodeError('Expecting value', '', 0) @pytest.mark.parametrize( ('mock_response_code'), [ (200), (201), (409) ] ) def test_create_trending_track_notification(monkeypatch, mock_response_code): """Test creating a trending track notification.""" ows_notifications_response = MagicMock( return_value=requests.models.Response()) ows_notifications_response.status_code = mock_response_code monkeypatch.setattr(ddtracer, 'enabled', False) monkeypatch.setattr( request, 'process', MagicMock(return_value=ows_notifications_response)) result = ows_notifications.create_trending_track_notification( '2019-06-15', 'USA', 'spotify', 100, 1000, 123, 'xyz', 987, 654) request.process.assert_called_with( application='swf-activity-detector', environment=base_config.ENVIRONMENT, method='post', service_name='ows-notifications', path='/activity/trending_track', json={ 'date': '2019-06-15', 'region': 'USA', 'dsp': 'spotify', 'percent_diff': 100, 'day_streams': 1000, 'track': { 'id': 123, 'isrc': 'xyz', 'vendor_id': 987, 'subaccount_id': 654 } }) assert result @pytest.mark.parametrize( ( 'mock_response_code', 'error_body', 'error_exception', 'expected_sleep_calls' ), [ (500, DEFAULT_ERROR, None, 0), (429, DEFAULT_ERROR, None, 5), (404, '', JSON_EMPTY_EXCEPTION, 0) ] ) def test_create_trending_track_notification_error( monkeypatch, mock_response_code, error_body, error_exception, expected_sleep_calls): """Test creating trending track error notification.""" ows_notifications_response = MagicMock( return_value=requests.models.Response()) ows_notifications_response.status_code = mock_response_code ows_notifications_response.json.side_effect = error_exception ows_notifications_response.json.return_value = error_body monkeypatch.setattr(ddtracer, 'enabled', False) monkeypatch.setattr( request, 'process', MagicMock(return_value=ows_notifications_response)) monkeypatch.setattr( sentry, 'send_response_to_sentry', MagicMock()) monkeypatch.setattr( time, 'sleep', MagicMock()) result = ows_notifications.create_trending_track_notification( '2019-06-15', 'USA', 'spotify', 100, 1000, 123, 'xyz', 987, 654) assert request.process.call_count == 6 assert time.sleep.call_count == expected_sleep_calls assert sentry.send_response_to_sentry.called assert not result @pytest.mark.parametrize( ('mock_response_code'), [ (200), (201), (409) ] ) def test_create_playlist_placement_notification( monkeypatch, mock_response_code): """Test creating playlist placement notification.""" ows_notifications_response = MagicMock( return_value=requests.models.Response()) ows_notifications_response.status_code = mock_response_code monkeypatch.setattr(ddtracer, 'enabled', False) monkeypatch.setattr( request, 'process', MagicMock(return_value=ows_notifications_response)) result = ows_notifications.create_playlist_placement_notification( '2019-06-15 10:15:35', 'Songs About Turtles', 'abcd', 'spotify', 286, 999, 'USMP1234', [{'track_id': 123, 'vendor_id': 12345, 'subaccount_id': 6789}] ) request.process.assert_called_with( application='swf-activity-detector', environment=base_config.ENVIRONMENT, method='post', service_name='ows-notifications', path='/activity/playlist_placement', json={ 'timestamp': '2019-06-15 10:15:35', 'playlist': { 'id': 'abcd', 'name': 'Songs About Turtles', 'rank': 999, 'dsp': 'spotify', 'store_id': 286 }, 'sound_recording': { 'isrc': 'USMP1234', 'tracks': [ { 'id': 123, 'vendor_id': 12345, 'subaccount_id': 6789 } ] } } ) assert result result = ows_notifications.create_playlist_placement_notification( '2019-06-15 10:15:35', 'Songs About Turtles', 'abcd', 'spotify', 286, 999, 'USMP1234', [{'track_id': 123, 'vendor_id': 12345}] ) request.process.assert_called_with( application='swf-activity-detector', environment=base_config.ENVIRONMENT, method='post', service_name='ows-notifications', path='/activity/playlist_placement', json={ 'timestamp': '2019-06-15 10:15:35', 'playlist': { 'id': 'abcd', 'name': 'Songs About Turtles', 'rank': 999, 'dsp': 'spotify', 'store_id': 286 }, 'sound_recording': { 'isrc': 'USMP1234', 'tracks': [ { 'id': 123, 'vendor_id': 12345, 'subaccount_id': None } ] } } ) assert result @pytest.mark.parametrize( ( 'mock_response_code', 'error_body', 'error_exception', 'expected_sleep_calls' ), [ (500, DEFAULT_ERROR, None, 0), (429, DEFAULT_ERROR, None, 5), (404, '', JSON_EMPTY_EXCEPTION, 0) ] ) def test_create_playlist_placement_notification_error( monkeypatch, mock_response_code, error_body, error_exception, expected_sleep_calls): """Test create playlist placement notification error response.""" ows_notifications_response = MagicMock( return_value=requests.models.Response()) ows_notifications_response.status_code = mock_response_code ows_notifications_response.json.side_effect = error_exception ows_notifications_response.json.return_value = error_body monkeypatch.setattr(ddtracer, 'enabled', False) monkeypatch.setattr( request, 'process', MagicMock(return_value=ows_notifications_response)) monkeypatch.setattr( sentry, 'send_response_to_sentry', MagicMock()) monkeypatch.setattr( time, 'sleep', MagicMock()) result = ows_notifications.create_playlist_placement_notification( '2019-06-15 10:15:35', 'Songs About Turtles', 'abcd', 'spotify', 286, 999, 'USMP1234', [{'track_id': 123, 'vendor_id': 12345}] ) assert request.process.call_count == 6 assert time.sleep.call_count == expected_sleep_calls assert sentry.send_response_to_sentry.called assert not result @pytest.mark.parametrize( ('mock_response_code'), [ (200), (201), (409) ] ) def test_create_social_spike_notification(monkeypatch, mock_response_code): """Test creating a social spike notification.""" ows_notifications_response = MagicMock( return_value=requests.models.Response()) ows_notifications_response.status_code = mock_response_code monkeypatch.setattr(ddtracer, 'enabled', False) monkeypatch.setattr( request, 'process', MagicMock(return_value=ows_notifications_response)) result = ows_notifications.create_social_spike_notification( '2019-06-15', 'instagram', 100, 12345 ) request.process.assert_called_with( application='swf-activity-detector', environment=base_config.ENVIRONMENT, method='post', service_name='ows-notifications', path='/activity/social_spike', json={ 'date': '2019-06-15', 'network': 'instagram', 'new_followers': 100, 'chartmetric_id': 12345 }) assert result @pytest.mark.parametrize( ( 'mock_response_code', 'error_body', 'error_exception', 'expected_sleep_calls' ), [ (500, DEFAULT_ERROR, None, 0), (429, DEFAULT_ERROR, None, 5), (404, '', JSON_EMPTY_EXCEPTION, 0) ] ) def test_create_social_spike_notification_error( monkeypatch, mock_response_code, error_body, error_exception, expected_sleep_calls): """Test creating social spike notification error response.""" ows_notifications_response = MagicMock( return_value=requests.models.Response()) ows_notifications_response.status_code = mock_response_code ows_notifications_response.json.side_effect = error_exception ows_notifications_response.json.return_value = error_body monkeypatch.setattr(ddtracer, 'enabled', False) monkeypatch.setattr( request, 'process', MagicMock(return_value=ows_notifications_response)) monkeypatch.setattr( sentry, 'send_response_to_sentry', MagicMock()) monkeypatch.setattr( time, 'sleep', MagicMock()) result = ows_notifications.create_social_spike_notification( '2019-06-15', 'instagram', 100, 12345 ) assert request.process.call_count == 6 assert time.sleep.call_count == expected_sleep_calls assert sentry.send_response_to_sentry.called assert not result def test_create_notification(monkeypatch): """Test creating a notification.""" ows_notifications_response = MagicMock( return_value=requests.models.Response()) ows_notifications_response.status_code = 201 monkeypatch.setattr( request, 'process', MagicMock(return_value=ows_notifications_response)) notification = { 'feed_name': 'label_analytics_digest', 'feed_id': 'vendor_123', 'payload': {} } result = ows_notifications.create_notification(notification) request.process.assert_called_with( application='swf-activity-detector', environment=base_config.ENVIRONMENT, method='post', service_name='ows-notifications', path='/activity', json=notification) assert result def test_create_notification_error(monkeypatch): """Test creating a notification when an error response is returned.""" monkeypatch.setattr(time, 'sleep', MagicMock()) monkeypatch.setattr(ddtracer, 'enabled', False) ows_notifications_response = MagicMock( return_value=requests.models.Response()) ows_notifications_response.status_code = 500 ows_notifications_response.json.return_value = { 'code': 'code', 'message': 'ERROR'} monkeypatch.setattr( request, 'process', MagicMock(return_value=ows_notifications_response)) monkeypatch.setattr( sentry, 'send_response_to_sentry', MagicMock()) notification = { 'feed_name': 'label_analytics_digest', 'feed_id': 'vendor_123', 'payload': {} } result = ows_notifications.create_notification(notification) request.process.assert_called_with( application='swf-activity-detector', environment=base_config.ENVIRONMENT, method='post', service_name='ows-notifications', path='/activity', json=notification) assert request.process.call_count == 6 assert sentry.send_response_to_sentry.called assert result