更新
This commit is contained in:
@@ -20,6 +20,7 @@ if str(BACKEND_DIR) not in sys.path:
|
||||
from rpa_engine.douyin_im import http_client as http_client_module
|
||||
from rpa_engine.douyin_im.http_client import DouyinImHttpClient
|
||||
from rpa_engine.douyin_im.session import DouyinImSession
|
||||
from rpa_engine.egress_channels import EgressChannel
|
||||
from rpa_engine.playwright_worker import DouyinWorker
|
||||
|
||||
|
||||
@@ -85,6 +86,7 @@ class SendTextMessageEntryTests(unittest.IsolatedAsyncioTestCase):
|
||||
last_send_meta=queued_meta,
|
||||
last_error="credential expired",
|
||||
last_send_needs_refresh=True,
|
||||
last_send_channel_retryable=False,
|
||||
last_request_debug="response status=401",
|
||||
)
|
||||
queued_context = MagicMock()
|
||||
@@ -131,6 +133,65 @@ class SendTextMessageEntryTests(unittest.IsolatedAsyncioTestCase):
|
||||
self.assertTrue(client.last_send_needs_refresh)
|
||||
self.assertEqual(client.last_request_debug, "response status=401")
|
||||
|
||||
async def test_retryable_rejection_switches_channels_serially(self):
|
||||
client = self._make_client(account_id=89)
|
||||
client.session.egress_auto_attempts = 2
|
||||
routes = [
|
||||
EgressChannel("198.51.100.10", "10.0.0.10", "eth0", True),
|
||||
EgressChannel("198.51.100.11", "10.0.0.11", "eth0:1", False),
|
||||
]
|
||||
|
||||
first = SimpleNamespace(
|
||||
send_text_message=AsyncMock(return_value=False),
|
||||
last_send_meta={},
|
||||
last_error="decision=KICK",
|
||||
last_send_needs_refresh=False,
|
||||
last_send_channel_retryable=True,
|
||||
last_request_debug="first route",
|
||||
)
|
||||
second = SimpleNamespace(
|
||||
send_text_message=AsyncMock(return_value=True),
|
||||
last_send_meta={"conv": {"ticket": "ok"}},
|
||||
last_error="",
|
||||
last_send_needs_refresh=False,
|
||||
last_send_channel_retryable=False,
|
||||
last_request_debug="second route",
|
||||
)
|
||||
|
||||
def context_for(value):
|
||||
context = MagicMock()
|
||||
context.__aenter__ = AsyncMock(return_value=value)
|
||||
context.__aexit__ = AsyncMock(return_value=None)
|
||||
return context
|
||||
|
||||
queued_factory = MagicMock(side_effect=[context_for(first), context_for(second)])
|
||||
|
||||
async def execute_submission(account_id, operation, description=""):
|
||||
self.assertEqual(account_id, 89)
|
||||
return await operation()
|
||||
|
||||
with (
|
||||
patch(
|
||||
"rpa_engine.douyin_im.traffic_control.submit_outbound",
|
||||
AsyncMock(side_effect=execute_submission),
|
||||
),
|
||||
patch(
|
||||
"rpa_engine.douyin_im.http_client.resolve_send_channels",
|
||||
AsyncMock(return_value=routes),
|
||||
),
|
||||
patch.object(http_client_module, "DouyinImHttpClient", queued_factory),
|
||||
patch.object(http_client_module.system_logger, "record"),
|
||||
):
|
||||
sent = await client.send_text_message("0:1:10001:20002", "hello")
|
||||
|
||||
self.assertTrue(sent)
|
||||
self.assertEqual(queued_factory.call_count, 2)
|
||||
self.assertEqual(queued_factory.call_args_list[0].kwargs["source_ip"], "10.0.0.10")
|
||||
self.assertEqual(queued_factory.call_args_list[1].kwargs["source_ip"], "10.0.0.11")
|
||||
first.send_text_message.assert_awaited_once()
|
||||
second.send_text_message.assert_awaited_once()
|
||||
self.assertEqual(client.last_request_debug, "second route")
|
||||
|
||||
|
||||
class WorkerLifecycleTests(unittest.IsolatedAsyncioTestCase):
|
||||
async def test_start_saves_task_and_stop_waits_until_it_is_done(self):
|
||||
|
||||
Reference in New Issue
Block a user