Files
inquiry_robot/inquiry-agent/tests/test_aibot_reply.py
T
jillion886andCursor 83b907c4b8 修复空运锁舱签名、报价编号落库和查价 Token 失效重试。
锁舱按签名原字节出站,查价要带上 TMS 真实 quoteId/optionNo;收到 2001 换令牌再查,避免工单建了却提示查询失败。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 18:19:44 +08:00

117 lines
4.9 KiB
Python

"""
空运 BOT 出站:没有当场回话地址时,打桥主动往群里说。
"""
from __future__ import annotations
import os
import sys
import unittest
from unittest.mock import MagicMock, patch
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
if ROOT not in sys.path:
sys.path.insert(0, ROOT)
from agent.channel.aibot import normalize_aibot_payload
from agent.channel.aibot.reply import AibotReplyClient
class AibotInboundNormalizeTests(unittest.TestCase):
def test_official_wecom_body(self) -> None:
parsed = normalize_aibot_payload(
{
"msgid": "m1",
"chatid": "wr_air_1",
"chattype": "group",
"from": {"userid": "WuJiLin"},
"msgtype": "text",
"text": {"content": "@询价小助手 WO202609160009"},
"aibot_direct": True,
}
)
self.assertEqual(parsed.sender_id, "WuJiLin")
self.assertEqual(parsed.message_id, "m1")
self.assertEqual(parsed.chat_id, "wr_air_1")
self.assertEqual(parsed.chat_type, "group")
self.assertIn("WO202609160009", parsed.content)
self.assertEqual(parsed.raw.get("source"), "aibot")
class AibotReplyTests(unittest.TestCase):
def test_empty_content_skips(self) -> None:
client = AibotReplyClient("")
out = client.send_group(chat_id="wr_1", content=" ")
self.assertFalse(out["ok"])
self.assertEqual(out["error"], "empty")
def test_proactive_posts_send_group(self) -> None:
client = AibotReplyClient("")
fake_http = MagicMock()
fake_http.post.return_value.status_code = 200
fake_http.post.return_value.text = '{"status":"sent"}'
settings = MagicMock()
settings.wecom_aibot_bridge_url = "http://127.0.0.1:8913"
settings.wecom_aibot_bridge_token = "tok"
with patch("agent.channel.aibot.reply.httpx", fake_http), patch(
"agent.channel.aibot.reply.get_settings", return_value=settings
):
out = client.send_group(chat_id="wr_air_1", content="附件已保存")
self.assertTrue(out["ok"])
url, = fake_http.post.call_args.args
self.assertEqual(url, "http://127.0.0.1:8913/send")
payload = fake_http.post.call_args.kwargs["json"]
self.assertEqual(payload["chatid"], "wr_air_1")
self.assertEqual(payload["operation"], "text")
self.assertEqual(payload["content"], "附件已保存")
self.assertEqual(
fake_http.post.call_args.kwargs["headers"]["X-Aibot-Bridge-Token"],
"tok",
)
def test_send_group_file_posts_send_file(self) -> None:
client = AibotReplyClient("")
fake_http = MagicMock()
fake_http.post.return_value.status_code = 200
fake_http.post.return_value.text = '{"status":"sent"}'
settings = MagicMock()
settings.wecom_aibot_bridge_url = "http://127.0.0.1:8913"
settings.wecom_aibot_bridge_token = "tok"
with patch("agent.channel.aibot.reply.httpx", fake_http), patch(
"agent.channel.aibot.reply.get_settings", return_value=settings
):
out = client.send_group_file(
chat_id="wr_air_1",
filename="WO1_quote.xlsx",
file_b64="QQ==",
)
self.assertTrue(out["ok"])
url, = fake_http.post.call_args.args
self.assertEqual(url, "http://127.0.0.1:8913/send-file")
payload = fake_http.post.call_args.kwargs["json"]
self.assertEqual(payload["chatid"], "wr_air_1")
self.assertEqual(payload["filename"], "WO1_quote.xlsx")
def test_at_reply_puts_brief_on_same_channel_as_file(self) -> None:
"""
@ 当场流式回话群里经常只看得见后面的文件。
工单信息必须再走桥主动发言,和模板同一条通道。
"""
client = AibotReplyClient("https://example.com/reply")
fake_http = MagicMock()
fake_http.post.return_value.status_code = 200
fake_http.post.return_value.text = '{"status":"sent"}'
settings = MagicMock()
settings.wecom_aibot_bridge_url = "http://127.0.0.1:8913"
settings.wecom_aibot_bridge_token = "tok"
brief = "工单号:WO202609160014\n询价字段:\n起运地:ZUH"
with patch("agent.channel.aibot.reply.httpx", fake_http), patch(
"agent.channel.aibot.reply.get_settings", return_value=settings
):
out = client.send_group(chat_id="wr_air_1", content=brief)
self.assertTrue(out["ok"])
urls = [c.args[0] for c in fake_http.post.call_args_list]
self.assertTrue(any(u.endswith("/send") or u.endswith("/send-group") for u in urls))
payloads = [c.kwargs.get("json") or {} for c in fake_http.post.call_args_list]
self.assertTrue(any(p.get("content") == brief for p in payloads))