新增了Twitch、Telegram、Discord、Slack、Mattermost、WeChat、Zalo等多渠道的单元测试用例,覆盖了令牌处理、速率限制、消息去重、会话解析、格式转换、安全策略等模块 同时在测试配置中添加了测试用的OpenAI API密钥环境变量
218 lines
6.9 KiB
Python
218 lines
6.9 KiB
Python
from __future__ import annotations
|
|
|
|
|
|
|
|
from yuxi.channels.adapters.irc._isupport import ISupport
|
|
from yuxi.channels.adapters.irc.normalizer import _parse_irc_time_tag, normalize_inbound
|
|
from yuxi.channels.models import ChannelType
|
|
|
|
|
|
EXAMPLE_ISUPPORT = (
|
|
":irc.example.com 005 mybot CASEMAPPING=rfc1459 CHANMODES=b,k,l,imnpst "
|
|
"CHANTYPES=# PREFIX=(ov)@+ NICKLEN=16 CHANNELLEN=50 TOPICLEN=390 "
|
|
"KICKLEN=400 AWAYLEN=200 MODES=3 MAXLIST=b:60,e:60,I:60 "
|
|
"STATUSMSG=@+ EXCEPTS=e INVEX=I MONITOR=100 "
|
|
":are supported by this server"
|
|
)
|
|
|
|
|
|
class TestISupport:
|
|
def test_parse_prefix_map(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
assert isup.prefix_map == {"@": "o", "+": "v"}
|
|
assert isup.mode_to_prefix("o") == "@"
|
|
assert isup.mode_to_prefix("v") == "+"
|
|
assert isup.prefix_to_mode("@") == "o"
|
|
assert isup.prefix_to_mode("+") == "v"
|
|
|
|
def test_parse_casemapping(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
assert isup.casemapping == "rfc1459"
|
|
|
|
def test_parse_nicklen(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
assert isup.nicklen == 16
|
|
|
|
def test_parse_chantypes(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
assert isup.chantypes == "#"
|
|
|
|
def test_parse_chanmodes(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
d = isup.to_dict()
|
|
assert d["chanmodes"]["a"] == "b"
|
|
assert d["chanmodes"]["b"] == "k"
|
|
assert d["chanmodes"]["c"] == "l"
|
|
assert d["chanmodes"]["d"] == "imnpst"
|
|
|
|
def test_parse_maxlist(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
d = isup.to_dict()
|
|
assert d["has_excepts"] is True
|
|
assert d["has_invex"] is True
|
|
|
|
def test_parse_monitor(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
assert isup.monitor == 100
|
|
|
|
def test_parse_modes(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
assert isup.modes == 3
|
|
|
|
def test_parse_topiclen(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
assert isup.topiclen == 390
|
|
|
|
def test_parse_kicklen(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
assert isup.kicklen == 400
|
|
|
|
def test_parse_awaylen(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
assert isup.awaylen == 200
|
|
|
|
def test_parse_statusmsg(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
assert isup.prefixes == ["@", "+"]
|
|
|
|
def test_strip_prefixes(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
assert isup.strip_prefixes("@nick") == "nick"
|
|
assert isup.strip_prefixes("+nick") == "nick"
|
|
assert isup.strip_prefixes("nick") == "nick"
|
|
assert isup.strip_prefixes("") == ""
|
|
|
|
def test_prefix_to_mode_unknown(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
assert isup.prefix_to_mode("~") is None
|
|
|
|
def test_mode_to_prefix_unknown(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
assert isup.mode_to_prefix("q") is None
|
|
|
|
def test_to_dict_includes_all_sections(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
d = isup.to_dict()
|
|
for key in [
|
|
"casemapping", "chantypes", "nicklen", "channellen",
|
|
"topiclen", "kicklen", "awaylen", "modes", "monitor",
|
|
"prefix_map", "chanmodes", "has_excepts", "has_invex", "raw",
|
|
]:
|
|
assert key in d, f"Missing key: {key}"
|
|
|
|
def test_get_raw_token(self):
|
|
isup = ISupport()
|
|
isup.feed_line(EXAMPLE_ISUPPORT)
|
|
assert isup.get("NICKLEN") == "16"
|
|
assert isup.get("NOT_EXISTS", "fallback") == "fallback"
|
|
|
|
def test_feed_multiple_lines(self):
|
|
isup = ISupport()
|
|
isup.feed_line(":irc.test 005 bot CASEMAPPING=ascii NICKLEN=9 :first")
|
|
isup.feed_line(":irc.test 005 bot CHANTYPES=&# CHANNELLEN=32 :second")
|
|
assert isup.casemapping == "ascii"
|
|
assert isup.nicklen == 9
|
|
assert isup.chantypes == "&#"
|
|
assert isup.channellen == 32
|
|
|
|
def test_feed_token_without_value(self):
|
|
isup = ISupport()
|
|
isup.feed_line(":irc.test 005 bot SAFELIST :are supported")
|
|
assert isup.get("SAFELIST") == ""
|
|
|
|
def test_channellen_default(self):
|
|
isup = ISupport()
|
|
assert isup.channellen == 200
|
|
|
|
def test_default_prefix_map(self):
|
|
isup = ISupport()
|
|
assert isup.prefix_map == {"@": "o", "+": "v"}
|
|
|
|
|
|
class TestServerTimeParsing:
|
|
def test_parse_valid_iso_time(self):
|
|
ts = _parse_irc_time_tag("2024-06-15T12:30:45.123Z")
|
|
assert ts > 0
|
|
|
|
def test_parse_time_without_ms(self):
|
|
ts = _parse_irc_time_tag("2024-06-15T12:30:45Z")
|
|
assert ts > 0
|
|
|
|
def test_parse_invalid_returns_current(self):
|
|
import time
|
|
now = int(time.time() * 1000)
|
|
ts = _parse_irc_time_tag("not-a-time")
|
|
assert abs(ts - now) < 1000
|
|
|
|
def test_parse_empty_returns_current(self):
|
|
import time
|
|
now = int(time.time() * 1000)
|
|
ts = _parse_irc_time_tag("")
|
|
assert abs(ts - now) < 1000
|
|
|
|
|
|
class TestNormalizeInboundWithServerTime:
|
|
def test_uses_server_time_when_present(self):
|
|
raw = {
|
|
"sender_nick": "user1",
|
|
"target": "#test",
|
|
"text": "hello",
|
|
"time": "2024-06-15T12:00:00.000Z",
|
|
}
|
|
msg = normalize_inbound(
|
|
raw, "irc-channel-id", ChannelType.IRC, "mybot"
|
|
)
|
|
assert msg.identity.channel_message_id.startswith("user1:")
|
|
assert "1718452800000" in msg.identity.channel_message_id
|
|
|
|
def test_uses_local_time_when_no_time_tag(self):
|
|
raw = {
|
|
"sender_nick": "user1",
|
|
"target": "#test",
|
|
"text": "hello",
|
|
}
|
|
msg = normalize_inbound(
|
|
raw, "irc-channel-id", ChannelType.IRC, "mybot"
|
|
)
|
|
assert msg.identity.channel_message_id.startswith("user1:")
|
|
|
|
def test_channel_message_mentions(self):
|
|
raw = {
|
|
"sender_nick": "user1",
|
|
"target": "#test",
|
|
"text": "hello @mybot how are you",
|
|
}
|
|
msg = normalize_inbound(
|
|
raw, "irc-channel-id", ChannelType.IRC, "mybot"
|
|
)
|
|
assert msg.mentions.is_bot_mentioned is True
|
|
assert "mybot" in msg.mentions.mentioned_user_ids
|
|
|
|
def test_direct_message_normalization(self):
|
|
raw = {
|
|
"sender_nick": "alice",
|
|
"target": "mybot",
|
|
"text": "hi there",
|
|
}
|
|
msg = normalize_inbound(
|
|
raw, "irc-channel-id", ChannelType.IRC, "mybot"
|
|
)
|
|
assert msg.chat_type.value == "direct"
|
|
assert msg.identity.channel_chat_id == "dm_alice"
|