b4fbd6fe9f
Deploy Site / deploy-vercel (push) Has been skipped
Deploy Site / deploy-docs (push) Has been skipped
Build Skills Index / build-index (push) Has been skipped
Build Skills Index / trigger-deploy (push) Waiting to run
CI / Deny unrelated histories (push) Has been skipped
CI / CI timing report (push) Blocked by required conditions
CI / Detect affected areas (push) Successful in 27m35s
CI / OSV scan (push) Failing after 4s
CI / Build&Test Docker image (push) Successful in 9s
CI / Supply-chain scan (push) Has been skipped
CI / Lint Docker scripts (push) Failing after 5m13s
CI / Check contributors (push) Failing after 12m8s
CI / Docs Site (push) Failing after 12m8s
CI / TypeScript (push) Failing after 12m8s
CI / Python lints (push) Failing after 12m9s
CI / Python tests (push) Failing after 12m9s
CI / Check uv.lock (push) Failing after 23m22s
CI / All required checks pass (push) Waiting to run
60 lines
2.0 KiB
Python
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()
|