"""Unit tests for Soundcloud Statistics Workflow.""" import datetime from unittest import mock from unittest.mock import call import config # from freezegun import freeze_time import soundcloud_with_selenium as soundcloud from tests.conftest import MockXPath, artist_last_stats,\ artist_statistics_from_table class TestSoundCloudTracker: """Test Soundcloud Tracker related methods.""" def test_get_id_from_link(self, processed_links): """Test get_username_from_link method with reverse parameter also.""" config.SOUNDCLOUD_LINK = 'https://soundcloud.com/' username = soundcloud.get_id_from_link(processed_links['soundcloud']) assert username == 'cijikin' def test_create_tables_for_the_first_time( self, mock_delete_from_staging_raw, mock_create_staging_raw_soundcloud_statistics, mock_create_soundcloud_statistics, mock_create_artist_link_table, mock_select_artists_links, mock_executor, processed_links, get_artists_links, mock_set_webdriver): """Test create_tables method working correctly during the first run.""" mock_select_artists_links.return_value = get_artists_links tracker = soundcloud.SoundCloudTracker() tracker.create_tables() called_methods = \ [not mock_create_artist_link_table.called, mock_select_artists_links.called, mock_create_soundcloud_statistics.called, mock_delete_from_staging_raw.called, mock_create_staging_raw_soundcloud_statistics.called] for _call in called_methods: assert _call assert tracker.__first_time__ assert 'cijikin' in tracker.get_profiles().keys() @mock.patch('soundcloud_with_selenium.SoundCloudStatsSFExecutor.' 'select_artists_stats', artist_statistics_from_table) def test_create_tables_not_for_the_first_time( self, mock_delete_from_staging_raw, mock_create_staging_raw_soundcloud_statistics, mock_create_soundcloud_statistics, mock_create_artist_link_table, mock_select_artists_links, mock_executor, processed_links, get_artists_links, mock_set_webdriver): """Test create_tables method working correctly for not first run.""" mock_select_artists_links.return_value = get_artists_links mock_create_artist_link_table.return_value, \ mock_create_staging_raw_soundcloud_statistics.return_value, \ mock_create_soundcloud_statistics.return_value = \ [['already exists']] * 3 tracker = soundcloud.SoundCloudTracker() tracker.create_tables() called_methods = \ [not mock_create_artist_link_table.called, mock_select_artists_links.called, mock_create_soundcloud_statistics.called, mock_delete_from_staging_raw.called, mock_create_staging_raw_soundcloud_statistics.called] for _call in called_methods: assert _call assert not tracker.__first_time__ assert 'cijikin' in tracker.get_profiles() @mock.patch('soundcloud_with_selenium.SoundCloudStatsSFExecutor.' 'select_weekly_change') def test_compare_current_and_last_week_stats_for_weekly_statistics( self, mock_select_weekly_change, mock_executor, processed_links, mock_set_webdriver): """Test correctness of comparing method calculations.""" def weekly_side_effect(*args, **kwargs): if -6 in list(kwargs.values()): return { 'followers_count': 45, 'followings_count': 0, 'tracks_count': 2, 'plays_count': 8698, 'likes_count': 923, 'reposts_count': 165} else: return { 'followers_count': 6, 'followings_count': 0, 'tracks_count': 0, 'plays_count': 7100, 'likes_count': 834, 'reposts_count': 114} mock_select_weekly_change.side_effect = weekly_side_effect current_followers = 578 tracker = soundcloud.SoundCloudTracker() calculations = tracker.compare_current_and_last_week_stats( current_followers, 'followers_count', artist_last_stats(), 'cijikin') artist_lasts = artist_last_stats()['cijikin'] calculations_to_assert = [ calculations['last_week_followers_count'] == artist_lasts['last_week_followers_count'], calculations['daily_change_in_followers_count'] == current_followers - artist_lasts['current_followers_count'], calculations['current_weekly_change_in_followers_count'] == calculations['daily_change_in_followers_count'] + weekly_side_effect('cijikin')['followers_count'], calculations['weekly_change_in_followers_count'] == weekly_side_effect(first_day_of_period=-6)['followers_count'], calculations['percentage_change_in_followers_count'] == calculations['current_weekly_change_in_followers_count'] / (current_followers - calculations[ 'current_weekly_change_in_followers_count']), calculations['acceleration_followers_count'] == (calculations['daily_change_in_followers_count'] + weekly_side_effect('cijikin')['followers_count'] - weekly_side_effect(first_day_of_period=-6)['followers_count']) / weekly_side_effect(first_day_of_period=-6)[ 'followers_count'], calculations['last_processing_date'] == datetime.date.today(), calculations['last_week_processing_date'] == artist_lasts['last_week_processing_date']] for calculation in calculations_to_assert: assert calculation @mock.patch('soundcloud_with_selenium.SoundCloudStatsSFExecutor.' 'select_weekly_change') def test_compare_current_and_last_week_stats_for_week_period_statistics( self, mock_select_weekly_change, mock_executor, processed_links, mock_set_webdriver): """Test correctness of comparing method calculations for posts.""" def weekly_side_effect(*args, **kwargs): if -6 in list(kwargs.values()): return { 'followers_count': 9, 'followings_count': 0, 'tracks_count': 0, 'plays_count': 8698, 'likes_count': 923, 'reposts_count': 165} else: return { 'followers_count': 6, 'followings_count': 0, 'tracks_count': 0, 'plays_count': 7100, 'likes_count': 834, 'reposts_count': 114} tracker = soundcloud.SoundCloudTracker() current_plays = 25409 mock_select_weekly_change.side_effect = weekly_side_effect calculations = tracker.compare_current_and_last_week_stats( current_plays, 'plays_count', artist_last_stats( last_week_processing_date=datetime.date.today() - datetime.timedelta(days=7)), 'cijikin') artist_lasts = artist_last_stats( last_week_processing_date=datetime.date.today() - datetime.timedelta(days=7))['cijikin'] # checking the calculation when week period ends assert mock_select_weekly_change.called calculations_to_assert = [ calculations['last_week_plays_count'] == artist_lasts['current_plays_count'], calculations['daily_change_in_plays_count'] == current_plays - artist_lasts['current_plays_count'], calculations['current_weekly_change_in_plays_count'] == calculations['daily_change_in_plays_count'] + weekly_side_effect('cijikin')['plays_count'], calculations['weekly_change_in_plays_count'] == weekly_side_effect(first_day_of_period=-6)['plays_count'], calculations['percentage_change_in_plays_count'] == (calculations['current_weekly_change_in_plays_count'] - calculations['weekly_change_in_plays_count']) / calculations['weekly_change_in_plays_count'], calculations['acceleration_plays_count'] == ( calculations['daily_change_in_plays_count'] + weekly_side_effect('cijikin')['plays_count'] - weekly_side_effect( first_day_of_period=-6)['plays_count']) / weekly_side_effect(first_day_of_period=-6)['plays_count'], calculations['last_processing_date'] == datetime.date.today(), calculations['last_week_processing_date'] == datetime.date.today() ] for calculation in calculations_to_assert: assert calculation @mock.patch('soundcloud_with_selenium.SoundCloudTracker.get_profiles', artist_last_stats) def test_get_artist_info( self, mock_abbreviated_value_to_int, mock_get_stat_from_, mock_executor, mock_executor_context, mock_set_webdriver, mock_compare_current_and_last_week_stats, mock_get_driver_of_artist_page): """Test get_artist_info method.""" tracker = soundcloud.SoundCloudTracker() mock_get_stat_from_.return_value = MockXPath() for artist in artist_last_stats(): tracker.get_artist_info(artist) called_methods = \ [mock_get_stat_from_.call_count == 4, mock_set_webdriver.called, mock_compare_current_and_last_week_stats.called, mock_compare_current_and_last_week_stats.call_count == 3, mock_compare_current_and_last_week_stats.call_args[0][0][ 'followers_count'] == 986756] for metric in ['followings', 'tracks_count']: called_methods.append( call(metric) in mock_get_stat_from_.call_args_list) for metric in ['followers', 'release']: called_methods.append( call(metric, _type='css') in mock_get_stat_from_.call_args_list) for method in called_methods: assert method @mock.patch('soundcloud_with_selenium.SoundCloudTracker.get_profiles', artist_last_stats) def test_get_tracks_info( self, mock_abbreviated_value_to_int, mock_get_stat_from_, mock_executor, mock_executor_context, mock_set_webdriver, mock_select_weekly_change, mock_get_driver_of_artist_page): """Test get_tracks_info method.""" tracker = soundcloud.SoundCloudTracker() for artist in artist_last_stats(): tracker.get_tracks_info(artist) called_methods = \ [mock_get_stat_from_.call_count == 4, mock_set_webdriver.called, mock_select_weekly_change.called, mock_select_weekly_change.call_count == 6, ] for metric in ['tracks', 'plays', 'likes', 'reposts']: called_methods.append( call(metric, multiple=True) in mock_get_stat_from_.call_args_list) for method in called_methods: assert method @mock.patch('soundcloud_with_selenium.SoundCloudTracker.' 'update_staging_raw_table_with_stats') def test_perform_tracking( self, mock_update_staging_raw_table_with_stats, mock_create_tables, mock_executor, mock_executor_context, mock_set_webdriver): """Test perform_tracking method.""" tracker = soundcloud.SoundCloudTracker() tracker.perform_tracking() called_methods = [mock_create_tables.called, mock_set_webdriver.called, mock_update_staging_raw_table_with_stats.called] for method in called_methods: assert method