Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
"""Tests for WeChat iLink typing ticket refresh logic (issue #38085)."""
|
||||
|
||||
import asyncio
|
||||
import time
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def weixin_adapter():
|
||||
"""Create a minimal WeixinAdapter with mocked internals for typing tests."""
|
||||
from gateway.platforms.weixin import WeixinAdapter, TypingTicketCache
|
||||
|
||||
config = MagicMock()
|
||||
config.extra = {"account_id": "test-account"}
|
||||
config.name = "weixin"
|
||||
|
||||
with patch.object(WeixinAdapter, "__init__", lambda self, cfg: None):
|
||||
adapter = WeixinAdapter.__new__(WeixinAdapter)
|
||||
adapter._send_session = AsyncMock()
|
||||
adapter._token = "test-token"
|
||||
adapter._base_url = "https://ilinkai.weixin.qq.com"
|
||||
adapter._account_id = "test-account"
|
||||
adapter._typing_cache = TypingTicketCache(ttl_seconds=600.0)
|
||||
adapter._token_store = MagicMock()
|
||||
adapter._token_store.get.return_value = None # no stored context_token
|
||||
adapter.platform = MagicMock()
|
||||
mock_value = MagicMock()
|
||||
mock_value.title.return_value = "Weixin"
|
||||
adapter.platform.value = mock_value
|
||||
|
||||
return adapter
|
||||
|
||||
|
||||
class TestEnsureTypingTicket:
|
||||
"""Tests for _ensure_typing_ticket — the fix for stuck typing indicator."""
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_refreshes_when_ticket_expired(self, weixin_adapter):
|
||||
"""When the cached ticket has expired, fetch a new one via getConfig."""
|
||||
# Insert an expired ticket directly (bypass TTL check)
|
||||
weixin_adapter._typing_cache._cache["user-123"] = (
|
||||
"old-ticket",
|
||||
time.time() - 601, # expired (TTL is 600s)
|
||||
)
|
||||
|
||||
mock_response = {"typing_ticket": "fresh-ticket-xyz"}
|
||||
with patch("gateway.platforms.weixin._get_config", new_callable=AsyncMock) as mock_get:
|
||||
mock_get.return_value = mock_response
|
||||
ticket = await weixin_adapter._ensure_typing_ticket("user-123")
|
||||
|
||||
assert ticket == "fresh-ticket-xyz"
|
||||
mock_get.assert_called_once_with(
|
||||
weixin_adapter._send_session,
|
||||
base_url=weixin_adapter._base_url,
|
||||
token=weixin_adapter._token,
|
||||
user_id="user-123",
|
||||
context_token=None,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_uses_stored_context_token_when_available(self, weixin_adapter):
|
||||
"""Pass the stored context_token to getConfig when available."""
|
||||
weixin_adapter._token_store.get.return_value = "stored-ctx-token"
|
||||
|
||||
mock_response = {"typing_ticket": "ticket-with-ctx"}
|
||||
with patch("gateway.platforms.weixin._get_config", new_callable=AsyncMock) as mock_get:
|
||||
mock_get.return_value = mock_response
|
||||
ticket = await weixin_adapter._ensure_typing_ticket("user-789")
|
||||
|
||||
assert ticket == "ticket-with-ctx"
|
||||
mock_get.assert_called_once_with(
|
||||
weixin_adapter._send_session,
|
||||
base_url=weixin_adapter._base_url,
|
||||
token=weixin_adapter._token,
|
||||
user_id="user-789",
|
||||
context_token="stored-ctx-token",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_returns_none_when_getconfig_fails(self, weixin_adapter):
|
||||
"""Return None when getConfig raises an exception."""
|
||||
with patch("gateway.platforms.weixin._get_config", new_callable=AsyncMock) as mock_get:
|
||||
mock_get.side_effect = Exception("network error")
|
||||
ticket = await weixin_adapter._ensure_typing_ticket("user-123")
|
||||
|
||||
assert ticket is None
|
||||
|
||||
|
||||
class TestTypingTicketCache:
|
||||
"""Tests for the TypingTicketCache TTL logic."""
|
||||
|
||||
def test_returns_ticket_when_fresh(self):
|
||||
from gateway.platforms.weixin import TypingTicketCache
|
||||
cache = TypingTicketCache(ttl_seconds=600.0)
|
||||
cache.set("user-1", "ticket-1")
|
||||
assert cache.get("user-1") == "ticket-1"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user