@@ -148,3 +148,96 @@ def test_flush_only_if_buffer_has_content(notify_mock, monkeypatch):
148148
149149 # Now send_notification should be called
150150 mock_send .assert_called_once ()
151+
152+
153+ def test_periodic_flush_stops_on_event_set (mocker ):
154+ """Test that periodic_flush exits when stop_event is set."""
155+ appriser = Appriser ()
156+
157+ # Pre-set the stop event before calling _periodic_flush
158+ appriser ._stop_event .set ()
159+
160+ # Add a log message to ensure buffer has content
161+ logger .error ("Test message" )
162+
163+ # Mock send_notification to track calls
164+ mock_send = mocker .patch .object (appriser , "send_notification" )
165+
166+ # Run the periodic flush - it should exit immediately
167+ appriser ._periodic_flush ()
168+
169+ # Verify send_notification was not called
170+ mock_send .assert_not_called ()
171+
172+ # Verify message still in buffer (didn't get cleared)
173+ assert len (appriser .buffer ) == 1
174+ assert "Test message" in appriser .buffer [0 ].record ["message" ]
175+
176+
177+ def test_periodic_flush_empty_buffer (mocker ):
178+ """Test that periodic_flush skips sending when buffer is empty."""
179+ appriser = Appriser ()
180+
181+ # Clear buffer
182+ appriser .buffer .clear ()
183+
184+ # Mock send_notification to track calls
185+ mock_send = mocker .patch .object (appriser , "send_notification" )
186+
187+ # Set up stop_event to trigger after a short delay
188+ def set_stop_after_delay ():
189+ time .sleep (0.1 ) # Short delay
190+ appriser ._stop_event .set ()
191+
192+ # Start a thread that will set the stop event after a delay
193+ thread = threading .Thread (target = set_stop_after_delay )
194+ thread .start ()
195+
196+ # Run periodic flush - it should wait until stop_event is set
197+ appriser ._periodic_flush ()
198+
199+ # Wait for our helper thread to complete
200+ thread .join ()
201+
202+ # Verify send_notification was not called since buffer was empty
203+ mock_send .assert_not_called ()
204+
205+
206+ def test_stop_periodic_flush_idempotent (mocker ):
207+ """Test that calling stop_periodic_flush twice is safe."""
208+ appriser = Appriser ()
209+
210+ # First call
211+ appriser .stop_periodic_flush ()
212+ assert appriser ._stop_event .is_set ()
213+
214+ # Mock thread for second call
215+ mock_thread = mocker .MagicMock ()
216+ mock_thread .is_alive .return_value = True
217+ appriser ._flush_thread = mock_thread
218+ appriser ._stop_event .clear () # Reset to test second call
219+
220+ # Second call
221+ appriser .stop_periodic_flush ()
222+
223+ # Verify stop_event is set and join was called
224+ assert appriser ._stop_event .is_set ()
225+ mock_thread .join .assert_called_once ()
226+
227+
228+ def test_notify_failure_preserves_buffer (mocker ):
229+ """Test that buffer is not cleared when notification fails."""
230+ appriser = Appriser ()
231+
232+ # Mock apprise_obj.notify to return False (failure)
233+ mocker .patch .object (appriser .apprise_obj , "notify" , return_value = False )
234+
235+ # Add test message to buffer
236+ logger .error ("Test message that should remain in buffer" )
237+
238+ # Try to send notification
239+ appriser .send_notification ()
240+
241+ # Verify buffer still contains the message
242+ assert len (appriser .buffer ) == 1
243+ assert "Test message that should remain in buffer" in appriser .buffer [0 ].record ["message" ]
0 commit comments