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

276 lines
9.8 KiB
Python

from __future__ import annotations
import json
import pytest
from yuxi.channels.meta import ChannelMeta
from yuxi.channels.models import ChannelAccountSnapshot, TokenStatus
class TestChannelMetaNewFields:
def test_all_fields_have_defaults(self):
meta = ChannelMeta(id="test", label="Test")
assert meta.selection_docs_prefix == ""
assert meta.selection_docs_omit_label is False
assert meta.detail_label == ""
assert meta.prefer_session_lookup_for_announce_target is False
assert meta.prefer_over is False
def test_full_meta_with_new_fields(self):
meta = ChannelMeta(
id="discord",
label="Discord",
selection_label="Discord Bot",
blurb="Discord 渠道适配器",
order=3,
docs_path="docs/channels/discord",
docs_label="Discord 文档",
selection_docs_prefix="/channels",
selection_docs_omit_label=False,
system_image="discord",
markdown_capable=True,
detail_label="Discord 详情",
aliases=["dc"],
exposure="public",
show_configured=True,
show_in_setup=True,
quickstart_allow_from=["web", "mobile"],
force_account_binding=False,
prefer_session_lookup_for_announce_target=True,
prefer_over=True,
)
assert meta.id == "discord"
assert meta.selection_docs_prefix == "/channels"
assert meta.selection_docs_omit_label is False
assert meta.detail_label == "Discord 详情"
assert meta.prefer_session_lookup_for_announce_target is True
assert meta.prefer_over is True
def test_model_dump_includes_new_fields(self):
meta = ChannelMeta(
id="telegram",
label="Telegram",
detail_label="TG",
prefer_over=True,
)
dumped = meta.model_dump()
assert "detail_label" in dumped
assert "prefer_over" in dumped
assert "selection_docs_prefix" in dumped
assert "selection_docs_omit_label" in dumped
assert "prefer_session_lookup_for_announce_target" in dumped
def test_model_dump_serializable(self):
meta = ChannelMeta(
id="test",
label="Test",
prefer_over=True,
detail_label="Detail",
)
json.dumps(meta.model_dump())
def test_wechat_meta_backward_compat(self):
from yuxi.channels.adapters.wechat.capabilities import WECHAT_META, get_meta
meta = get_meta()
assert isinstance(meta, ChannelMeta)
assert meta.id == "wechat"
assert meta.label == "微信"
assert meta.order == 8
assert meta.aliases == ["weixin", "WeChat"]
assert meta.markdown_capable is False
assert meta.exposure == "configured"
dumped = WECHAT_META.model_dump()
assert dumped["id"] == "wechat"
assert dumped["label"] == "微信"
def test_roundtrip_serialization(self):
original = ChannelMeta(
id="line",
label="LINE",
selection_label="LINE Bot",
docs_path="docs/channels/line",
blurb="LINE 渠道适配器",
order=10,
aliases=["line_me"],
system_image="line",
markdown_capable=False,
exposure="public",
detail_label="LINE",
prefer_over=False,
prefer_session_lookup_for_announce_target=False,
)
data = original.model_dump()
restored = ChannelMeta(**data)
assert restored == original
class TestTokenStatus:
def test_default_values(self):
ts = TokenStatus()
assert ts.source == ""
assert ts.status == "unknown"
assert ts.last_verified_at == 0.0
def test_custom_values(self):
ts = TokenStatus(source="env", status="valid", last_verified_at=1715000000.0)
assert ts.source == "env"
assert ts.status == "valid"
assert ts.last_verified_at == 1715000000.0
def test_model_dump_serializable(self):
ts = TokenStatus(source="vault", status="expired", last_verified_at=1715000000.0)
json.dumps(ts.model_dump())
class TestChannelAccountSnapshotNewFields:
def test_default_token_fields(self):
snap = ChannelAccountSnapshot()
assert snap.token_source == ""
assert snap.token_status is None
assert snap.bot_token_source == ""
assert snap.bot_token_status is None
assert snap.app_token_source == ""
assert snap.app_token_status is None
assert snap.signing_secret_source == ""
assert snap.signing_secret_status is None
assert snap.user_token_status is None
assert snap.credential_source == ""
assert snap.secret_source == ""
def test_default_network_fields(self):
snap = ChannelAccountSnapshot()
assert snap.webhook_path == ""
assert snap.webhook_url == ""
assert snap.base_url == ""
assert snap.cli_path == ""
assert snap.db_path == ""
assert snap.port == 0
def test_default_probe_fields(self):
snap = ChannelAccountSnapshot()
assert snap.probe is None
assert snap.last_probe_at == 0.0
assert snap.audit is None
def test_default_bot_fields(self):
snap = ChannelAccountSnapshot()
assert snap.application is None
assert snap.bot is None
assert snap.public_key == ""
assert snap.profile is None
def test_token_status_with_data(self):
snap = ChannelAccountSnapshot(
account_id="acc_1",
token_source="env",
token_status=TokenStatus(source="env", status="valid"),
bot_token_source="config",
bot_token_status=TokenStatus(source="config", status="expired"),
)
assert snap.token_source == "env"
assert snap.token_status.source == "env"
assert snap.token_status.status == "valid"
assert snap.bot_token_status.status == "expired"
def test_network_fields_with_data(self):
snap = ChannelAccountSnapshot(
account_id="acc_1",
webhook_path="/webhook/whatsapp",
webhook_url="https://example.com/webhook",
base_url="https://api.example.com",
port=8443,
)
assert snap.webhook_path == "/webhook/whatsapp"
assert snap.webhook_url == "https://example.com/webhook"
assert snap.base_url == "https://api.example.com"
assert snap.port == 8443
def test_probe_fields_with_data(self):
snap = ChannelAccountSnapshot(
account_id="acc_1",
probe={"endpoint": "/health", "timeout": 5},
last_probe_at=1715000000.0,
audit={"last_audit": "2024-01-01"},
)
assert snap.probe == {"endpoint": "/health", "timeout": 5}
assert snap.last_probe_at == 1715000000.0
assert snap.audit == {"last_audit": "2024-01-01"}
def test_bot_fields_with_data(self):
snap = ChannelAccountSnapshot(
account_id="acc_1",
application={"name": "MyBot", "version": "1.0"},
bot={"username": "my_bot", "id": "123"},
public_key="ssh-rsa AAA...",
profile={"display_name": "My Bot"},
)
assert snap.application == {"name": "MyBot", "version": "1.0"}
assert snap.bot == {"username": "my_bot", "id": "123"}
assert snap.public_key == "ssh-rsa AAA..."
assert snap.profile == {"display_name": "My Bot"}
def test_snapshot_dump_includes_new_fields(self):
snap = ChannelAccountSnapshot(
account_id="acc_1",
token_source="env",
webhook_path="/wh",
probe={"key": "val"},
public_key="abc",
)
dumped = snap.model_dump()
assert "token_source" in dumped
assert "webhook_path" in dumped
assert "probe" in dumped
assert "public_key" in dumped
def test_snapshot_backward_compat_core_fields(self):
snap = ChannelAccountSnapshot(account_id="acc_1", name="test", configured=True)
assert snap.account_id == "acc_1"
assert snap.name == "test"
assert snap.configured is True
assert snap.enabled is True
assert snap.linked is False
def test_snapshot_extra_fields_still_allowed(self):
snap = ChannelAccountSnapshot(account_id="acc_1", custom_field="custom_value")
assert snap.custom_field == "custom_value"
def test_snapshot_json_serializable(self):
snap = ChannelAccountSnapshot(
account_id="acc_1",
token_status=TokenStatus(source="env", status="valid"),
probe={"key": "val"},
bot={"id": "123"},
)
json.dumps(snap.model_dump())
class TestWhatsAppChannelMetaMigration:
def test_whatsapp_channel_meta_import_works(self):
from yuxi.channels.adapters.whatsapp.channel_meta import (
ChannelCapability,
ChannelMeta,
ChannelMode,
WhatsAppChannelMeta,
)
assert ChannelMeta is WhatsAppChannelMeta
def test_whatsapp_channel_meta_has_capability(self):
from yuxi.channels.adapters.whatsapp.channel_meta import (
ChannelCapability,
WhatsAppChannelMeta,
)
meta = WhatsAppChannelMeta()
assert meta.has_capability(ChannelCapability.TEXT) is True
assert meta.has_capability(ChannelCapability.REACTION) is False
def test_whatsapp_adapter_has_display_meta(self):
from yuxi.channels.adapters.whatsapp.adapter import WhatsAppAdapter
from yuxi.channels.meta import ChannelMeta as DisplayMeta
assert isinstance(WhatsAppAdapter.meta, DisplayMeta)
assert WhatsAppAdapter.meta.id == "whatsapp"
assert WhatsAppAdapter.meta.label == "WhatsApp"