From 08f343f5d7240a22d4b2c3274cf84a68d8075ca5 Mon Sep 17 00:00:00 2001 From: lisry-1 Date: Sun, 1 Nov 2026 23:59:00 +0800 Subject: [PATCH] fix(wecom): report False when send_file cannot upload instead of True (#7768) send_file short-circuited with `return True` for non-final messages, which reported a successful upload that never happened. Per the Channel.send_file contract ("Returns True if the upload succeeded, False otherwise"), a message with no upload path must report False so the attachment lands in the 'failed' feedback the user relies on, instead of being silently dropped. Drop the non-final short-circuit so the method reaches its normal connectivity checks (no WS client / no thread frame -> False), matching every other channel. Co-authored-by: lisry-1 <249596828+lisry-1@users.noreply.github.com> --- backend/app/channels/wecom.py | 2 -- .../test_channel_outbound_files.py | 21 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/backend/app/channels/wecom.py b/backend/app/channels/wecom.py index 6911e7426d..9f7c0bd458 100644 --- a/backend/app/channels/wecom.py +++ b/backend/app/channels/wecom.py @@ -434,8 +434,6 @@ class WeComChannel(Channel): logger.exception("[WeCom] failed to send attachment delivery feedback") async def send_file(self, msg: OutboundMessage, attachment: ResolvedAttachment) -> bool: - if not msg.is_final: - return True if not self._ws_client: return False if not msg.thread_ts: diff --git a/backend/tests/blocking_io/test_channel_outbound_files.py b/backend/tests/blocking_io/test_channel_outbound_files.py index 4257807f84..ffdc19cc07 100644 --- a/backend/tests/blocking_io/test_channel_outbound_files.py +++ b/backend/tests/blocking_io/test_channel_outbound_files.py @@ -190,3 +190,24 @@ async def test_wecom_outbound_upload_does_not_block_event_loop(tmp_path: Path) - assert calls[0].args[1]["md5"] == hashlib.md5(payload).hexdigest() encoded_chunks = [call.args[1]["base64_data"] for call in calls[1:-1]] assert b"".join(base64.b64decode(chunk) for chunk in encoded_chunks) == payload + + +async def test_wecom_send_file_does_not_report_success_when_disconnected(tmp_path: Path) -> None: + """send_file must return False, not True, when there is no upload path. + + A non-final message (or one without a live WS client / thread frame) has + nothing uploaded, so reporting success would drop the attachment from the + 'failed' feedback the user relies on. + """ + path = tmp_path / "report.bin" + await asyncio.to_thread(path.write_bytes, b"payload") + + channel = WeComChannel(MessageBus(), {}) + # No _ws_client: there is no way to upload, so send_file must report False. + assert channel._ws_client is None + + msg = _outbound("wecom") + # Explicitly non-final: this used to short-circuit with `return True` and + # report an upload that never happened. + msg.is_final = False + assert await channel.send_file(msg, _attachment(path, is_image=False)) is False