Skip to content

Commit ce23229

Browse files
test: cover background output manager edge cases
1 parent 9c09400 commit ce23229

2 files changed

Lines changed: 87 additions & 0 deletions

File tree

vulcano/app/background_test.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
"""Tests for background task management."""
22

3+
import queue
34
import threading
45
import time
56
import unittest
7+
import unittest.mock
68

79
from vulcano.app.background import (
810
BackgroundTaskManager,
@@ -244,6 +246,57 @@ def worker():
244246
self.assertEqual(len(results), 1)
245247
self.assertEqual(results[0], "done")
246248

249+
def test_mark_completed_triggers_ui_invalidate_callback(self):
250+
"""Completing a task invalidates the UI when callback is configured."""
251+
252+
callback = unittest.mock.MagicMock()
253+
self.manager.set_ui_invalidate_callback(callback)
254+
thread = threading.Thread(target=lambda: None)
255+
task_id = self.manager.register_task("task", thread)
256+
257+
self.manager.mark_completed(task_id)
258+
259+
callback.assert_called_once()
260+
261+
def test_mark_failed_triggers_ui_invalidate_callback(self):
262+
"""Failing a task invalidates the UI when callback is configured."""
263+
264+
callback = unittest.mock.MagicMock()
265+
self.manager.set_ui_invalidate_callback(callback)
266+
thread = threading.Thread(target=lambda: None)
267+
task_id = self.manager.register_task("task", thread)
268+
269+
self.manager.mark_failed(task_id, RuntimeError("boom"))
270+
271+
callback.assert_called_once()
272+
273+
def test_enqueue_output_triggers_ui_invalidate_callback(self):
274+
"""Enqueuing output invalidates the UI when callback is configured."""
275+
276+
callback = unittest.mock.MagicMock()
277+
self.manager.set_ui_invalidate_callback(callback)
278+
279+
self.manager.enqueue_output("task_0", "hello")
280+
281+
callback.assert_called_once()
282+
283+
def test_get_queued_output_handles_empty_race(self):
284+
"""Queue empty races are handled gracefully."""
285+
286+
class RaceQueue(object):
287+
def empty(self):
288+
return False
289+
290+
def get_nowait(self):
291+
raise queue.Empty
292+
293+
original_queue = self.manager._output_queue
294+
self.manager._output_queue = RaceQueue()
295+
try:
296+
self.assertEqual(self.manager.get_queued_output(), [])
297+
finally:
298+
self.manager._output_queue = original_queue
299+
247300

248301
if __name__ == "__main__":
249302
unittest.main()

vulcano/app/classes_test.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,3 +655,37 @@ def queue_output():
655655
"task_0" in call and "test message" in call for call in print_calls
656656
)
657657
self.assertTrue(found_message)
658+
659+
@patch(print_builtin)
660+
@patch("vulcano.app.classes.print_formatted_text")
661+
@patch("vulcano.app.classes.sys")
662+
def test_display_background_output_falls_back_to_print(
663+
self, sys_mock, prompt_print_mock, print_mock
664+
):
665+
"""Prompt-toolkit print failures fall back to plain print."""
666+
sys_mock.argv = ["ensure_no_repl", "noop"]
667+
app = VulcanoApp()
668+
app.background_tasks.enqueue_output("task_0", "hello")
669+
prompt_print_mock.side_effect = RuntimeError("not in prompt")
670+
671+
app._display_background_output(use_prompt_toolkit=True)
672+
673+
print_mock.assert_called_with("[task_0] hello")
674+
675+
@patch("vulcano.app.classes.threading.Thread")
676+
@patch("vulcano.app.classes.sys")
677+
def test_cli_mode_skips_wait_when_no_background_tasks(self, sys_mock, thread_mock):
678+
"""CLI mode does not wait when there are no active background tasks."""
679+
sys_mock.argv = ["ensure_no_repl", "noop"]
680+
app = VulcanoApp()
681+
app.background_tasks.wait_for_all_tasks = MagicMock()
682+
683+
@app.command()
684+
def noop():
685+
return "ok"
686+
687+
app.run(print_result=False)
688+
689+
app.background_tasks.wait_for_all_tasks.assert_not_called()
690+
thread_mock.return_value.start.assert_called_once()
691+
thread_mock.return_value.join.assert_called_once_with(timeout=1.0)

0 commit comments

Comments
 (0)