"""Unit tests for tasks of Amazon Prime Marketshare Workflow.""" from unittest.mock import MagicMock from unittest.mock import patch import boto3 from boto3.exceptions import S3UploadFailedError from garcon_contrib.dynamo_feed_status import garcon_feed_status import pytest from feed_ingestion.flows.amazon_prime_marketshare import config from feed_ingestion.flows.amazon_prime_marketshare import tasks _date = '2018-05-01' @pytest.fixture def expected_bootstrap_response(): """Response for bootstrap task.""" return { 'feed_name': config.feed_name, 'secrets_path': config.secrets_path, 'date': _date, 's3_archive_path': ( 's3://dev-cucumbers/' 'AmazonPrimeMarketShare/archives/2018-05/'), 's3_preprocessed_path': ( 's3://dev-cucumbers/' 'AmazonPrimeMarketShare/preprocessed/'), 'processed_filename': 'amazon_prime_mkt_share_2018-05-01.tsv.gz', 'file_pattern': 'Monthly_Prime_Summary_201805', 'temp_staging_raw_table': ( 'temp_staging_raw_amazon_market_share_v2_20180501'), 's3_temp_staging_raw_bucket': ( 's3://dev-cucumbers/AmazonPrimeMarketShare/preprocessed/' 'amazon_prime_mkt_share_2018-05-01.tsv.gz'), 'staging_raw_table': config.snowflake_table_names['staging_raw'], 'kwargs': {'date_for_sqlloader': _date}, } def test_bootstrap( expected_bootstrap_response): """Test bootstrap task.""" result = tasks.bootstrap( activity=MagicMock(), date=_date, reload=None) assert result == expected_bootstrap_response result = tasks.bootstrap( activity=MagicMock(), date='2018-05-01', reload=None) assert result == expected_bootstrap_response @patch('feed_ingestion.flows.amazon_prime_marketshare.tasks.' 'garcon_feed_status.delete_status') def test_bootstrap_if_reload( mock_delete_status, expected_bootstrap_response): """The feed status should be deleted.""" result = tasks.bootstrap( activity=MagicMock(), date=_date, reload='True') mock_delete_status.assert_called_with( config.feed_name, _date) assert result == expected_bootstrap_response @pytest.fixture def mock_set_overall_status(): """Yield overall status.""" overall_status_path = ( 'feed_ingestion.flows.amazon_prime_marketshare.tasks.' 'garcon_feed_status.set_overall_status') with patch(overall_status_path) as overall_status: yield overall_status @pytest.fixture def process_drop_files_context(expected_bootstrap_response): """Context for task process_drop_files.""" source_files_dict = { 'files': [ { 'file_name': ( 'GB ZQFT_Monthly_Prime_Summary_20180531_gb.csv'), 'found': True, 'file_size': 1}, { 'file_name': ( 'DE ZQRED_Monthly_Prime_Summary_20180531_de.csv'), 'found': True, 'file_size': 1}]} return { 'activity': MagicMock(), 'feed_name': config.feed_name, 'date': _date, 's3_archive_path': expected_bootstrap_response['s3_archive_path'], 's3_preprocessed_path': expected_bootstrap_response[ 's3_preprocessed_path'], 'processed_filename': expected_bootstrap_response[ 'processed_filename'], 'source_files_dict': source_files_dict} @patch('feed_ingestion.flows.amazon_prime_marketshare.tasks._process_data') @patch('feed_ingestion.flows.amazon_prime_marketshare.tasks.s3utils') def test_process_drop_files( mock_s3utils, mock_process_data, process_drop_files_context): """Should process and upload files.""" tasks.process_drop_files(**process_drop_files_context) assert mock_process_data.called assert mock_s3utils.upload_processed_to_s3.called @patch('feed_ingestion.flows.amazon_prime_marketshare.tasks._process_data') @patch('feed_ingestion.flows.amazon_prime_marketshare.tasks.s3utils') def test_process_drop_files_with_upload_error( mock_s3utils, mock_process_data, process_drop_files_context, mock_set_overall_status): """Should set status NOT_AVAILABLE.""" def sf_raise_error(csvfile, s3_path, expected_bucket_owner=config.expected_bucket_owner): raise S3UploadFailedError(500, 'Service error.') mock_s3utils.upload_processed_to_s3.side_effect = sf_raise_error with pytest.raises(S3UploadFailedError): tasks.process_drop_files(**process_drop_files_context) assert mock_process_data.called assert mock_s3utils.upload_processed_to_s3.called mock_set_overall_status.assert_called_with( '_'.join([config.feed_name, config.feed_name]), _date, garcon_feed_status.STATUS_NOT_AVAILABLE) def test_process_data( monkeypatch, process_drop_files_context): """_process_data should process all available files.""" client = MagicMock() monkeypatch.setattr( boto3, 'client', MagicMock(return_value=client)) tasks._process_data( process_drop_files_context['s3_archive_path'], _date, process_drop_files_context['source_files_dict']) assert client.get_object.call_count == len( process_drop_files_context['source_files_dict']['files'])