"""Test decorators.""" from unittest.mock import call, patch import pytest from feed_ingestion.util.decorators import retry def test_retry_rethrow_last_exception(): """Test retry exceed tries should re-raise last exception.""" @retry(max_attempts=3, initial_delay=1, delay_multiplier=2) def target_function(): raise ValueError() with patch('time.sleep') as time_sleep_mock: with pytest.raises(ValueError): target_function() assert time_sleep_mock.call_count == 2 assert time_sleep_mock.call_args_list == [ call(1), call(2) ] def test_retry_pass(): """Test retry without exception.""" @retry(max_attempts=3, initial_delay=1, delay_multiplier=2) def target_function(): return 10 with patch('time.sleep') as time_sleep_mock: assert target_function() == 10 assert not time_sleep_mock.called def test_retry_pass_exception(): """Test retry when passing non-retryable exception.""" @retry(retry_on_exception=ValueError) def target_function(): return 1 / 0 with patch('time.sleep') as time_sleep_mock: with pytest.raises(ZeroDivisionError): target_function() assert not time_sleep_mock.called def test_retry_second_attempt(): """Test retry when target function success on 2nd attempt.""" attempt = 0 @retry(max_attempts=3, initial_delay=1, delay_multiplier=2) def target_function(): nonlocal attempt attempt += 1 if attempt > 1: return 11 else: raise ValueError() with patch('time.sleep') as time_sleep_mock: assert target_function() == 11 assert time_sleep_mock.call_count == 1 assert time_sleep_mock.call_args_list == [ call(1) ]