ForcePilot/backend/test/unit/channels/test_zalo_user_gateway.py
Kris 3264900bc9 test: 新增多渠道单元测试用例并配置测试环境变量
新增了Twitch、Telegram、Discord、Slack、Mattermost、WeChat、Zalo等多渠道的单元测试用例,覆盖了令牌处理、速率限制、消息去重、会话解析、格式转换、安全策略等模块
同时在测试配置中添加了测试用的OpenAI API密钥环境变量
2026-05-12 00:56:47 +08:00

179 lines
5.5 KiB
Python

from __future__ import annotations
import pytest
from yuxi.channels.adapters.zalo_user.gateway import ZaloGateway, GatewayContext, get_zalo_gateway
class FakeBridge:
base_url = "http://fake:5556"
_started = False
async def start(self):
self._started = True
async def stop(self):
self._started = False
async def start_qr_login(self):
return {"qr_url": "http://qr.example.com", "qr_id": "qr_001", "expires_in": 120}
async def check_login_status(self, qr_id=""):
return {"status": "success", "logged_in": True}
async def check_raw_login_status(self):
return {"logged_in": True}
def get_websocket_url(self):
return "ws://fake:5556/ws"
class FakeBridgeDelayLogin:
base_url = "http://fake:5556"
_started = False
async def start(self):
self._started = True
async def stop(self):
self._started = False
async def start_qr_login(self):
return {"qr_url": "http://qr.example.com", "qr_id": "qr_002", "expires_in": 5}
async def check_login_status(self, qr_id=""):
return {"status": "pending"}
async def check_raw_login_status(self):
return {"logged_in": False}
def get_websocket_url(self):
return "ws://fake:5556/ws"
class TestZaloGateway:
@pytest.fixture
def gateway(self):
gw = ZaloGateway()
yield gw
def test_singleton(self):
gw1 = get_zalo_gateway()
gw2 = get_zalo_gateway()
assert gw1 is gw2
@pytest.mark.asyncio
async def test_start_account(self):
gw = ZaloGateway()
config = {"bridge_url": "http://test:5556", "profile": "test"}
ctx = await gw.start_account("test", config)
assert isinstance(ctx, GatewayContext)
assert ctx.bridge_url == "http://test:5556"
assert "test" in gw.list_accounts()
@pytest.mark.asyncio
async def test_start_duplicate_account(self):
gw = ZaloGateway()
config = {"bridge_url": "http://test:5556"}
ctx1 = await gw.start_account("dup", config)
ctx2 = await gw.start_account("dup", config)
assert ctx1 is ctx2
@pytest.mark.asyncio
async def test_list_accounts(self):
gw = ZaloGateway()
config = {"bridge_url": "http://test:5556"}
await gw.start_account("a", config)
await gw.start_account("b", config)
accounts = gw.list_accounts()
assert sorted(accounts) == ["a", "b"]
@pytest.mark.asyncio
async def test_logout_account(self):
gw = ZaloGateway()
config = {"bridge_url": "http://test:5556"}
await gw.start_account("test_logout", config)
result = await gw.logout_account("test_logout")
assert result["status"] == "logged_out"
assert "test_logout" not in gw.list_accounts()
@pytest.mark.asyncio
async def test_logout_nonexistent(self):
gw = ZaloGateway()
result = await gw.logout_account("nonexistent")
assert result["status"] == "not_found"
@pytest.mark.asyncio
async def test_login_qr_start_not_started(self):
gw = ZaloGateway()
with pytest.raises(ValueError, match="not started"):
await gw.login_with_qr_start("nonexistent")
@pytest.mark.asyncio
async def test_login_qr_wait_not_started(self):
gw = ZaloGateway()
with pytest.raises(ValueError, match="not started"):
await gw.login_with_qr_wait("nonexistent")
@pytest.mark.asyncio
async def test_login_qr_start(self):
gw = ZaloGateway()
config = {"bridge_url": "http://test:5556"}
await gw.start_account("qr_test", config)
ctx = gw._accounts["qr_test"]
fake_bridge = FakeBridge()
ctx.bridge = fake_bridge
ctx.login_flow._bridge = fake_bridge
result = await gw.login_with_qr_start("qr_test")
assert result["qr_url"] == "http://qr.example.com"
assert result["qr_id"] == "qr_001"
@pytest.mark.asyncio
async def test_login_qr_wait_success(self):
gw = ZaloGateway()
config = {"bridge_url": "http://test:5556"}
await gw.start_account("qr_wait", config)
ctx = gw._accounts["qr_wait"]
fake_bridge = FakeBridge()
ctx.bridge = fake_bridge
ctx.login_flow._bridge = fake_bridge
result = await gw.login_with_qr_wait("qr_wait")
assert result["logged_in"] is True
@pytest.mark.asyncio
async def test_login_qr_wait_timeout(self):
gw = ZaloGateway()
config = {"bridge_url": "http://test:5556"}
await gw.start_account("qr_timeout", config)
ctx = gw._accounts["qr_timeout"]
fake_bridge = FakeBridgeDelayLogin()
ctx.bridge = fake_bridge
ctx.login_flow._bridge = fake_bridge
result = await gw.login_with_qr_wait("qr_timeout", poll_interval=0.5, timeout=1.0)
assert result["logged_in"] is False
assert result["status"] == "error"
@pytest.mark.asyncio
async def test_shutdown(self):
gw = ZaloGateway()
config = {"bridge_url": "http://test:5556"}
await gw.start_account("s1", config)
await gw.start_account("s2", config)
await gw.shutdown()
assert len(gw.list_accounts()) == 0
@pytest.mark.asyncio
async def test_gateway_context_defaults(self):
ctx = GatewayContext(
bridge_url="http://test:5556",
config={"profile": "default"},
)
assert ctx.bridge is None
assert ctx.login_flow is None
assert ctx.bridge_url == "http://test:5556"