"""Unit tests for tasks of Kuwo Workflow.""" from unittest.mock import MagicMock from unittest.mock import patch from freezegun import freeze_time import pytest from feed_ingestion.flows.kuwo import tasks _date = '2022-11-16' @pytest.fixture def mock_executor_context(): """Yield executor context.""" sf_executor_class_path = \ 'feed_ingestion.flows.kuwo.tasks.Kuwo' with patch(sf_executor_class_path) as sf_executor: mock_executor_context = sf_executor.return_value.__enter__.return_value yield mock_executor_context class TestBootstrap(object): """Test bootstrap.""" @pytest.fixture def expected_bootstrap_response(self): """Response for bootstrap task.""" return { 'feed_name': 'kuwo_theorchard', 'date': '2022-11-16', 'licensor': 'theorchard', 'store_id': 1601, 's3_bucket': 'dev-cucumbers', 'drop_path': 's3://dev-feed-drop/koowo/in/', 'archive_path': 'kuwo/archives/2022-11-16/', 's3_full_path': 's3://dev-cucumbers/kuwo/archives/2022-11-16/', 'source_file_pattern': '^PO42_\\d{8}_\\d{8}_TheOrchard\\.txt$', 'skip_corrupted_rows': 'False', 'expected_files': ['PO42_20221116_20221116_TheOrchard.txt'], 'secrets_path': 'kuwo', 'staging_raw_table': 'staging_raw_kuwo', 'replace_archive_files': True } @freeze_time(_date) @patch('feed_ingestion.flows.kuwo.tasks.garcon_feed_status') def test_bootstrap_no_date_is_passed( self, feed_status_mock, expected_bootstrap_response): """Date should be set to today if it is not provided.""" context = { 'activity': MagicMock(), 'date': None, 'licensor': 'theorchard', 'reload': 'False', 'skip_corrupted_rows': 'False'} result = tasks.bootstrap(**context) assert result == expected_bootstrap_response @patch('feed_ingestion.flows.kuwo.tasks.garcon_feed_status') def test_bootstrap_date_is_passed( self, feed_status_mock, expected_bootstrap_response): """Date should be returned if it is provided.""" result = tasks.bootstrap(MagicMock(), date=_date, licensor='theorchard', reload='False', skip_corrupted_rows='False') assert result == expected_bootstrap_response class TestBootstrapNewFormat(object): """Test bootstrap for the new P0CY format (date >= new_format_since).""" @pytest.mark.parametrize('licensor, expected_files, expected_pattern', [ ( 'theorchard', ['P0CY_D_20260707_Kuwo_TO.txt'], r'^P0CY_D_\d{8}_Kuwo_TO\.txt$', ), ( 'sme', ['P0CY_D_20260707_Kuwo_SME.txt', 'P0CY_D_20260707_Kuwo_SMEJ.txt'], r'^P0CY_D_\d{8}_Kuwo_SME(J)*\.txt$', ), ]) @patch('feed_ingestion.flows.kuwo.tasks.garcon_feed_status') def test_bootstrap_new_format_files( self, feed_status_mock, licensor, expected_files, expected_pattern): """New P0CY file names/patterns are used on/after the cutover.""" result = tasks.bootstrap( MagicMock(), date='2026-07-07', licensor=licensor, reload='False', skip_corrupted_rows='False') assert result['expected_files'] == expected_files assert result['source_file_pattern'] == expected_pattern @pytest.mark.parametrize('date, expected_prefix', [ ('2026-06-30', 'PO42_20260630_20260630_TheOrchard.txt'), ('2026-07-01', 'P0CY_D_20260701_Kuwo_TO.txt'), ]) @patch('feed_ingestion.flows.kuwo.tasks.garcon_feed_status') def test_bootstrap_format_cutover_boundary( self, feed_status_mock, date, expected_prefix): """The cutover switches formats exactly on new_format_since.""" result = tasks.bootstrap( MagicMock(), date=date, licensor='theorchard', reload='False', skip_corrupted_rows='False') assert result['expected_files'] == [expected_prefix]