"""Unit tests for tasks of Spotify Marquee Workflow.""" from datetime import datetime import re from unittest.mock import MagicMock from unittest.mock import patch import pytest from snowflake_connector.etl_connector import SQLLoader from feed_ingestion.flows.spotify_marquee import config from feed_ingestion.flows.spotify_marquee import snowflake_executor from feed_ingestion.flows.spotify_marquee import tasks _date = '2024-10-22' _report_name = 'segment_level' _licensor = 'theorchard' _REMOVED_COLUMNS = ['campaign_name', 'release_upc', 'po_number'] class TestBootstrap(object): """Test bootstrap.""" @pytest.fixture def expected_bootstrap_response(self): """Response for bootstrap task.""" _date_dt = datetime.strptime(_date, '%Y-%m-%d').date() file_name = config.reports[_report_name]['file_pattern'].format( date=_date_dt ) return { 'date': _date, 'file_name': file_name, 'feed_name': '_'.join([config.feed_name, _licensor, _report_name]), 'report_name': _report_name, 'licensor': _licensor, 's3_drop_path': config.s3['drop'].format(date=_date_dt), 's3_archive_path': config.s3['archive'].format(date=_date_dt), 'staging_raw_table': config.reports[_report_name][ 'staging_raw_table'], 'temp_table_name': config.temp_table_name.format( report_name=_report_name, date=_date_dt), 'sf_kwargs': { 'date': _date, 'file_pattern': '.*{}.*'.format( re.escape(file_name.replace('.txt.gz', ''))), 'report_name': _report_name, 'licensor': _licensor, 'error_limit': config.snowflake_error_limit }, 'source_files_dict': { 'files': [{ 'file_name': file_name, 'found': True}] } } @patch('feed_ingestion.flows.spotify_marquee.tasks.garcon_feed_status') def test_bootstrap(self, feed_status_mock, expected_bootstrap_response): """Test bootstrap task.""" context = { 'activity': MagicMock(), 'date': _date, 'report_name': _report_name, 'licensor': 'theorchard', 'reload': None } result = tasks.bootstrap(**context) assert result == expected_bootstrap_response class TestRemovedColumnsQueryVersion: """Tests for 2026-03-23 query version handling removed Spotify columns. Spotify removed CAMPAIGN_NAME, RELEASE_UPC, and PO_NUMBER from Marquee report files starting 2026-03-23. """ @pytest.mark.parametrize( 'report_name', ['campaign_level', 'segment_level']) def test_create_temp_table_uses_new_version_from_removal_date( self, report_name): """Loader picks the 2026-03-23 folder for dates on/after removal.""" loader = SQLLoader( snowflake_executor.__file__, date='2026-03-23', ) assert loader.folder_version == '2026-03-23' @pytest.mark.parametrize( 'report_name', ['campaign_level', 'segment_level']) def test_create_temp_table_uses_previous_version_before_removal_date( self, report_name): """Loader picks the 2026-01-20 folder for dates before removal.""" loader = SQLLoader( snowflake_executor.__file__, date='2026-03-22', ) assert loader.folder_version == '2026-01-20' @pytest.mark.parametrize( 'report_name', ['campaign_level', 'segment_level']) def test_create_temp_table_excludes_removed_columns(self, report_name): """New temp table DDL must not define the 3 removed columns.""" loader = SQLLoader( snowflake_executor.__file__, date='2026-03-23', ) sql = loader.load_query( config.create_temp_table_query_name.format( report_name=report_name) ) for column in _REMOVED_COLUMNS: assert '\t{}\t'.format(column.upper()) not in sql assert '\t{} '.format(column.upper()) not in sql @pytest.mark.parametrize( 'report_name', ['campaign_level', 'segment_level']) def test_load_staging_raw_inserts_null_for_removed_columns( self, report_name): """Load staging raw insert uses null for the 3 removed columns.""" loader = SQLLoader( snowflake_executor.__file__, date='2026-03-23', ) sql = loader.load_query( config.load_query_name.format(report_name=report_name) ).lower() for column in _REMOVED_COLUMNS: assert 'null as {}'.format(column) in sql