"""Tests for Handlers.""" import datetime import json from unittest.mock import MagicMock from unittest.mock import patch from oto import response from oto import status import pytest from social_analytics import api from social_analytics import handlers from social_analytics.constants import error from social_analytics.constants import header from social_analytics.logic import artist_social_profile from social_analytics.logic import artist_url from social_analytics.logic import collector from social_analytics.logic import metrics from social_analytics.logic import new_social_profile from social_analytics.logic import social_profile from social_analytics.logic import platform from social_analytics.logic import user_interaction @pytest.fixture def fixture_client(): """Create an api test fixture.""" return api.app.test_client() @pytest.fixture def fixture_success(): """Create a success response.""" return response.Response('a-ok') @pytest.fixture def fixture_fatal(): """Create a fatal response.""" return response.create_fatal_response() @pytest.fixture def fixture_empty_body(): """Create an empty body response.""" return response.create_error_response( status.BAD_REQUEST, error.ERROR_MESSAGE_EMPTY_BODY) @pytest.fixture def fixture_bad_params(): """Create an empty body response.""" return response.create_error_response( status.BAD_REQUEST, error.ERROR_MESSAGE_BAD_PARAMS) @pytest.fixture def fixture_missing_grass_headers(): """Create a missing grass headers response.""" return response.create_error_response( status.BAD_REQUEST, error.ERROR_MESSAGE_MISSING_GRASS_HEADERS) @pytest.fixture def fixture_not_found(): """Create a not found response.""" return response.create_not_found_response() @pytest.fixture def fixture_time_series_data(): """Fixture for time series response data.""" return {'items': [ { 'social_profile_id': 5, 'platform_id': 1, 'label_id': 1, 'metric_id': 2, 'metric_value': 3898087.0, 'processed_datetime': '2017-09-22T11:19:12', 'activity_datetime': '2017-09-22T11:19:12', } ]} @pytest.fixture( params=[ '/social-profile/5/platform/1/metric/2?end_date=1506079152', '/social-profile/5/platform/1/metric/2?start_date=1506079152']) def bad_params(request): """Fixture for time series data bad params.""" return request.param @pytest.fixture(params=[ {'search_token': None, 'context': 'test', 'term': 'a'}, {'search_token': 'test', 'context': None, 'term': 'a'}, {'search_token': 'test', 'context': 'test', 'term': None} ]) def search_artists_bad_params(request): """Fixture for search artists bad params.""" return request.param @pytest.fixture def search_artists_params(): """Fixture for search artists params.""" return { 'search_token': '1', 'context': 'test', 'term': 'the' } @pytest.fixture def search_artist_results(): """Fixture for search artists resuts.""" return [ { 'artist_id': 1, 'artist_name': 'Artist 1', 'is_linked': True }, { 'artist_id': 2, 'artist_name': 'Artist 2', 'is_linked': False } ] @patch('social_analytics.handlers.g') def test_exception_handler(mock_g): """Verify exception_Handler returns 500 status code and json payload.""" message = ( 'The server encountered an internal error ' 'and was unable to complete your request.') mock_error = MagicMock() server_response = handlers.exception_handler(mock_error) mock_g.log.exception.assert_called_with(mock_error) # assert status code is 500 assert server_response.status_code == 500 # assert json payload response_message = json.loads(server_response.data.decode()) assert response_message['message'] == message assert response_message['code'] == response.error.ERROR_CODE_INTERNAL_ERROR def test_get_artist_social_profiles( monkeypatch, fixture_client, fixture_success): """Test get artist social profiles.""" monkeypatch.setattr( social_profile, 'get_social_profiles_by_artist_id', MagicMock( return_value=fixture_success )) artist_id = '1' route = '/artist/{artist_id}/social-profiles'.format(artist_id=artist_id) data = { 'artist_id': artist_id, 'social_profile_id': 1, 'label_id': 1 } result = fixture_client.get(route, data=json.dumps(data)) social_profile.get_social_profiles_by_artist_id.assert_called_once_with( artist_id) assert result.status_code == 200 def test_get_artist_social_profiles_not_found( monkeypatch, fixture_client, fixture_not_found): """Test get artist social profiles bad params.""" monkeypatch.setattr( social_profile, 'get_social_profiles_by_artist_id', MagicMock( return_value=fixture_not_found )) artist_id = '10' route = '/artist/{artist_id}/social-profiles'.format(artist_id=artist_id) data = {} result = fixture_client.get(route, data=json.dumps(data)) social_profile.get_social_profiles_by_artist_id.assert_called_once_with( artist_id) assert result.status_code == status.NOT_FOUND def test_get_linked_artists( monkeypatch, fixture_client, fixture_success): """Test get social profiles for a label id.""" monkeypatch.setattr( artist_url, 'get_last_viewed_artists', MagicMock( return_value=fixture_success)) route = '/linked-artists' headers = { header.GRASS_ORCHARD_USER_ID: 'alw:1010', } result = fixture_client.get(route, headers=headers) artist_url.get_last_viewed_artists.assert_called_once_with('alw:1010') assert result.status_code == status.OK def test_get_linked_artists_not_found( monkeypatch, fixture_client, fixture_not_found): """Test get social profiles for a label id not found.""" monkeypatch.setattr( artist_url, 'get_last_viewed_artists', MagicMock( return_value=fixture_not_found)) headers = { header.GRASS_ORCHARD_USER_ID: 'alw:1010', } route = '/linked-artists' data = {} result = fixture_client.get(route, data=json.dumps(data), headers=headers) artist_url.get_last_viewed_artists.assert_called_once_with('alw:1010') assert result.status_code == status.NOT_FOUND def test_get_linked_artists_missing_grass_headers( monkeypatch, fixture_client, fixture_missing_grass_headers): """Test get social profiles for a label id missing grass headers.""" monkeypatch.setattr( artist_social_profile, 'get_linked_artists', MagicMock( return_value=fixture_missing_grass_headers)) route = '/linked-artists' data = {} result = fixture_client.get(route, data=json.dumps(data)) assert result.status_code == status.BAD_REQUEST def test_create_or_update_social_profile( monkeypatch, fixture_client, fixture_success): """Test create or update social profile.""" monkeypatch.setattr( new_social_profile, 'create_or_update_social_profile', MagicMock( return_value=fixture_success )) route = '/social-profile' label_id = 1 data = { 'platform': 'facebook', 'platform_name': 'Taylor Swift', 'platform_id': '987', 'artist_id': 1} headers = { header.GRASS_ACCOUNT_TYPE: header.GRASS_ACCOUNT_TYPE_VENDOR, header.GRASS_ACCOUNT_ID: label_id } result = fixture_client.post(route, data=json.dumps(data), headers=headers) new_social_profile.create_or_update_social_profile.assert_called_once_with( data) assert result.status_code == status.OK def test_create_or_update_social_profile_not_found( monkeypatch, fixture_client, fixture_not_found): """Test create or update social profile not found.""" monkeypatch.setattr( new_social_profile, 'create_or_update_social_profile', MagicMock( return_value=fixture_not_found )) label_id = 1 route = '/social-profile' data = {} headers = { header.GRASS_ACCOUNT_TYPE: header.GRASS_ACCOUNT_TYPE_VENDOR, header.GRASS_ACCOUNT_ID: label_id } result = fixture_client.post(route, data=json.dumps(data), headers=headers) new_social_profile.create_or_update_social_profile.assert_called_once_with( data) assert result.status_code == status.NOT_FOUND def test_get_instagram_user(monkeypatch, fixture_client, fixture_success): """Test get instagram user.""" monkeypatch.setattr( platform, 'get_instagram_user', MagicMock(return_value=fixture_success)) platform_id = '1' route = '/platform/instagram/user/{platform_id}'.format( platform_id=platform_id) result = fixture_client.get(route) platform.get_instagram_user.assert_called_once_with( platform_id) assert result.status_code == status.OK def test_social_profile_suggestions( monkeypatch, fixture_client, fixture_success): """Test recommend social profile suggestions.""" data = { 'platform': 'spotify', 'platform_name': 'Las Grecas'} route = '/social-profile/suggestions' monkeypatch.setattr( collector, 'recommend_profile_for_social_network', MagicMock( return_value=fixture_success )) result = fixture_client.post(route, data=json.dumps(data)) collector.recommend_profile_for_social_network.assert_called_once_with( data) assert result.status_code == status.OK def test_social_profile_suggestions_not_found( monkeypatch, fixture_client, fixture_not_found): """Test recommend social profile suggestions.""" data = { 'platform': 'spotify', 'platform_name': 'Las Grecas'} route = '/social-profile/suggestions' monkeypatch.setattr( collector, 'recommend_profile_for_social_network', MagicMock( return_value=fixture_not_found )) result = fixture_client.post(route, data=json.dumps(data)) collector.recommend_profile_for_social_network.assert_called_once_with( data) assert result.status_code == status.NOT_FOUND def test_get_artist_metrics( monkeypatch, fixture_client, fixture_success): """Test get artist metrics for an artist id.""" monkeypatch.setattr( metrics, 'get_latest_metrics_by_artist_id', MagicMock( return_value=fixture_success)) artist_id = 2 route = '/artist/{artist_id}/latest-metrics'.format(artist_id=artist_id) data = [ { 'social_profile_id': 4, 'artist_id': 3, 'label_id': 3, 'likes': 123 }, { 'social_profile_id': 5, 'artist_id': 3, 'label_id': 3, 'followers': 567 }, { 'social_profile_id': 6, 'artist_id': 3, 'label_id': 3, 'followed_by': 568 } ] result = fixture_client.get(route, data=json.dumps(data)) (metrics.get_latest_metrics_by_artist_id .assert_called_once_with(artist_id)) assert result.status_code == status.OK def test_get_artist_metrics_not_found( monkeypatch, fixture_client, fixture_not_found): """Test get artist metrics no artist id.""" monkeypatch.setattr( metrics, 'get_latest_metrics_by_artist_id', MagicMock( return_value=fixture_not_found)) artist_id = 15 route = '/artist/{artist_id}/latest-metrics'.format(artist_id=artist_id) data = [] result = fixture_client.get(route, data=json.dumps(data)) (metrics.get_latest_metrics_by_artist_id .assert_called_once_with(artist_id)) assert result.status_code == status.NOT_FOUND def test_delete_artist_social_profile( monkeypatch, fixture_client, fixture_success): """Test delete artist social profile.""" monkeypatch.setattr( artist_url, 'delete_social_profile', MagicMock( return_value=fixture_success)) social_profile_id = 2 artist_id = 2 route = ('/social-profile/{social_profile_id}/artist/{artist_id}' .format(social_profile_id=social_profile_id, artist_id=artist_id)) data = [ { 'social_profile_id': 4, 'artist_id': 3, 'label_id': 3 } ] result = fixture_client.delete(route, data=json.dumps(data)) (artist_url.delete_social_profile .assert_called_once_with(social_profile_id, artist_id)) assert result.status_code == status.OK def test_delete_artist_social_profile_not_found( monkeypatch, fixture_client, fixture_not_found): """Test delete artist social profile not found.""" monkeypatch.setattr( artist_url, 'delete_social_profile', MagicMock( return_value=fixture_not_found)) social_profile_id = 15 artist_id = 2 route = ('/social-profile/{social_profile_id}/artist/{artist_id}' .format(social_profile_id=social_profile_id, artist_id=artist_id)) result = fixture_client.delete(route) (artist_url.delete_social_profile .assert_called_once_with(social_profile_id, artist_id)) assert result.status_code == status.NOT_FOUND def test_get_time_series_data_for_platform( monkeypatch, fixture_client, fixture_success, fixture_time_series_data): """Test get time series data for platform.""" monkeypatch.setattr( metrics, 'get_time_series_data_for_period', MagicMock( return_value=fixture_success)) route = ('/social-profile/5/platform/1/metric/2?start_date=1506079151&' 'end_date=1506079152') params = { 'social_profile_id': 5, 'platform_id': 1, 'metric_id': 2, 'start_date': datetime.datetime(2017, 9, 22, 11, 19, 11), 'end_date': datetime.datetime(2017, 9, 22, 11, 19, 12), } result = fixture_client.get( route, data=json.dumps(fixture_time_series_data)) (metrics.get_time_series_data_for_period.assert_called_once_with(params)) assert result.status_code == status.OK def test_get_time_series_data_for_platform_bad_params( fixture_client, bad_params): """Test get time series data for platform.""" route = bad_params data = [] result = fixture_client.get(route, data=json.dumps(data)) assert result.status_code == status.BAD_REQUEST def test_create_user_interaction(monkeypatch, fixture_client, fixture_success): """Test create user interaction.""" monkeypatch.setattr( user_interaction, 'create_user_interaction', MagicMock( return_value=fixture_success )) route = '/social-analytics/user-interaction' data = {'artist_id': '57451', 'user_id': '2'} result = fixture_client.post(route, data=json.dumps(data), headers={ header.GRASS_ORCHARD_USER_ID: '2'}) user_interaction.create_user_interaction.assert_called_once_with( data) assert result.status_code == status.OK def test_create_user_interaction_bad_params(fixture_client): """Test create user interaction.""" route = '/social-analytics/user-interaction' data = { 'artist_id': '57451', 'user_id': '2'} result = fixture_client.post(route, data=json.dumps(data)) assert result.status_code == status.BAD_REQUEST def test_search_artists_bad_params(fixture_client, search_artists_bad_params): """Test search artists bad params.""" route = '/search-artists' data = [] result = fixture_client.get( route, data=json.dumps(data), query_string=search_artists_bad_params) assert result.status_code == status.BAD_REQUEST def test_search_artists_not_found( monkeypatch, fixture_client, fixture_not_found, search_artists_params): """Test search artists not found.""" monkeypatch.setattr( artist_url, 'search_artists', MagicMock( return_value=fixture_not_found)) route = '/search-artists' data = [] headers = { header.GRASS_ACCOUNT_TYPE: header.GRASS_ACCOUNT_TYPE_VENDOR, header.GRASS_ACCOUNT_ID: 2 } result = fixture_client.get( route, data=json.dumps(data), query_string=search_artists_params, headers=headers) assert result.status_code == status.NOT_FOUND def test_search_artists( monkeypatch, fixture_client, fixture_success, search_artists_params, search_artist_results): """Test search artists.""" monkeypatch.setattr( artist_url, 'search_artists', MagicMock( return_value=fixture_success)) route = '/search-artists' data = search_artist_results headers = { header.GRASS_ACCOUNT_TYPE: header.GRASS_ACCOUNT_TYPE_VENDOR, header.GRASS_ACCOUNT_ID: 2 } result = fixture_client.get( route, data=json.dumps(data), query_string=search_artists_params, headers=headers) assert result.status_code == status.OK def test_get_last_viewed_artists(monkeypatch, fixture_client, fixture_success): """Test get last viewed artists.""" monkeypatch.setattr( artist_url, 'get_last_viewed_artists', MagicMock( return_value=fixture_success)) route = '/last-viewed-artists' headers = { header.GRASS_ORCHARD_USER_ID: 'alw:1010', } result = fixture_client.get(route, headers=headers) artist_url.get_last_viewed_artists.assert_called_once_with('alw:1010') assert result.status_code == status.OK