mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 03:15:46 -06:00
fix(telegram): classify hosted media size errors consistently (#120757)
This commit is contained in:
committed by
GitHub
parent
019dd0e086
commit
6972ef80b7
@@ -2,9 +2,48 @@ import { MediaFetchError } from "openclaw/plugin-sdk/media-runtime";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
isDurablyRetryableInboundMediaError,
|
||||
isMediaSizeLimitError,
|
||||
isRecoverableMediaGroupError,
|
||||
TelegramBotApiFileTooLargeError,
|
||||
} from "./bot-handlers.media.js";
|
||||
|
||||
describe("isMediaSizeLimitError", () => {
|
||||
it.each([
|
||||
{
|
||||
name: "content-length limit",
|
||||
error: new MediaFetchError("max_bytes", "content length 11 exceeds maxBytes 10"),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "streaming payload limit",
|
||||
error: new MediaFetchError("max_bytes", "payload exceeds maxBytes 10"),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Telegram Bot API file limit",
|
||||
error: new TelegramBotApiFileTooLargeError(new Error("Bad Request: file is too big")),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "legacy untyped size error",
|
||||
error: new Error("media exceeds 20 MB limit"),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "fetch failure with misleading size text",
|
||||
error: new MediaFetchError("fetch_failed", "media exceeds 20 MB limit"),
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "HTTP failure with misleading size text",
|
||||
error: new MediaFetchError("http_error", "media exceeds 20 MB limit", { status: 500 }),
|
||||
expected: false,
|
||||
},
|
||||
])("classifies $name by its authoritative error code", ({ error, expected }) => {
|
||||
expect(isMediaSizeLimitError(error)).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isDurablyRetryableInboundMediaError", () => {
|
||||
const networkCause = () => Object.assign(new Error("read ECONNRESET"), { code: "ECONNRESET" });
|
||||
const abortCause = () => Object.assign(new Error("aborted"), { name: "AbortError" });
|
||||
|
||||
@@ -19,8 +19,8 @@ export class TelegramBotApiFileTooLargeError extends MediaFetchError {
|
||||
}
|
||||
|
||||
export function isMediaSizeLimitError(err: unknown): boolean {
|
||||
if (err instanceof TelegramBotApiFileTooLargeError) {
|
||||
return true;
|
||||
if (err instanceof MediaFetchError) {
|
||||
return err.code === "max_bytes";
|
||||
}
|
||||
const errMsg = String(err);
|
||||
return errMsg.includes("exceeds") && errMsg.includes("MB limit");
|
||||
|
||||
@@ -420,7 +420,7 @@ describe("createTelegramBot channel_post media", () => {
|
||||
const response = await params.fetchImpl(params.url);
|
||||
const buffer = new Uint8Array(await response.arrayBuffer());
|
||||
if (buffer.length > params.maxBytes) {
|
||||
throw new MediaFetchError("max_bytes", `media exceeds ${params.maxBytes} MB limit`);
|
||||
throw new MediaFetchError("max_bytes", `payload exceeds maxBytes ${params.maxBytes}`);
|
||||
}
|
||||
return {
|
||||
path: "/tmp/telegram-media.bin",
|
||||
@@ -507,7 +507,6 @@ describe("createTelegramBot channel_post media", () => {
|
||||
|
||||
it("dispatches an oversized channel_post as a type-only media fact", async () => {
|
||||
setOpenChannelPostConfig();
|
||||
|
||||
const fetchSpy = createImageFetchSpy({
|
||||
body: new Uint8Array([0xff, 0xd8, 0xff, 0x00]),
|
||||
contentType: "image/jpeg",
|
||||
@@ -525,6 +524,7 @@ describe("createTelegramBot channel_post media", () => {
|
||||
);
|
||||
|
||||
expect(replySpy).toHaveBeenCalledOnce();
|
||||
expect(sendMessageSpy).not.toHaveBeenCalled();
|
||||
expectTypeOnlyMediaPayload("image");
|
||||
fetchSpy.mockRestore();
|
||||
});
|
||||
@@ -608,21 +608,21 @@ describe("createTelegramBot channel_post media", () => {
|
||||
cause: Object.assign(new Error("aborted"), { name: "AbortError" }),
|
||||
}),
|
||||
result: { kind: "failed-retryable", error: expect.any(MediaFetchError) },
|
||||
warnings: 0,
|
||||
warning: undefined,
|
||||
},
|
||||
{
|
||||
name: "permanent oversized media",
|
||||
messageId: 98077,
|
||||
error: new MediaFetchError("max_bytes", "Failed to fetch media: payload exceeds maxBytes 10"),
|
||||
result: { kind: "completed" },
|
||||
warnings: 1,
|
||||
warning: "⚠️ File too large. Maximum size is 100MB.",
|
||||
},
|
||||
{
|
||||
name: "permanent SSRF rejection",
|
||||
messageId: 98078,
|
||||
error: new MediaFetchError("fetch_failed", "blocked by SSRF guard: private address"),
|
||||
result: { kind: "completed" },
|
||||
warnings: 1,
|
||||
warning: "⚠️ Failed to download media. Please try again.",
|
||||
},
|
||||
])("preserves durable replay handling for $name (#98076)", async (testCase) => {
|
||||
setOpenTelegramDirectConfig();
|
||||
@@ -640,13 +640,12 @@ describe("createTelegramBot channel_post media", () => {
|
||||
withTelegramSpooledReplayUpdate(update, () => handler(ctx)),
|
||||
);
|
||||
expect(result).toEqual(testCase.result);
|
||||
expect(sendMessageSpy).toHaveBeenCalledTimes(testCase.warnings);
|
||||
expect(replySpy).toHaveBeenCalledTimes(testCase.warnings);
|
||||
expect(sendMessageSpy.mock.calls[0]?.[1]).toEqual(
|
||||
[undefined, "⚠️ Failed to download media. Please try again."][testCase.warnings],
|
||||
);
|
||||
if (testCase.warnings) {
|
||||
expectTelegramDownloadWarning(testCase.messageId);
|
||||
const expectedWarnings = testCase.warning ? 1 : 0;
|
||||
expect(sendMessageSpy).toHaveBeenCalledTimes(expectedWarnings);
|
||||
expect(replySpy).toHaveBeenCalledTimes(expectedWarnings);
|
||||
expect(sendMessageSpy.mock.calls[0]?.[1]).toBe(testCase.warning);
|
||||
if (testCase.warning) {
|
||||
expectTelegramDownloadWarning(testCase.messageId, testCase.warning);
|
||||
expectTypeOnlyMediaPayload("document");
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user