mirror of https://github.com/openclaw/openclaw.git
test: speed up telegram extension suites
This commit is contained in:
parent
db4572b459
commit
83bb647238
|
|
@ -1,5 +1,5 @@
|
|||
import type { Bot } from "grammy";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { TelegramBotDeps } from "./bot-deps.js";
|
||||
import {
|
||||
createSequencedTestDraftStream,
|
||||
|
|
@ -120,9 +120,12 @@ const telegramDepsForTest: TelegramBotDeps = {
|
|||
describe("dispatchTelegramMessage draft streaming", () => {
|
||||
type TelegramMessageContext = Parameters<typeof dispatchTelegramMessage>[0]["context"];
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ dispatchTelegramMessage } = await import("./bot-message-dispatch.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
createTelegramDraftStream.mockClear();
|
||||
dispatchReplyWithBufferedBlockDispatcher.mockClear();
|
||||
deliverReplies.mockClear();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { TelegramBotDeps } from "./bot-deps.js";
|
||||
|
||||
const buildTelegramMessageContext = vi.hoisted(() => vi.fn());
|
||||
|
|
@ -18,12 +18,15 @@ vi.mock("./bot-message-dispatch.js", () => ({
|
|||
let createTelegramMessageProcessor: typeof import("./bot-message.js").createTelegramMessageProcessor;
|
||||
|
||||
describe("telegram bot message processor", () => {
|
||||
beforeEach(async () => {
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ createTelegramMessageProcessor } = await import("./bot-message.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
buildTelegramMessageContext.mockClear();
|
||||
dispatchTelegramMessage.mockClear();
|
||||
upsertChannelPairingRequest.mockClear();
|
||||
({ createTelegramMessageProcessor } = await import("./bot-message.js"));
|
||||
});
|
||||
|
||||
const telegramDepsForTest = {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ const {
|
|||
useSpy,
|
||||
} = harness;
|
||||
let resolveTelegramFetch: typeof import("./fetch.js").resolveTelegramFetch;
|
||||
let setTelegramBotRuntimeForTest: typeof import("./bot.js").setTelegramBotRuntimeForTest;
|
||||
let createTelegramBotBase: typeof import("./bot.js").createTelegramBot;
|
||||
let createTelegramBot: (
|
||||
opts: Parameters<typeof import("./bot.js").createTelegramBot>[0],
|
||||
) => ReturnType<typeof import("./bot.js").createTelegramBot>;
|
||||
|
|
@ -79,21 +81,22 @@ describe("createTelegramBot", () => {
|
|||
beforeAll(() => {
|
||||
process.env.TZ = "UTC";
|
||||
});
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ resolveTelegramFetch } = await import("./fetch.js"));
|
||||
({
|
||||
createTelegramBot: createTelegramBotBase,
|
||||
getTelegramSequentialKey,
|
||||
setTelegramBotRuntimeForTest,
|
||||
} = await import("./bot.js"));
|
||||
});
|
||||
afterAll(() => {
|
||||
process.env.TZ = ORIGINAL_TZ;
|
||||
});
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
({ resolveTelegramFetch } = await import("./fetch.js"));
|
||||
const {
|
||||
createTelegramBot: createTelegramBotBase,
|
||||
getTelegramSequentialKey: importedGetTelegramSequentialKey,
|
||||
setTelegramBotRuntimeForTest,
|
||||
} = await import("./bot.js");
|
||||
beforeEach(() => {
|
||||
setTelegramBotRuntimeForTest(
|
||||
telegramBotRuntimeForTest as unknown as Parameters<typeof setTelegramBotRuntimeForTest>[0],
|
||||
);
|
||||
getTelegramSequentialKey = importedGetTelegramSequentialKey;
|
||||
createTelegramBot = (opts) =>
|
||||
createTelegramBotBase({
|
||||
...opts,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ let listNativeCommandSpecs: typeof import("../../../src/auto-reply/commands-regi
|
|||
let listNativeCommandSpecsForConfig: typeof import("../../../src/auto-reply/commands-registry.js").listNativeCommandSpecsForConfig;
|
||||
let loadSessionStore: typeof import("../../../src/config/sessions.js").loadSessionStore;
|
||||
let normalizeTelegramCommandName: typeof import("../../../src/config/telegram-custom-commands.js").normalizeTelegramCommandName;
|
||||
let createTelegramBotBase: typeof import("./bot.js").createTelegramBot;
|
||||
let setTelegramBotRuntimeForTest: typeof import("./bot.js").setTelegramBotRuntimeForTest;
|
||||
let createTelegramBot: (
|
||||
opts: Parameters<typeof import("./bot.js").createTelegramBot>[0],
|
||||
) => ReturnType<typeof import("./bot.js").createTelegramBot>;
|
||||
|
|
@ -48,6 +50,16 @@ function resolveSkillCommands(config: Parameters<typeof listNativeCommandSpecsFo
|
|||
|
||||
const ORIGINAL_TZ = process.env.TZ;
|
||||
describe("createTelegramBot", () => {
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ listNativeCommandSpecs, listNativeCommandSpecsForConfig } =
|
||||
await import("../../../src/auto-reply/commands-registry.js"));
|
||||
({ loadSessionStore } = await import("../../../src/config/sessions.js"));
|
||||
({ normalizeTelegramCommandName } =
|
||||
await import("../../../src/config/telegram-custom-commands.js"));
|
||||
({ createTelegramBot: createTelegramBotBase, setTelegramBotRuntimeForTest } =
|
||||
await import("./bot.js"));
|
||||
});
|
||||
beforeAll(() => {
|
||||
process.env.TZ = "UTC";
|
||||
});
|
||||
|
|
@ -68,16 +80,6 @@ describe("createTelegramBot", () => {
|
|||
telegram: { dmPolicy: "open", allowFrom: ["*"] },
|
||||
},
|
||||
});
|
||||
});
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
({ listNativeCommandSpecs, listNativeCommandSpecsForConfig } =
|
||||
await import("../../../src/auto-reply/commands-registry.js"));
|
||||
({ loadSessionStore } = await import("../../../src/config/sessions.js"));
|
||||
({ normalizeTelegramCommandName } =
|
||||
await import("../../../src/config/telegram-custom-commands.js"));
|
||||
const { createTelegramBot: createTelegramBotBase, setTelegramBotRuntimeForTest } =
|
||||
await import("./bot.js");
|
||||
setTelegramBotRuntimeForTest(
|
||||
telegramBotRuntimeForTest as unknown as Parameters<typeof setTelegramBotRuntimeForTest>[0],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const setDefaultResultOrder = vi.hoisted(() => vi.fn());
|
||||
const setDefaultAutoSelectFamily = vi.hoisted(() => vi.fn());
|
||||
|
|
@ -58,12 +58,16 @@ let resolveFetch: typeof import("../../../src/infra/fetch.js").resolveFetch;
|
|||
let resolveTelegramFetch: typeof import("./fetch.js").resolveTelegramFetch;
|
||||
let resolveTelegramTransport: typeof import("./fetch.js").resolveTelegramTransport;
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ resolveFetch } = await import("../../../src/infra/fetch.js"));
|
||||
({ resolveTelegramFetch, resolveTelegramTransport } = await import("./fetch.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
function resolveTelegramFetchOrThrow(
|
||||
proxyFetch?: typeof fetch,
|
||||
options?: { network?: { autoSelectFamily?: boolean; dnsResultOrder?: "ipv4first" | "verbatim" } },
|
||||
|
|
@ -218,7 +222,6 @@ afterEach(() => {
|
|||
ProxyAgentCtor.mockClear();
|
||||
setDefaultResultOrder.mockReset();
|
||||
setDefaultAutoSelectFamily.mockReset();
|
||||
vi.unstubAllEnvs();
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
type MonitorTelegramOpts = import("./monitor.js").MonitorTelegramOpts;
|
||||
let monitorTelegramProvider: typeof import("./monitor.js").monitorTelegramProvider;
|
||||
|
||||
type MockCtx = {
|
||||
message: {
|
||||
|
|
@ -137,7 +138,6 @@ function mockRunOnceAndAbort(abort: AbortController) {
|
|||
}
|
||||
|
||||
async function expectOffsetConfirmationSkipped(offset: number | null) {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
readTelegramUpdateOffsetSpy.mockResolvedValueOnce(offset);
|
||||
const abort = new AbortController();
|
||||
api.getUpdates.mockReset();
|
||||
|
|
@ -151,7 +151,6 @@ async function expectOffsetConfirmationSkipped(offset: number | null) {
|
|||
}
|
||||
|
||||
async function runMonitorAndCaptureStartupOrder(params?: { persistedOffset?: number | null }) {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
if (params && "persistedOffset" in params) {
|
||||
readTelegramUpdateOffsetSpy.mockResolvedValueOnce(params.persistedOffset ?? null);
|
||||
}
|
||||
|
|
@ -233,7 +232,6 @@ function expectRecoverableRetryState(
|
|||
}
|
||||
|
||||
async function monitorWithAutoAbort(opts: Omit<MonitorTelegramOpts, "abortSignal"> = {}) {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
const abort = new AbortController();
|
||||
mockRunOnceAndAbort(abort);
|
||||
await monitorTelegramProvider({
|
||||
|
|
@ -337,8 +335,12 @@ vi.mock("../../../src/auto-reply/reply.js", () => ({
|
|||
describe("monitorTelegramProvider (grammY)", () => {
|
||||
let consoleErrorSpy: { mockRestore: () => void } | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ monitorTelegramProvider } = await import("./monitor.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
loadConfig.mockReturnValue({
|
||||
agents: { defaults: { maxConcurrent: 2 } },
|
||||
channels: { telegram: {} },
|
||||
|
|
@ -434,7 +436,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("retries on recoverable undici fetch errors", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
const abort = new AbortController();
|
||||
const networkError = makeRecoverableFetchError();
|
||||
runSpy
|
||||
|
|
@ -458,7 +459,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("retries recoverable deleteWebhook failures before polling", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
const abort = new AbortController();
|
||||
const cleanupError = makeRecoverableFetchError();
|
||||
api.deleteWebhook.mockReset();
|
||||
|
|
@ -472,7 +472,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("retries setup-time recoverable errors before starting polling", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
const abort = new AbortController();
|
||||
const setupError = makeRecoverableFetchError();
|
||||
createTelegramBotErrors.push(setupError);
|
||||
|
|
@ -484,7 +483,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("awaits runner.stop before retrying after recoverable polling error", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
const abort = new AbortController();
|
||||
const recoverableError = makeRecoverableFetchError();
|
||||
let firstStopped = false;
|
||||
|
|
@ -512,7 +510,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("stops bot instance when polling cycle exits", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
const abort = new AbortController();
|
||||
mockRunOnceAndAbort(abort);
|
||||
|
||||
|
|
@ -523,7 +520,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("clears bounded cleanup timers after a clean stop", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
vi.useFakeTimers();
|
||||
try {
|
||||
const abort = new AbortController();
|
||||
|
|
@ -538,7 +534,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("surfaces non-recoverable errors", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
runSpy.mockImplementationOnce(() =>
|
||||
makeRunnerStub({
|
||||
task: () => Promise.reject(new Error("bad token")),
|
||||
|
|
@ -549,7 +544,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("force-restarts polling when unhandled network rejection stalls runner", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
const abort = new AbortController();
|
||||
const firstCycle = mockRunOnceWithStalledPollingRunner();
|
||||
mockRunOnceWithStalledPollingRunner();
|
||||
|
|
@ -566,7 +560,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("reuses the resolved transport across polling restarts", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
vi.useFakeTimers({ shouldAdvanceTime: true });
|
||||
try {
|
||||
const telegramTransport = {
|
||||
|
|
@ -595,7 +588,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("aborts the active Telegram fetch when unhandled network rejection forces restart", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
const abort = new AbortController();
|
||||
const { stop, waitForTaskStart } = mockRunOnceWithStalledPollingRunner();
|
||||
mockRunOnceAndAbort(abort);
|
||||
|
|
@ -615,7 +607,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("ignores unrelated process-level network errors while telegram polling is active", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
const abort = new AbortController();
|
||||
const { stop } = mockRunOnceWithStalledPollingRunner();
|
||||
|
||||
|
|
@ -641,7 +632,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("passes configured webhookHost to webhook listener", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
await monitorTelegramProvider({
|
||||
token: "tok",
|
||||
useWebhook: true,
|
||||
|
|
@ -666,7 +656,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("webhook mode waits for abort signal before returning", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
const abort = new AbortController();
|
||||
const settled = vi.fn();
|
||||
const monitor = monitorTelegramProvider({
|
||||
|
|
@ -686,7 +675,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("force-restarts polling when getUpdates stalls (watchdog)", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
vi.useFakeTimers({ shouldAdvanceTime: true });
|
||||
const abort = new AbortController();
|
||||
const { stop } = mockRunOnceWithStalledPollingRunner();
|
||||
|
|
@ -726,7 +714,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("resets webhookCleared latch on 409 conflict so deleteWebhook re-runs", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
const abort = new AbortController();
|
||||
api.deleteWebhook.mockReset();
|
||||
api.deleteWebhook.mockResolvedValue(true);
|
||||
|
|
@ -765,7 +752,6 @@ describe("monitorTelegramProvider (grammY)", () => {
|
|||
});
|
||||
|
||||
it("falls back to configured webhookSecret when not passed explicitly", async () => {
|
||||
const { monitorTelegramProvider } = await import("./monitor.js");
|
||||
await monitorTelegramProvider({
|
||||
token: "tok",
|
||||
useWebhook: true,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { afterEach, beforeEach, type Mock, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeAll, beforeEach, type Mock, describe, expect, it, vi } from "vitest";
|
||||
import { withFetchPreconnect } from "../../../test/helpers/extensions/fetch-mock.js";
|
||||
|
||||
const resolveTelegramFetch = vi.hoisted(() => vi.fn());
|
||||
|
|
@ -72,7 +72,7 @@ describe("probeTelegram retry logic", () => {
|
|||
}
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ probeTelegram, resetTelegramProbeFetcherCacheForTests } = await import("./probe.js"));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,16 +1,26 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import { createTelegramSendChatActionHandler } from "./sendchataction-401-backoff.js";
|
||||
import { beforeAll, describe, expect, it, vi } from "vitest";
|
||||
|
||||
// Mock the backoff sleep to avoid real delays in tests
|
||||
vi.mock("../../../src/infra/backoff.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../../../src/infra/backoff.js")>();
|
||||
const mocks = vi.hoisted(() => ({
|
||||
sleepWithAbort: vi.fn().mockResolvedValue(undefined),
|
||||
}));
|
||||
|
||||
// Mock the runtime-exported backoff sleep that the handler actually imports.
|
||||
vi.mock("openclaw/plugin-sdk/infra-runtime", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/infra-runtime")>();
|
||||
return {
|
||||
...actual,
|
||||
sleepWithAbort: vi.fn().mockResolvedValue(undefined),
|
||||
sleepWithAbort: mocks.sleepWithAbort,
|
||||
};
|
||||
});
|
||||
|
||||
let createTelegramSendChatActionHandler: typeof import("./sendchataction-401-backoff.js").createTelegramSendChatActionHandler;
|
||||
|
||||
describe("createTelegramSendChatActionHandler", () => {
|
||||
beforeAll(async () => {
|
||||
vi.resetModules();
|
||||
({ createTelegramSendChatActionHandler } = await import("./sendchataction-401-backoff.js"));
|
||||
});
|
||||
|
||||
const make401Error = () => new Error("401 Unauthorized");
|
||||
const make500Error = () => new Error("500 Internal Server Error");
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue