"""Unit tests for TikTok OpenEscrow tasks.""" from unittest.mock import MagicMock from unittest.mock import patch import pytest from feed_ingestion.flows.tiktok_openescrow import config from feed_ingestion.flows.tiktok_openescrow import tasks _date = '2026-01-01' _drop = 's3://dev-feed-drop/drop/report.zip' _archive = 's3://dev-cucumbers/archives/2026-01/report.gz' def test_bootstrap(): """Bootstrap returns the context for the reporting month.""" result = tasks.bootstrap(MagicMock(), _date, reload=None) assert result['date'] == '2026-01-01' assert result['feed_name'] == 'tiktok_openescrow' assert result['source_file_name'] == \ 'TikTok_OpenEscrow_report_202601.txt.zip' assert result['new_file_name'] == \ 'TikTok_OpenEscrow_report_202601.txt.gz' assert result['archive_path'] == 'tiktok_openescrow/archives/2026-01' assert result['s3_drop_file_path'] == ( f's3://{config.drop_bucket}/{config.s3["drop"]}/' 'TikTok_OpenEscrow_report_202601.txt.zip') assert result['s3_archive_file_path'] == ( f's3://{config.data_bucket}/tiktok_openescrow/archives/2026-01/' 'TikTok_OpenEscrow_report_202601.txt.gz') assert result['secrets_path'] == 'swf-tiktok-openescrow' assert result['staging_raw_table'] == 'STAGING_RAW_TIKTOK_OPENESCROW' def test_bootstrap_filenames_use_year_month(): """Source/archive file names use the YYYYMM of the reporting month.""" result = tasks.bootstrap(MagicMock(), '2026-03-01', reload=None) assert result['source_file_name'] == \ 'TikTok_OpenEscrow_report_202603.txt.zip' assert result['new_file_name'] == \ 'TikTok_OpenEscrow_report_202603.txt.gz' @pytest.fixture def s3_mock(): """Patch the s3 helper used by grab_drop_files.""" with patch('feed_ingestion.flows.tiktok_openescrow.tasks.s3') as s3: yield s3 @pytest.fixture def task_status_mock(): """Patch the task_status helper used by grab_drop_files.""" path = 'feed_ingestion.flows.tiktok_openescrow.tasks.task_status' with patch(path) as task_status: yield task_status def test_grab_drop_files_converts_when_not_completed( s3_mock, task_status_mock): """A fresh run converts the zip and returns source_files_dict.""" task_status_mock.is_completed_task.return_value = False s3_mock.get_list_of_files_and_directories.return_value = [_drop] s3_mock.get_key_size.return_value = 123 activity = MagicMock() result = tasks.grab_drop_files(activity, _date, _drop, _archive) s3_mock.convert_zip_to_gzip_on_s3.assert_called_once_with( activity, zip_s3_path=_drop, gz_s3_path=_archive, local_temp_dir='./', extract_original_filename=True) task_status_mock.mark_completed_task.assert_called_once_with( config.feed_name, _date, 'grab_drop_files') assert result == { 'source_files_dict': { 'files': [{ 'file_name': 'report.gz', 'file_size': 123, 'found': True, }], }, } def test_grab_drop_files_stops_when_no_file(s3_mock, task_status_mock): """No dropped file - the task stops and converts nothing.""" task_status_mock.is_completed_task.return_value = False s3_mock.get_list_of_files_and_directories.return_value = [] result = tasks.grab_drop_files(MagicMock(), _date, _drop, _archive) s3_mock.convert_zip_to_gzip_on_s3.assert_not_called() task_status_mock.mark_completed_task.assert_not_called() assert result == {'stop': True, 'missing_file': _drop} def test_grab_drop_files_skips_conversion_when_completed( s3_mock, task_status_mock): """A resumed run skips conversion but still returns source_files_dict.""" task_status_mock.is_completed_task.return_value = True s3_mock.get_key_size.return_value = 456 result = tasks.grab_drop_files(MagicMock(), _date, _drop, _archive) s3_mock.get_list_of_files_and_directories.assert_not_called() s3_mock.convert_zip_to_gzip_on_s3.assert_not_called() task_status_mock.mark_completed_task.assert_not_called() assert result == { 'source_files_dict': { 'files': [{ 'file_name': 'report.gz', 'file_size': 456, 'found': True, }], }, }