Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions gateway/platforms/qqbot/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,14 @@ def enforces_own_access_policy(self) -> bool:
# Connection lifecycle
# ------------------------------------------------------------------

async def connect(self) -> bool:
"""Authenticate, obtain gateway URL, and open the WebSocket."""
async def connect(self, *, is_reconnect: bool = False) -> bool:
"""Authenticate, obtain gateway URL, and open the WebSocket.

``is_reconnect`` is part of the BasePlatformAdapter.connect contract:
the gateway's reconnect loop calls ``connect(is_reconnect=True)``. The
QQ adapter establishes a fresh WebSocket session either way, so the
flag is accepted for signature compatibility but not otherwise used.
"""
if not AIOHTTP_AVAILABLE:
message = "QQ startup failed: aiohttp not installed"
self._set_fatal_error("qq_missing_dependency", message, retryable=True)
Expand Down
25 changes: 25 additions & 0 deletions tests/gateway/test_qqbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,31 @@ def test_connect_uses_redirect_guard_hook(self):
assert kwargs.get("follow_redirects") is True
assert kwargs.get("event_hooks", {}).get("response") == [_ssrf_redirect_guard]

def test_connect_accepts_is_reconnect_kwarg(self):
"""The gateway reconnect loop calls ``connect(is_reconnect=True)``.

BasePlatformAdapter.connect declares ``is_reconnect`` as a keyword
argument and gateway.run forwards it on every reconnect attempt, so
every adapter must accept it. Regression test for a TypeError
("unexpected keyword argument 'is_reconnect'") that broke QQ
reconnection entirely.
"""
import inspect
from gateway.platforms.qqbot import QQAdapter

sig = inspect.signature(QQAdapter.connect)
assert "is_reconnect" in sig.parameters

client = mock.AsyncMock()
with mock.patch("gateway.platforms.qqbot.adapter.httpx.AsyncClient", return_value=client):
adapter = QQAdapter(_make_config(app_id="a", client_secret="b"))
adapter._ensure_token = mock.AsyncMock(side_effect=RuntimeError("stop after client creation"))

# Must not raise TypeError on the reconnect call path.
connected = asyncio.run(adapter.connect(is_reconnect=True))

assert connected is False


# ---------------------------------------------------------------------------
# WebSocket proxy handling
Expand Down