"""Unit tests for app.py module.""" import json from unittest.mock import patch import pytest from src import app from src.queries import snowflake_queries @patch('src.app.send_email_with_csv') @patch('src.app.execute_snowflake_query') @patch('src.app.uuid') def test_main_handler_success(mock_uuid, mock_execute_query, mock_send_email_with_csv): """Test main_handler executes all steps successfully.""" # Setup mock_uuid.uuid4.return_value = 'test-task-id-12345' mock_execute_query.side_effect = [ None, # CREATE_VENDOR_DELETIONS_EXPORT [ # GET_VENDOR_DELETIONS {'REQUEST_ID': '1', 'EMAIL': 'user1@example.com', 'PLATFORMS': '["smf", "wordpress"]'}, {'REQUEST_ID': '2', 'EMAIL': 'user2@example.com', 'PLATFORMS': '["wyng"]'}, ], None, # MARK_VENDOR_DELETIONS_AS_EXPORTED None, # CLEANUP_VENDOR_DELETIONS_EXPORT ] event = {} context = {} # Execute result = app.main_handler(event, context) # Assert assert result['statusCode'] == 200 assert 'Completed vendor deletions export process' in result['body'] # Verify all Snowflake queries were called assert mock_execute_query.call_count == 3 # Verify CREATE call mock_execute_query.assert_any_call( snowflake_queries.CREATE_VENDOR_DELETIONS_EXPORT, {'platforms': json.dumps(['smf', 'wyng', 'tunespeak', 'mtl', 'wordpress'])} ) # Verify GET call mock_execute_query.assert_any_call( snowflake_queries.GET_VENDOR_DELETIONS, {} ) # Verify MARK call mock_execute_query.assert_any_call( snowflake_queries.MARK_VENDOR_DELETIONS_AS_EXPORTED, {'task_run_id': 'test-task-id-12345'} ) # Verify CLEANUP call # commented out for debugging purposes # mock_execute_query.assert_any_call( # snowflake_queries.CLEANUP_VENDOR_DELETIONS_EXPORT, {} # ) # Verify emails were sent to correct vendors assert mock_send_email_with_csv.call_count == 2 # Verify AE/DELPHI email mock_send_email_with_csv.assert_any_call( vendor_name='AE/DELPHI', emails_list=['user1@example.com'], to_addresses=['tbd@gmail.com'], cc_addresses=[], sender_email='donotreply@sonymusic.com', sender_display_name='Sony Music Fan Delete Request' ) # Verify Wyng email mock_send_email_with_csv.assert_any_call( vendor_name='Wyng', emails_list=['user2@example.com'], to_addresses=['tbd@gmail.com'], cc_addresses=[], sender_email='donotreply@sonymusic.com', sender_display_name='Sony Music Fan Delete Request' ) @patch('src.app.send_email_with_csv') @patch('src.app.execute_snowflake_query') @patch('src.app.uuid') def test_main_handler_with_empty_results(mock_uuid, mock_execute_query, mock_send_email_with_csv): """Test main_handler when no deletion requests are found.""" # Setup mock_uuid.uuid4.return_value = 'test-task-id-67890' mock_execute_query.side_effect = [ None, # CREATE_VENDOR_DELETIONS_EXPORT [], # GET_VENDOR_DELETIONS - empty results None, # MARK_VENDOR_DELETIONS_AS_EXPORTED None, # CLEANUP_VENDOR_DELETIONS_EXPORT ] event = {} context = {} # Execute result = app.main_handler(event, context) # Assert assert result['statusCode'] == 200 assert mock_execute_query.call_count == 3 # Verify no emails were sent mock_send_email_with_csv.assert_not_called() @patch('src.app.capture_exception') @patch('src.app.main_handler') def test_handler_success(mock_main_handler, mock_capture_exception): """Test handler delegates to main_handler successfully.""" # Setup expected_result = {'statusCode': 200, 'body': 'Success'} mock_main_handler.return_value = expected_result event = {'test': 'event'} context = {'test': 'context'} # Execute result = app.handler(event, context) # Assert assert result == expected_result mock_main_handler.assert_called_once_with(event, context) mock_capture_exception.assert_not_called() @patch('src.app.capture_exception') @patch('src.app.main_handler') def test_handler_catches_exception(mock_main_handler, mock_capture_exception): """Test handler catches and reports exceptions.""" # Setup test_exception = Exception('Test error') mock_main_handler.side_effect = test_exception event = {} context = {} # Execute & Assert with pytest.raises(Exception) as exc_info: app.handler(event, context) assert exc_info.value == test_exception mock_capture_exception.assert_called_once_with(test_exception) def test_group_emails_by_vendor_single_platform(): """Test grouping emails when each email has a single platform.""" # Setup result = [ {'EMAIL': 'user1@example.com', 'PLATFORMS': '["smf"]'}, {'EMAIL': 'user2@example.com', 'PLATFORMS': '["wyng"]'}, {'EMAIL': 'user3@example.com', 'PLATFORMS': '["tunespeak"]'}, {'EMAIL': 'user4@example.com', 'PLATFORMS': '["mtl"]'}, ] # Execute vendor_emails = app.group_emails_by_vendor(result) # Assert assert vendor_emails['AE/DELPHI'] == ['user1@example.com'] assert vendor_emails['Wyng'] == ['user2@example.com'] assert vendor_emails['TuneSpeak'] == ['user3@example.com'] assert vendor_emails['MTL'] == ['user4@example.com'] def test_group_emails_by_vendor_multiple_platforms(): """Test grouping emails when an email has multiple platforms.""" # Setup result = [ {'EMAIL': 'user1@example.com', 'PLATFORMS': '["smf", "wordpress"]'}, {'EMAIL': 'user2@example.com', 'PLATFORMS': '["wyng", "tunespeak"]'}, ] # Execute vendor_emails = app.group_emails_by_vendor(result) # Assert # user1 has both smf and wordpress, both belong to AE/DELPHI assert vendor_emails['AE/DELPHI'] == ['user1@example.com'] # user2 has wyng and tunespeak, each belongs to different vendors assert vendor_emails['Wyng'] == ['user2@example.com'] assert vendor_emails['TuneSpeak'] == ['user2@example.com'] def test_group_emails_by_vendor_empty_result(): """Test grouping emails with empty result set.""" # Setup result = [] # Execute vendor_emails = app.group_emails_by_vendor(result) # Assert assert len(vendor_emails) == 0 def test_group_emails_by_vendor_unknown_platform(): """Test grouping emails with platforms not in vendor mapping.""" # Setup result = [ {'EMAIL': 'user1@example.com', 'PLATFORMS': '["unknown_platform"]'}, {'EMAIL': 'user2@example.com', 'PLATFORMS': '["smf", "unknown_platform"]'}, ] # Execute vendor_emails = app.group_emails_by_vendor(result) # Assert # user1 should not appear anywhere assert 'user1@example.com' not in str(vendor_emails) # user2 should appear in AE/DELPHI because of 'smf' assert vendor_emails['AE/DELPHI'] == ['user2@example.com'] def test_group_emails_by_vendor_duplicate_emails_same_vendor(): """Test grouping when same email appears multiple times for same vendor.""" # Setup result = [ {'EMAIL': 'user1@example.com', 'PLATFORMS': '["smf"]'}, {'EMAIL': 'user1@example.com', 'PLATFORMS': '["wordpress"]'}, ] # Execute vendor_emails = app.group_emails_by_vendor(result) # Assert # Both smf and wordpress map to AE/DELPHI, so email appears twice assert vendor_emails['AE/DELPHI'] == ['user1@example.com', 'user1@example.com'] def test_group_emails_by_vendor_all_platforms(): """Test grouping with all supported platforms.""" # Setup result = [ {'EMAIL': 'user1@example.com', 'PLATFORMS': '["smf"]'}, {'EMAIL': 'user2@example.com', 'PLATFORMS': '["wordpress"]'}, {'EMAIL': 'user3@example.com', 'PLATFORMS': '["wyng"]'}, {'EMAIL': 'user4@example.com', 'PLATFORMS': '["tunespeak"]'}, {'EMAIL': 'user5@example.com', 'PLATFORMS': '["mtl"]'}, ] # Execute vendor_emails = app.group_emails_by_vendor(result) # Assert assert vendor_emails['AE/DELPHI'] == ['user1@example.com', 'user2@example.com'] assert vendor_emails['Wyng'] == ['user3@example.com'] assert vendor_emails['TuneSpeak'] == ['user4@example.com'] assert vendor_emails['MTL'] == ['user5@example.com'] @patch('src.app.constants') def test_group_emails_by_vendor_uses_config_mapping(mock_config): """Test that group_emails_by_vendor uses config.VENDOR_MAPPING.""" # Setup custom vendor mapping mock_config.VENDOR_MAPPING = { 'TestVendor': { 'platforms': ['test_platform'], 'email': 'test@example.com' } } result = [ {'EMAIL': 'user1@example.com', 'PLATFORMS': '["test_platform"]'}, ] # Execute vendor_emails = app.group_emails_by_vendor(result) # Assert assert vendor_emails['TestVendor'] == ['user1@example.com'] def test_group_emails_by_vendor_complex_scenario(): """Test complex scenario with multiple emails and overlapping platforms.""" # Setup result = [ {'EMAIL': 'user1@example.com', 'PLATFORMS': '["smf", "wyng"]'}, {'EMAIL': 'user2@example.com', 'PLATFORMS': '["wordpress"]'}, {'EMAIL': 'user3@example.com', 'PLATFORMS': '["tunespeak", "mtl"]'}, {'EMAIL': 'user4@example.com', 'PLATFORMS': '["smf", "wordpress", "wyng"]'}, ] # Execute vendor_emails = app.group_emails_by_vendor(result) # Assert assert set(vendor_emails['AE/DELPHI']) == {'user1@example.com', 'user2@example.com', 'user4@example.com'} assert set(vendor_emails['Wyng']) == {'user1@example.com', 'user4@example.com'} assert vendor_emails['TuneSpeak'] == ['user3@example.com'] assert vendor_emails['MTL'] == ['user3@example.com']