import asyncio import os import sys from pathlib import Path from types import SimpleNamespace sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) import discord import bot class FakeChannel: def __init__(self, failures_before_success=0, channel_id=999): self.failures_before_success = failures_before_success self.messages = [] self.attempts = 0 self.id = channel_id async def send(self, text): self.attempts += 1 if self.attempts <= self.failures_before_success: response = SimpleNamespace(status=403, reason="Forbidden") raise discord.Forbidden(response, {"message": "Missing Permissions", "code": 50013}) self.messages.append(text) def test_safe_send_chunked_falls_back_to_secondary_channel(): async def run(): primary = FakeChannel(failures_before_success=1, channel_id=100) fallback = FakeChannel(channel_id=200) delivered = await bot.safe_send_chunked( primary, "hello world", fallback_channels=[fallback], purpose="test notification", ) return delivered, fallback.messages delivered, messages = asyncio.run(run()) assert messages == ["hello world"] assert delivered is not None def test_safe_send_chunked_returns_none_when_all_channels_fail(): async def run(): primary = FakeChannel(failures_before_success=10, channel_id=100) fallback = FakeChannel(failures_before_success=10, channel_id=200) return await bot.safe_send_chunked( primary, "hello world", fallback_channels=[fallback], purpose="test notification", ) assert asyncio.run(run()) is None def test_build_retry_notice_mentions_reason_and_path(): message = bot.build_retry_notice( file_path=str(Path("recordings") / "1" / "session" / "meeting.wav"), reason="OpenRouter 502", ) assert "OpenRouter 502" in message assert "meeting.wav" in message assert "`/retry`" in message