From c040b0e4ae1d2b241898402bfeb95cc1c8cc8af5 Mon Sep 17 00:00:00 2001 From: Teknium Date: Tue, 7 Apr 2026 12:32:23 -0700 Subject: [PATCH] =?UTF-8?q?test:=20add=20unit=20tests=20for=20media=20help?= =?UTF-8?q?er=20=E2=80=94=20video,=20document,=20multi-file,=20failure=20i?= =?UTF-8?q?solation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapted from PR #5679 (0xbyt4) to cover edge cases not in the integration tests: video routing, unknown extension fallback to send_document, multi-file delivery, and single-failure isolation. --- tests/cron/test_scheduler.py | 56 +++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/tests/cron/test_scheduler.py b/tests/cron/test_scheduler.py index baa6be9de..4a15fa223 100644 --- a/tests/cron/test_scheduler.py +++ b/tests/cron/test_scheduler.py @@ -7,7 +7,7 @@ from unittest.mock import AsyncMock, patch, MagicMock import pytest -from cron.scheduler import _resolve_origin, _resolve_delivery_target, _deliver_result, run_job, SILENT_MARKER, _build_job_prompt +from cron.scheduler import _resolve_origin, _resolve_delivery_target, _deliver_result, _send_media_via_adapter, run_job, SILENT_MARKER, _build_job_prompt class TestResolveOrigin: @@ -1044,3 +1044,57 @@ class TestTickAdvanceBeforeRun: adv_mock.assert_called_once_with("test-advance") # advance must happen before run assert call_order == [("advance", "test-advance"), ("run", "test-advance")] + + +class TestSendMediaViaAdapter: + """Unit tests for _send_media_via_adapter — routes files to typed adapter methods.""" + + @staticmethod + def _run_with_loop(adapter, chat_id, media_files, metadata, job): + """Helper: run _send_media_via_adapter with a real running event loop.""" + import asyncio + import threading + + loop = asyncio.new_event_loop() + t = threading.Thread(target=loop.run_forever, daemon=True) + t.start() + try: + _send_media_via_adapter(adapter, chat_id, media_files, metadata, loop, job) + finally: + loop.call_soon_threadsafe(loop.stop) + t.join(timeout=5) + loop.close() + + def test_video_dispatched_to_send_video(self): + adapter = MagicMock() + adapter.send_video = AsyncMock() + media_files = [("/tmp/clip.mp4", False)] + self._run_with_loop(adapter, "123", media_files, None, {"id": "j1"}) + adapter.send_video.assert_called_once() + assert adapter.send_video.call_args[1]["video_path"] == "/tmp/clip.mp4" + + def test_unknown_ext_dispatched_to_send_document(self): + adapter = MagicMock() + adapter.send_document = AsyncMock() + media_files = [("/tmp/report.pdf", False)] + self._run_with_loop(adapter, "123", media_files, None, {"id": "j2"}) + adapter.send_document.assert_called_once() + assert adapter.send_document.call_args[1]["file_path"] == "/tmp/report.pdf" + + def test_multiple_media_files_all_delivered(self): + adapter = MagicMock() + adapter.send_voice = AsyncMock() + adapter.send_image_file = AsyncMock() + media_files = [("/tmp/voice.mp3", False), ("/tmp/photo.jpg", False)] + self._run_with_loop(adapter, "123", media_files, None, {"id": "j3"}) + adapter.send_voice.assert_called_once() + adapter.send_image_file.assert_called_once() + + def test_single_failure_does_not_block_others(self): + adapter = MagicMock() + adapter.send_voice = AsyncMock(side_effect=RuntimeError("network error")) + adapter.send_image_file = AsyncMock() + media_files = [("/tmp/voice.ogg", False), ("/tmp/photo.png", False)] + self._run_with_loop(adapter, "123", media_files, None, {"id": "j4"}) + adapter.send_voice.assert_called_once() + adapter.send_image_file.assert_called_once()