@@ -228,3 +228,103 @@ def test_start_time_initialization_in_context(self):
228228 with spinner :
229229 assert spinner .start_time is not None
230230 assert isinstance (spinner .start_time , datetime )
231+
232+ def test_throttling_first_update_logged (self , caplog ):
233+ """Test that the first update is always logged when console is not available."""
234+ with patch .object (LeaseAcquisitionSpinner , '_is_terminal_available' , return_value = False ):
235+ spinner = LeaseAcquisitionSpinner ("test-lease" )
236+ spinner .start_time = datetime .now ()
237+
238+ with caplog .at_level (logging .INFO ):
239+ spinner .update_status ("First message" )
240+
241+ assert "First message" in caplog .text
242+ assert spinner ._last_log_time is not None
243+
244+ def test_throttling_second_update_within_interval_not_logged (self , caplog ):
245+ """Test that updates within 5 minutes are not logged."""
246+ with patch .object (LeaseAcquisitionSpinner , '_is_terminal_available' , return_value = False ):
247+ spinner = LeaseAcquisitionSpinner ("test-lease" )
248+ spinner .start_time = datetime .now ()
249+ spinner ._last_log_time = datetime .now () - timedelta (minutes = 2 ) # 2 minutes ago
250+
251+ with caplog .at_level (logging .INFO ):
252+ spinner .update_status ("Second message" )
253+
254+ # Should not log because only 2 minutes have passed
255+ assert "Second message" not in caplog .text
256+
257+ def test_throttling_update_after_interval_logged (self , caplog ):
258+ """Test that updates after 5 minutes are logged."""
259+ with patch .object (LeaseAcquisitionSpinner , '_is_terminal_available' , return_value = False ):
260+ spinner = LeaseAcquisitionSpinner ("test-lease" )
261+ spinner .start_time = datetime .now ()
262+ spinner ._last_log_time = datetime .now () - timedelta (minutes = 6 ) # 6 minutes ago
263+
264+ with caplog .at_level (logging .INFO ):
265+ spinner .update_status ("After interval message" )
266+
267+ assert "After interval message" in caplog .text
268+ assert spinner ._last_log_time is not None
269+
270+ def test_throttling_forced_update_always_logged (self , caplog ):
271+ """Test that forced updates are always logged regardless of throttle interval."""
272+ with patch .object (LeaseAcquisitionSpinner , '_is_terminal_available' , return_value = False ):
273+ spinner = LeaseAcquisitionSpinner ("test-lease" )
274+ spinner .start_time = datetime .now ()
275+ spinner ._last_log_time = datetime .now () - timedelta (minutes = 1 ) # 1 minute ago
276+
277+ with caplog .at_level (logging .INFO ):
278+ spinner .update_status ("Forced message" , force = True )
279+
280+ assert "Forced message" in caplog .text
281+ assert spinner ._last_log_time is not None
282+
283+ def test_throttling_multiple_updates_only_logs_when_needed (self , caplog ):
284+ """Test that multiple rapid updates only log at appropriate intervals."""
285+ with patch .object (LeaseAcquisitionSpinner , '_is_terminal_available' , return_value = False ):
286+ spinner = LeaseAcquisitionSpinner ("test-lease" )
287+ spinner .start_time = datetime .now ()
288+
289+ with caplog .at_level (logging .INFO ):
290+ # First update should be logged
291+ spinner .update_status ("Message 1" )
292+ assert "Message 1" in caplog .text
293+
294+ # Set last log time to recent
295+ spinner ._last_log_time = datetime .now () - timedelta (minutes = 1 )
296+
297+ # Second update should not be logged (within interval)
298+ spinner .update_status ("Message 2" )
299+ assert "Message 2" not in caplog .text
300+
301+ # Third update should not be logged (within interval)
302+ spinner .update_status ("Message 3" )
303+ assert "Message 3" not in caplog .text
304+
305+ # Set last log time to past the interval
306+ spinner ._last_log_time = datetime .now () - timedelta (minutes = 6 )
307+
308+ # Fourth update should be logged (past interval)
309+ spinner .update_status ("Message 4" )
310+ assert "Message 4" in caplog .text
311+
312+ def test_throttling_not_applied_when_console_available (self ):
313+ """Test that throttling is not applied when console is available."""
314+ with patch .object (LeaseAcquisitionSpinner , '_is_terminal_available' , return_value = True ):
315+ spinner = LeaseAcquisitionSpinner ("test-lease" )
316+ spinner .start_time = datetime .now ()
317+
318+ mock_spinner = Mock ()
319+ spinner .spinner = mock_spinner
320+
321+ # Multiple updates should all call update() regardless of throttle
322+ spinner .update_status ("Message 1" )
323+ spinner .update_status ("Message 2" )
324+ spinner .update_status ("Message 3" )
325+
326+ # All should be called even if we set a recent last_log_time
327+ spinner ._last_log_time = datetime .now () - timedelta (minutes = 1 )
328+ spinner .update_status ("Message 4" )
329+
330+ assert mock_spinner .update .call_count == 4
0 commit comments