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

217 lines
7.4 KiB
Python

from __future__ import annotations
import time
import pytest
from yuxi.channels.adapters.zalo_user.constants import ZaloCredentialStage
from yuxi.channels.adapters.zalo_user.credentials import CredentialManager, _compute_signature
class TestCredentialStageTransitions:
def test_initial_uninitialized(self):
mgr = CredentialManager()
assert mgr.stage == ZaloCredentialStage.UNINITIALIZED
assert mgr.is_authenticated is False
def test_mark_qr_pending(self):
mgr = CredentialManager()
mgr.mark_qr_pending("qr_test_123")
assert mgr.stage == ZaloCredentialStage.QR_PENDING
def test_mark_qr_scanned(self):
mgr = CredentialManager()
mgr.mark_qr_pending("qr_1")
mgr.mark_qr_scanned()
assert mgr.stage == ZaloCredentialStage.QR_SCANNED
def test_mark_qr_declined(self):
mgr = CredentialManager()
mgr.mark_qr_declined()
assert mgr.stage == ZaloCredentialStage.QR_DECLINED
assert mgr.error_message is not None
assert "declined" in mgr.error_message.lower()
def test_mark_qr_expired(self):
mgr = CredentialManager()
mgr.mark_qr_expired()
assert mgr.stage == ZaloCredentialStage.QR_EXPIRED
assert mgr.error_message is not None
assert "expired" in mgr.error_message.lower()
def test_mark_connected_no_data(self):
mgr = CredentialManager()
mgr.mark_connected()
assert mgr.stage == ZaloCredentialStage.CONNECTED
assert mgr.is_authenticated is True
def test_mark_connected_with_data(self):
mgr = CredentialManager()
mgr.mark_connected({"user_id": "123", "display_name": "Test"})
assert mgr.stage == ZaloCredentialStage.CONNECTED
assert mgr.credential_signature is not None
def test_mark_logged_out(self):
mgr = CredentialManager()
mgr.mark_connected({"user_id": "123"})
mgr.mark_logged_out()
assert mgr.stage == ZaloCredentialStage.LOGGED_OUT
assert mgr.is_authenticated is False
assert mgr.credential_signature is None
def test_mark_error(self):
mgr = CredentialManager()
mgr.mark_error("something went wrong")
assert mgr.stage == ZaloCredentialStage.ERROR
assert mgr.error_message == "something went wrong"
def test_full_lifecycle(self):
mgr = CredentialManager()
mgr.mark_qr_pending("qr_001")
assert mgr.stage == ZaloCredentialStage.QR_PENDING
mgr.mark_qr_scanned()
assert mgr.stage == ZaloCredentialStage.QR_SCANNED
mgr.mark_connected({"user_id": "u1"})
assert mgr.stage == ZaloCredentialStage.CONNECTED
mgr.mark_logged_out()
assert mgr.stage == ZaloCredentialStage.LOGGED_OUT
class TestCredentialSignature:
def test_no_signature_initially(self):
mgr = CredentialManager()
assert mgr.credential_signature is None
def test_signature_after_connect(self):
mgr = CredentialManager()
mgr.mark_connected({"user_id": "123"})
assert mgr.credential_signature is not None
def test_signature_cleared_on_logout(self):
mgr = CredentialManager()
mgr.mark_connected({"user_id": "123"})
mgr.mark_logged_out()
assert mgr.credential_signature is None
def test_same_data_same_signature(self):
sig1 = _compute_signature({"user_id": "123", "name": "A"})
sig2 = _compute_signature({"name": "A", "user_id": "123"})
assert sig1 == sig2
def test_different_data_different_signature(self):
sig1 = _compute_signature({"user_id": "123"})
sig2 = _compute_signature({"user_id": "456"})
assert sig1 != sig2
def test_has_credential_changed_no_signature(self):
mgr = CredentialManager()
assert mgr.has_credential_changed({"user_id": "123"}) is True
def test_has_credential_changed_same_data(self):
mgr = CredentialManager()
mgr.mark_connected({"user_id": "123"})
assert mgr.has_credential_changed({"user_id": "123"}) is False
def test_has_credential_changed_different_data(self):
mgr = CredentialManager()
mgr.mark_connected({"user_id": "123"})
assert mgr.has_credential_changed({"user_id": "456"}) is True
def test_update_credentials_same_data(self):
mgr = CredentialManager()
mgr.mark_connected({"user_id": "123"})
assert mgr.update_credentials({"user_id": "123"}) is False
def test_update_credentials_different_data(self):
mgr = CredentialManager()
mgr.mark_connected({"user_id": "123"})
old_sig = mgr.credential_signature
changed = mgr.update_credentials({"user_id": "456"})
assert changed is True
assert mgr.credential_signature != old_sig
class TestSessionStatus:
@pytest.mark.asyncio
async def test_session_alive(self):
class FakeBridge:
async def check_login_status(self):
return {"logged_in": True}
mgr = CredentialManager()
result = await mgr.check_session_status(FakeBridge())
assert result is True
assert mgr.stage == ZaloCredentialStage.CONNECTED
@pytest.mark.asyncio
async def test_session_dead(self):
class FakeBridge:
async def check_login_status(self):
return {"logged_in": False}
mgr = CredentialManager()
mgr.mark_connected({"user_id": "123"})
result = await mgr.check_session_status(FakeBridge())
assert result is False
assert mgr.stage == ZaloCredentialStage.LOGGED_OUT
@pytest.mark.asyncio
async def test_session_check_error(self):
class FakeBridge:
async def check_login_status(self):
raise RuntimeError("network error")
mgr = CredentialManager()
mgr.mark_connected({"user_id": "123"})
result = await mgr.check_session_status(FakeBridge())
assert result is True
class TestLogout:
@pytest.mark.asyncio
async def test_logout_success(self):
class FakeBridge:
async def post(self, path, json=None, **kwargs):
class FakeResp:
@staticmethod
def json():
return {"success": True}
return FakeResp()
mgr = CredentialManager()
mgr.mark_connected({"user_id": "123"})
result = await mgr.logout(FakeBridge())
assert result is True
assert mgr.stage == ZaloCredentialStage.LOGGED_OUT
@pytest.mark.asyncio
async def test_logout_error_graceful(self):
class FakeBridge:
async def post(self, path, json=None, **kwargs):
raise RuntimeError("network down")
mgr = CredentialManager()
mgr.mark_connected({"user_id": "123"})
result = await mgr.logout(FakeBridge())
assert result is False
assert mgr.stage == ZaloCredentialStage.LOGGED_OUT
class TestReset:
def test_reset(self):
mgr = CredentialManager()
mgr.mark_connected({"user_id": "123"})
mgr.reset()
assert mgr.stage == ZaloCredentialStage.UNINITIALIZED
assert mgr.credential_signature is None
class TestToDict:
def test_to_dict(self):
mgr = CredentialManager()
mgr.mark_connected({"user_id": "123"})
d = mgr.to_dict()
assert d["stage"] == "connected"
assert d["is_authenticated"] is True
assert "last_check_time" in d
assert "error" in d