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
12 changes: 10 additions & 2 deletions gateway/platforms/qqbot/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,16 @@ 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.

Accepts ``is_reconnect`` to match the ``PlatformAdapter.connect()``
contract (the gateway's reconnect watcher always forwards it). QQ keeps
its own server-side resume state (``_session_id`` / ``_last_seq``) and
has no separate update queue to preserve, so the flag is accepted and
ignored per the base-class note that adapters with no such queue may
ignore it.
"""
if not AIOHTTP_AVAILABLE:
message = "QQ startup failed: aiohttp not installed"
self._set_fatal_error("qq_missing_dependency", message, retryable=True)
Expand Down
37 changes: 37 additions & 0 deletions tests/gateway/test_qqbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2220,3 +2220,40 @@ def test_read_events_raises_when_ws_none(self):
adapter._ws = None
with pytest.raises(RuntimeError):
asyncio.run(adapter._read_events())


# ---------------------------------------------------------------------------
# QQAdapter.connect() signature contract (issue #54679)
# ---------------------------------------------------------------------------

class TestQQConnectIsReconnectKwarg:
"""The gateway reconnect watcher always calls
``adapter.connect(is_reconnect=...)`` via
``_connect_adapter_with_timeout``. QQAdapter.connect() must accept the
keyword to match the PlatformAdapter contract; before the fix its
signature was ``async def connect(self)`` and the reconnect call raised
``TypeError: connect() got an unexpected keyword argument 'is_reconnect'``
(QQ Bot failed to reconnect after a disconnect)."""

def _make_adapter(self, **extra):
from gateway.platforms.qqbot import QQAdapter
return QQAdapter(_make_config(app_id="a", client_secret="b", **extra))

def test_connect_signature_accepts_is_reconnect(self):
import inspect
from gateway.platforms.qqbot import QQAdapter
sig = inspect.signature(QQAdapter.connect)
assert "is_reconnect" in sig.parameters
param = sig.parameters["is_reconnect"]
# Keyword-only with a False default, matching PlatformAdapter.connect().
assert param.kind == inspect.Parameter.KEYWORD_ONLY
assert param.default is False

def test_connect_callable_with_is_reconnect_kwarg(self):
# Calling connect(is_reconnect=True) must not raise TypeError for the
# unexpected keyword. We force an early, dependency-style return so the
# call exercises only the signature/binding, not real networking.
adapter = self._make_adapter()
with mock.patch("gateway.platforms.qqbot.adapter.AIOHTTP_AVAILABLE", False):
result = asyncio.run(adapter.connect(is_reconnect=True))
assert result is False
Loading