"""Unit tests for VEVO tasks workflow.""" from unittest.mock import MagicMock from unittest.mock import patch from botocore.exceptions import ClientError import pytest from feed_ingestion.flows.vevo import config from feed_ingestion.flows.vevo import tasks _date = '2021-01-03' @pytest.fixture def expected_bootstrap_response_theorchard(): """Response for bootstrap task.""" return { 'feed_name': '_'.join([config.feed_name, 'theorchard']), 'licensor': 'theorchard', 'date': '2021-01-03', 'filename_theorchard_prefix': 'The_Orchard_Vevo_YouTube_Active_Claims_Metadata_2021-01-03T', 'filename_sme': 'active_claims_20210103.csv.gz', 'drop_path': 'feed-drop/Vevo/', 'archive_path': 'Vevo/archives/2021-01-03/', 'temp_staging_raw_table': 'temp_staging_raw_vevo_theorchard_20210103', 'staging_raw_table': config.staging_raw_table, 'secrets_path': config.secrets_path } @pytest.fixture def mock_get_overall_status(): """Yield get overall status.""" overall_status_path = ( 'feed_ingestion.flows.vevo.tasks.garcon_feed_status.' 'get_overall_status') with patch(overall_status_path) as overall_status: yield overall_status @pytest.fixture def mock_set_overall_status(): """Yield overall status.""" overall_status_path = ( 'feed_ingestion.flows.vevo.tasks.garcon_feed_status.' 'set_overall_status') with patch(overall_status_path) as overall_status: yield overall_status @pytest.fixture def mock_delete_status(): """Yield delete overall status.""" overall_status_path = ( 'feed_ingestion.flows.vevo.tasks.garcon_feed_status.' 'delete_status') with patch(overall_status_path) as overall_status: yield overall_status @pytest.fixture def mock_set_missing_files(): """Yield set missing files.""" set_missing_files_path = ( 'feed_ingestion.flows.vevo.tasks.garcon_feed_status.' 'set_missing_files') with patch(set_missing_files_path) as set_missing_files: yield set_missing_files def test_bootstrap(expected_bootstrap_response_theorchard): """Test bootstrap task.""" result = tasks.bootstrap( MagicMock(), _date, licensor='theorchard') assert result == expected_bootstrap_response_theorchard @pytest.fixture def mock_task_status(): """Yield task status.""" task_status_path = 'feed_ingestion.tasks.task_status' with patch(task_status_path) as task_status: task_status.is_completed_task.return_value = False task_status.mark_completed_task = MagicMock() task_status.get_values = MagicMock() yield task_status @pytest.fixture def mock_s3_tasks(): """Yield overall status.""" path = 'feed_ingestion.flows.vevo.tasks.s3_tasks' with patch(path) as mock_s3: yield mock_s3 @pytest.fixture def mock_get_list_of_files_and_directories(): """Yield overall status.""" path = 'feed_ingestion.flows.vevo.tasks.get_list_of_files_and_directories' with patch(path) as mock_get_list_of_files: yield mock_get_list_of_files def test_grab_drop_files_file_is_not_available( mock_task_status, mock_set_overall_status, mock_s3_tasks, mock_get_list_of_files_and_directories, mock_set_missing_files): """Test test_grab_drop_files when a file is not available.""" mock_s3_tasks.copy_file.return_value = {} mock_get_list_of_files_and_directories.return_value = [] result = tasks.grab_drop_files( MagicMock(), 'feed_name', _date, filename_prefix='filename_2021-01-03T', drop_path='feed-drop/Vevo/', archive_path='Vevo/archives/2021-01-03/') assert result == {'stop': True} mock_set_overall_status.assert_called_with( 'feed_name', _date, 'NOT_AVAILABLE') mock_set_missing_files.assert_called_with( 'feed_name', _date, ['filename_2021-01-03T']) def test_grab_drop_files_file_is_available( mock_task_status, mock_set_overall_status, mock_s3_tasks, mock_get_list_of_files_and_directories, mock_set_missing_files): """Test test_grab_drop_files when a file is available.""" mock_s3_tasks.copy_file.return_value = {} filename = ( 'The_Orchard_Vevo_YouTube_Active_Claims_Metadata' '_2021-01-03T1355_Z3GS9N.txt') source_key_name = f'feed-drop/Vevo/{filename}' mock_s3_tasks.copy_file.return_value = { filename: True, } mock_get_list_of_files_and_directories.return_value = [source_key_name] result = tasks.grab_drop_files( MagicMock(), 'feed_name', _date, filename_prefix='filename_2021-01-03T', drop_path='feed-drop/Vevo/', archive_path='Vevo/archives/2021-01-03/') assert result == { 's3_drop_path': f's3://{config.drop_bucket}/{source_key_name}'} mock_set_overall_status.assert_not_called() mock_set_missing_files.assert_not_called() @patch('feed_ingestion.flows.vevo.tasks.get_s3_client_assume_role') def test_grab_drop_files_sme( mock_sme_s3, mock_task_status, mock_set_overall_status): """Test grab_drop_files_sme.""" result = tasks.grab_drop_files_sme( MagicMock(), 'vevo_sme', _date, drop_path='feed-drop/Vevo/', filename='active_claims_20210103.csv.gz', archive_path='Vevo/archives/2021-01-03/') mock_sme_s3.return_value.copy.assert_called_once_with({ 'Bucket': 'sme-data-archive', 'Key': 'feed-drop/Vevo/active_claims_20210103.csv.gz' }, 'dev-cucumbers', 'Vevo/archives/2021-01-03/active_claims_20210103.csv.gz' ) assert result == { 's3_drop_path': ( 's3://dev-cucumbers/Vevo/archives/' '2021-01-03/active_claims_20210103.csv.gz')} @patch('feed_ingestion.flows.vevo.tasks.get_s3_client_assume_role') def test_grab_drop_files_sme_if_no_new_file( mock_sme_s3, mock_task_status, mock_set_overall_status): """Test grab_drop_files_sme if there is no file.""" mock_sme_s3.return_value.copy.side_effect = ClientError( {'Error': {'Code': '404', 'Message': 'Not found'}}, 'Not found') result = tasks.grab_drop_files_sme( MagicMock(), 'vevo_sme', _date, drop_path='feed-drop/Vevo/', filename='active_claims_20210103.csv.gz', archive_path='Vevo/archives/2021-01-03/') mock_sme_s3.return_value.copy.assert_called_once_with({ 'Bucket': 'sme-data-archive', 'Key': 'feed-drop/Vevo/active_claims_20210103.csv.gz' }, 'dev-cucumbers', 'Vevo/archives/2021-01-03/active_claims_20210103.csv.gz' ) assert result == { 'stop': True, 'message': 'Cannot find feed-drop/Vevo/' 'active_claims_20210103.csv.gz object on S3'} @patch('feed_ingestion.flows.vevo.tasks.get_s3_client_assume_role') def test_grab_drop_files_sme_if_other_exception( mock_sme_s3, mock_task_status, mock_set_overall_status): """Test grab_drop_files_sme if other_exception occurs.""" mock_sme_s3.return_value.copy.side_effect = ClientError( {'Error': {'Code': '400', 'Message': 'Bad Request'}}, 'Bad Request') with pytest.raises(ClientError): tasks.grab_drop_files_sme( MagicMock(), 'vevo_sme', _date, drop_path='feed-drop/Vevo/', filename='active_claims_20210103.csv.gz', archive_path='Vevo/archives/2021-01-03/') mock_sme_s3.return_value.copy.assert_called_once_with({ 'Bucket': 'sme-data-archive', 'Key': 'feed-drop/Vevo/active_claims_20210103.csv.gz' }, 'dev-cucumbers', 'Vevo/archives/2021-01-03/active_claims_20210103.csv.gz' )