@@ -151,6 +151,62 @@ def _side_effect_timer() -> Generator[ConnectTimeout, None, None]:
151151 expected_sleep_times = [0.1 , 0.2 , 0.4 , 0.5 , 0.5 ]
152152 self .assertListEqual (sleep_times , expected_sleep_times )
153153
154+ def test_backoff_on_429_uses_ratelimit_header_capped (self ) -> None :
155+ """Test that 429 wait time is capped by max_wait_time."""
156+ sleep_times = []
157+
158+ def _side_effect_timer () -> Generator :
159+ t0 = time .time ()
160+ mock_429 = Mock ()
161+ mock_429 .status_code = 429
162+ mock_429 .headers = {"ratelimit" : '"api";r=0;t=1' } # Server says wait 1s
163+ yield mock_429
164+ t1 = time .time ()
165+ sleep_times .append (round (t1 - t0 , 1 ))
166+ t0 = t1
167+ mock_200 = Mock ()
168+ mock_200 .status_code = 200
169+ yield mock_200
170+
171+ self .mock_request .side_effect = _side_effect_timer ()
172+
173+ # max_wait_time=0.5 is less than t=1, so wait should be capped at 0.5
174+ response = http_backoff (
175+ "GET" , URL , base_wait_time = 0.1 , max_wait_time = 0.5 , max_retries = 3 , retry_on_status_codes = 429
176+ )
177+
178+ self .assertEqual (self .mock_request .call_count , 2 )
179+ self .assertEqual (sleep_times , [0.5 ]) # Capped at max_wait_time
180+ self .assertEqual (response .status_code , 200 )
181+
182+ def test_backoff_on_429_uses_ratelimit_header_not_capped (self ) -> None :
183+ """Test that 429 wait time uses full reset time when under max_wait_time."""
184+ sleep_times = []
185+
186+ def _side_effect_timer () -> Generator :
187+ t0 = time .time ()
188+ mock_429 = Mock ()
189+ mock_429 .status_code = 429
190+ mock_429 .headers = {"ratelimit" : '"api";r=0;t=1' } # Server says wait 1s
191+ yield mock_429
192+ t1 = time .time ()
193+ sleep_times .append (round (t1 - t0 , 1 ))
194+ t0 = t1
195+ mock_200 = Mock ()
196+ mock_200 .status_code = 200
197+ yield mock_200
198+
199+ self .mock_request .side_effect = _side_effect_timer ()
200+
201+ # max_wait_time=5 is greater than t=1, so wait should be full 1s
202+ response = http_backoff (
203+ "GET" , URL , base_wait_time = 0.1 , max_wait_time = 5.0 , max_retries = 3 , retry_on_status_codes = 429
204+ )
205+
206+ self .assertEqual (self .mock_request .call_count , 2 )
207+ self .assertEqual (sleep_times , [1.0 ]) # Full reset time (not capped)
208+ self .assertEqual (response .status_code , 200 )
209+
154210
155211class TestConfigureSession (unittest .TestCase ):
156212 def setUp (self ) -> None :
0 commit comments