更新
This commit is contained in:
@@ -24,6 +24,7 @@ if str(BACKEND_DIR) not in sys.path:
|
||||
|
||||
from rpa_engine.douyin_im import hosted_registry
|
||||
from rpa_engine.douyin_im import ws_client as ws_module
|
||||
from rpa_engine.douyin_im.auth import DouyinAuth
|
||||
from rpa_engine.douyin_im.conv_util import conversation_belongs_to
|
||||
from rpa_engine.douyin_im.http_client import DouyinImHttpClient
|
||||
from rpa_engine.douyin_im.service import DouyinImService
|
||||
@@ -151,6 +152,80 @@ class ForeignSendRefusalTests(unittest.IsolatedAsyncioTestCase):
|
||||
self.assertFalse(client.last_send_channel_retryable)
|
||||
|
||||
|
||||
class ExpectedRecipientTests(unittest.IsolatedAsyncioTestCase):
|
||||
"""手动发送必须打给调用方点选的那个人(昵称重复时会话可能匹配错)。"""
|
||||
|
||||
OTHER_PEER = 975976494279630
|
||||
|
||||
def _client(self) -> DouyinImHttpClient:
|
||||
return DouyinImHttpClient(
|
||||
DouyinImSession(cookies={"sessionid": "a"}, my_uid=ACCOUNT_A_UID),
|
||||
account_id=1,
|
||||
)
|
||||
|
||||
async def _send(self, client, conversation_id, expected_peer_uid):
|
||||
resolve_meta = AsyncMock(return_value=("", "", ""))
|
||||
with (
|
||||
patch.object(
|
||||
DouyinImHttpClient,
|
||||
"_resolve_authoritative_uid",
|
||||
return_value=ACCOUNT_A_UID,
|
||||
),
|
||||
# 本组用例只验收件人闸门,凭证是否齐全与它无关
|
||||
patch.object(DouyinAuth, "is_sign_ready", return_value=True),
|
||||
patch.object(
|
||||
DouyinImHttpClient, "resolve_conversation_meta", resolve_meta
|
||||
),
|
||||
patch("rpa_engine.douyin_im.http_client.system_logger.record", Mock()),
|
||||
):
|
||||
sent = await client.send_text_message(
|
||||
conversation_id,
|
||||
"你好",
|
||||
expected_peer_uid=expected_peer_uid,
|
||||
_bypass_global_queue=True,
|
||||
)
|
||||
return sent, resolve_meta
|
||||
|
||||
async def test_refuses_when_the_conversation_points_at_someone_else(self):
|
||||
client = self._client()
|
||||
|
||||
sent, resolve_meta = await self._send(
|
||||
client,
|
||||
f"0:1:{ACCOUNT_A_UID}:{self.OTHER_PEER}",
|
||||
str(PEER_OF_B),
|
||||
)
|
||||
|
||||
self.assertFalse(sent)
|
||||
# 必须在解析 ticket / 发包之前就拒绝
|
||||
resolve_meta.assert_not_awaited()
|
||||
self.assertIn("发送目标与预期不一致", client.last_error)
|
||||
self.assertFalse(client.last_send_channel_retryable)
|
||||
|
||||
async def test_allows_the_intended_recipient(self):
|
||||
client = self._client()
|
||||
|
||||
sent, resolve_meta = await self._send(
|
||||
client,
|
||||
f"0:1:{ACCOUNT_A_UID}:{PEER_OF_B}",
|
||||
str(PEER_OF_B),
|
||||
)
|
||||
|
||||
# ticket 解析被 mock 成空 -> 发送仍会失败,但必须是「拿不到票据」而不是被闸门拦下
|
||||
self.assertFalse(sent)
|
||||
resolve_meta.assert_awaited()
|
||||
self.assertNotIn("发送目标与预期不一致", client.last_error)
|
||||
|
||||
async def test_no_expectation_keeps_the_old_behaviour(self):
|
||||
client = self._client()
|
||||
|
||||
_, resolve_meta = await self._send(
|
||||
client, f"0:1:{ACCOUNT_A_UID}:{self.OTHER_PEER}", ""
|
||||
)
|
||||
|
||||
resolve_meta.assert_awaited()
|
||||
self.assertNotIn("发送目标与预期不一致", client.last_error)
|
||||
|
||||
|
||||
class HostedPeerLoopTests(unittest.IsolatedAsyncioTestCase):
|
||||
"""两个本系统托管的账号之间不得互相自动回复(无限回环 → 抖音风控)。"""
|
||||
|
||||
|
||||
@@ -188,15 +188,18 @@ class SendTextMessageEntryTests(unittest.IsolatedAsyncioTestCase):
|
||||
"0:1:10001:20002",
|
||||
"queued hello",
|
||||
conversation_short_id="short-before-send",
|
||||
expected_peer_uid="20002",
|
||||
)
|
||||
|
||||
self.assertFalse(sent)
|
||||
submit.assert_awaited_once()
|
||||
queued_factory.assert_called_once_with(client.session, account_id=88)
|
||||
# 收件人期望必须原样传给真正写出去的那个 client:排队调度层不能把它吃掉
|
||||
queued_client.send_text_message.assert_awaited_once_with(
|
||||
"0:1:10001:20002",
|
||||
"queued hello",
|
||||
conversation_short_id="short-before-send",
|
||||
expected_peer_uid="20002",
|
||||
_bypass_global_queue=True,
|
||||
)
|
||||
self.assertEqual(client.last_send_meta, queued_meta)
|
||||
|
||||
Reference in New Issue
Block a user