Files
hermes-agent/tests/plugins/test_discord_runtime_failure.py
2026-06-14 14:30:48 -04:00

60 lines
2.0 KiB
Python

import asyncio
from unittest.mock import AsyncMock
import pytest
from gateway.config import PlatformConfig
from plugins.platforms.discord.adapter import DiscordAdapter
@pytest.mark.asyncio
async def test_discord_bot_task_runtime_exit_notifies_gateway_for_reconnect(monkeypatch):
"""A post-ready discord.py websocket task crash must not leave the gateway split-brained.
Regression: producers stayed systemd-active while Discord stopped responding after
a runtime ClientOSError/ConnectionResetError. The adapter must mark Discord as a
retryable fatal platform error and notify the gateway supervisor so the existing
reconnect watcher can replace the dead adapter.
"""
adapter = DiscordAdapter(PlatformConfig(enabled=True, token="token"))
adapter._running = True
adapter._ready_event.set()
adapter._notify_fatal_error = AsyncMock()
async def crash():
raise ConnectionResetError("Cannot write to closing transport")
task = asyncio.create_task(crash())
await asyncio.sleep(0)
adapter._handle_bot_task_done(task)
await asyncio.sleep(0)
assert adapter.has_fatal_error is True
assert adapter.fatal_error_retryable is True
assert adapter.fatal_error_code == "discord_gateway_task_exited"
assert adapter.fatal_error_message is not None
assert "Cannot write to closing transport" in adapter.fatal_error_message
adapter._notify_fatal_error.assert_awaited_once()
@pytest.mark.asyncio
async def test_discord_bot_task_done_ignored_during_intentional_disconnect():
adapter = DiscordAdapter(PlatformConfig(enabled=True, token="token"))
adapter._running = True
adapter._ready_event.set()
adapter._disconnecting = True
adapter._notify_fatal_error = AsyncMock()
async def stop_cleanly():
return None
task = asyncio.create_task(stop_cleanly())
await asyncio.sleep(0)
adapter._handle_bot_task_done(task)
await asyncio.sleep(0)
assert adapter.has_fatal_error is False
adapter._notify_fatal_error.assert_not_awaited()