openclaw/extensions/telegram/src/error-policy.test.ts

161 lines
3.6 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
buildTelegramErrorScopeKey,
resolveTelegramErrorPolicy,
resetTelegramErrorPolicyStoreForTest,
shouldSuppressTelegramError,
} from "./error-policy.js";
describe("telegram error policy", () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date("2026-01-01T00:00:00Z"));
resetTelegramErrorPolicyStoreForTest();
});
afterEach(() => {
resetTelegramErrorPolicyStoreForTest();
vi.useRealTimers();
});
it("resolves policy and cooldown from the most specific config", () => {
expect(
resolveTelegramErrorPolicy({
accountConfig: { errorPolicy: "once", errorCooldownMs: 1000 },
groupConfig: { errorCooldownMs: 2000 },
topicConfig: { errorPolicy: "silent" },
}),
).toEqual({
policy: "silent",
cooldownMs: 2000,
});
});
it("suppresses only repeated matching errors within the same scope", () => {
const scopeKey = buildTelegramErrorScopeKey({
accountId: "work",
chatId: 42,
threadId: 7,
});
expect(
shouldSuppressTelegramError({
scopeKey,
cooldownMs: 1000,
errorMessage: "429",
}),
).toBe(false);
expect(
shouldSuppressTelegramError({
scopeKey,
cooldownMs: 1000,
errorMessage: "429",
}),
).toBe(true);
expect(
shouldSuppressTelegramError({
scopeKey,
cooldownMs: 1000,
errorMessage: "403",
}),
).toBe(false);
});
it("keeps cooldowns per error message within the same scope", () => {
const scopeKey = buildTelegramErrorScopeKey({
accountId: "work",
chatId: 42,
});
expect(
shouldSuppressTelegramError({
scopeKey,
cooldownMs: 1000,
errorMessage: "A",
}),
).toBe(false);
expect(
shouldSuppressTelegramError({
scopeKey,
cooldownMs: 1000,
errorMessage: "B",
}),
).toBe(false);
expect(
shouldSuppressTelegramError({
scopeKey,
cooldownMs: 1000,
errorMessage: "A",
}),
).toBe(true);
});
it("prunes expired cooldowns within a single scope", () => {
const scopeKey = buildTelegramErrorScopeKey({
accountId: "work",
chatId: 42,
});
expect(
shouldSuppressTelegramError({
scopeKey,
cooldownMs: 1000,
errorMessage: "A",
}),
).toBe(false);
vi.advanceTimersByTime(1001);
expect(
shouldSuppressTelegramError({
scopeKey,
cooldownMs: 1000,
errorMessage: "B",
}),
).toBe(false);
expect(
shouldSuppressTelegramError({
scopeKey,
cooldownMs: 1000,
errorMessage: "A",
}),
).toBe(false);
});
it("does not leak suppression across accounts or threads", () => {
const workMain = buildTelegramErrorScopeKey({
accountId: "work",
chatId: 42,
});
const personalMain = buildTelegramErrorScopeKey({
accountId: "personal",
chatId: 42,
});
const workTopic = buildTelegramErrorScopeKey({
accountId: "work",
chatId: 42,
threadId: 9,
});
expect(
shouldSuppressTelegramError({
scopeKey: workMain,
cooldownMs: 1000,
errorMessage: "429",
}),
).toBe(false);
expect(
shouldSuppressTelegramError({
scopeKey: personalMain,
cooldownMs: 1000,
errorMessage: "429",
}),
).toBe(false);
expect(
shouldSuppressTelegramError({
scopeKey: workTopic,
cooldownMs: 1000,
errorMessage: "429",
}),
).toBe(false);
});
});