"""Unit tests for lambda function.""" from unittest.mock import patch from src.app import handler from tests.connectors.local_storage import LocalStorage # sfn_execution_id for the delivery with no ACK file in local storage (awaited) _AWAITED_SFN = '0005831b-49ca-4a40-b90f-573b8cfd7968-jFz6ByZlzKanCJroJzDZI0htjRyM98Xn-False' # sfn_execution_id for the delivery with an auto-retry error ACK in local storage _AUTO_RETRY_SFN = '0005831b-49ca-4a40-b90f-573b8cfd7968-jFz6ByZlzKanCJroJzDZI0htjRyM97Xn-False' _AUTO_RETRY_DELIVERY = { 'sfn_execution_id': _AUTO_RETRY_SFN, 'version_id': 'USESK1315720', 'datetime': '2025-07-08T05:55:07.750132Z', } def test_invoke_lambda(): """Assert lambda action. The awaited delivery (USESK1315719) has a datetime from 2025, which is older than the default MISSING_HOURS_THRESHOLD of 72 hours, so it is promoted to 'missing'. """ missing_resolver_calls = [] dependencies = { 'ack_storage': LocalStorage(), 'awaited_deliveries': [ { 'sfn_execution_id': '0005831b-49ca-4a40-b90f-573b8cfd7968-jFz6ByZlzKanCJroJzDZI0htjRyM95Xn-False', # noqa: E501 'version_id': 'USESK1315718', 'datetime': '2025-07-08T05:54:07.750132Z' }, { 'sfn_execution_id': '0005831b-49ca-4a40-b90f-573b8cfd7968-jFz6ByZlzKanCJroJzDZI0htjRyM96Xn-False', # noqa: E501 'version_id': 'USESK1315717', 'datetime': '2025-07-08T05:58:07.750132Z' }, { 'sfn_execution_id': _AWAITED_SFN, 'version_id': 'USESK1315719', 'datetime': '2025-07-08T05:51:07.750132Z' } ], 'awaited_resolver': lambda acks: None, 'awaited_as_missing_resolver': lambda acks: missing_resolver_calls.extend(acks), 'show_data': True, } result = handler(None, {}, dependencies) assert result == { 'awaited': 0, 'processed': 3, 'errors': 1, 'successful': 1, 'missing': 1, 'data': { 'errors': [ { 'datetime': '2025-07-08T05:58:07.750132Z', 'message': 'MetadataMissing isrc:USESK1315717 no track file_info,because SoundRecordingDetailsByTerritory.TechnicalSoundRecordingDetails is empty', # noqa: E501 'version_id': 'USESK1315717' } ], 'successful': [ { 'datetime': '2025-07-08T05:54:07.750132Z', 'version_id': 'USESK1315718' } ], 'awaited': [ { 'datetime': '2025-07-08T05:51:07.750132Z', 'version_id': 'USESK1315719', } ] } } assert len(missing_resolver_calls) == 1 assert missing_resolver_calls[0]['version_id'] == 'USESK1315719' @patch('src.common.ack_processor.processor.config') def test_awaited_older_than_threshold_resolves_as_missing(mock_config): """Awaited rows whose datetime is older than MISSING_HOURS_THRESHOLD are resolved as missing.""" mock_config.LIMIT = 1000 mock_config.MISSING_HOURS_THRESHOLD = 72 missing_resolver_calls = [] dependencies = { 'ack_storage': LocalStorage(), 'awaited_deliveries': [ { 'sfn_execution_id': _AWAITED_SFN, 'version_id': 'USESK1315719', 'datetime': '2025-07-08T05:51:07.750132Z' } ], 'awaited_resolver': lambda acks: None, 'awaited_as_missing_resolver': lambda acks: missing_resolver_calls.extend(acks), } result = handler(None, {}, dependencies) assert result['missing'] > 0 assert result['awaited'] == 0 assert len(missing_resolver_calls) > 0 @patch('src.common.ack_processor.processor.config') def test_awaited_within_threshold_stays_awaited(mock_config): """Awaited rows whose datetime is within MISSING_HOURS_THRESHOLD remain awaited.""" mock_config.LIMIT = 1000 mock_config.MISSING_HOURS_THRESHOLD = 999999 # cutoff far in the past — nothing is missing missing_resolver_calls = [] dependencies = { 'ack_storage': LocalStorage(), 'awaited_deliveries': [ { 'sfn_execution_id': _AWAITED_SFN, 'version_id': 'USESK1315719', 'datetime': '2025-07-08T05:51:07.750132Z' } ], 'awaited_resolver': lambda acks: None, 'awaited_as_missing_resolver': lambda acks: missing_resolver_calls.extend(acks), } result = handler(None, {}, dependencies) assert result['awaited'] > 0 assert result['missing'] == 0 assert len(missing_resolver_calls) == 0 @patch('src.common.ack_processor.processor.config') def test_auto_retry_within_threshold_treated_as_awaited(mock_config): """An auto-retry error within MISSING_HOURS_THRESHOLD is treated as awaited, not error.""" mock_config.LIMIT = 1000 mock_config.MISSING_HOURS_THRESHOLD = 999999 # cutoff far in the past — all deliveries are within mock_config.AUTO_RETRY_PATTERNS = ['please wait for automatic retry'] error_resolver_calls = [] missing_resolver_calls = [] dependencies = { 'ack_storage': LocalStorage(), 'awaited_deliveries': [_AUTO_RETRY_DELIVERY], 'awaited_resolver': lambda acks: error_resolver_calls.extend(acks), 'awaited_as_missing_resolver': lambda acks: missing_resolver_calls.extend(acks), } result = handler(None, {}, dependencies) assert result['errors'] == 0 assert result['awaited'] == 1 assert result['missing'] == 0 assert len(error_resolver_calls) == 0 assert len(missing_resolver_calls) == 0 @patch('src.common.ack_processor.processor.config') def test_auto_retry_past_threshold_treated_as_error(mock_config): """An auto-retry error past MISSING_HOURS_THRESHOLD is treated as a real error.""" mock_config.LIMIT = 1000 mock_config.MISSING_HOURS_THRESHOLD = 0 # cutoff = now — all 2025 deliveries are past it mock_config.AUTO_RETRY_PATTERNS = ['please wait for automatic retry'] error_resolver_calls = [] dependencies = { 'ack_storage': LocalStorage(), 'awaited_deliveries': [_AUTO_RETRY_DELIVERY], 'awaited_resolver': lambda acks: error_resolver_calls.extend(acks), 'awaited_as_missing_resolver': lambda acks: None, } result = handler(None, {}, dependencies) assert result['errors'] == 1 assert result['awaited'] == 0 assert len(error_resolver_calls) == 1 assert error_resolver_calls[0]['version_id'] == 'USESK1315720'