|
1 | 1 | """Tests for background task management.""" |
2 | 2 |
|
| 3 | +import queue |
3 | 4 | import threading |
4 | 5 | import time |
5 | 6 | import unittest |
| 7 | +import unittest.mock |
6 | 8 |
|
7 | 9 | from vulcano.app.background import ( |
8 | 10 | BackgroundTaskManager, |
@@ -244,6 +246,57 @@ def worker(): |
244 | 246 | self.assertEqual(len(results), 1) |
245 | 247 | self.assertEqual(results[0], "done") |
246 | 248 |
|
| 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 | + |
247 | 300 |
|
248 | 301 | if __name__ == "__main__": |
249 | 302 | unittest.main() |
0 commit comments