test: stabilize maintainer prepare baseline

This commit is contained in:
Gio Della-Libera
2026-06-04 20:25:17 -07:00
parent 520992a1de
commit cbf66c346b
5 changed files with 88 additions and 15 deletions

View File

@@ -83,8 +83,8 @@ const SLACK_SUBTEAM_MENTION_RE = /<!subteam\^([^>|]+)(?:\|[^>]+)?>/g;
const SLACK_SUBTEAM_MENTION_MARKER = "<!subteam^";
const SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS = 4;
const SLACK_HISTORY_MEDIA_MAX_BYTES = 10 * 1024 * 1024;
const SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS = 1_000;
const SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS = 3_000;
const SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS = 10_000;
const SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS = 15_000;
function recordString(
record: Record<string, unknown> | undefined,

View File

@@ -124,6 +124,53 @@ function resolveFlushTimerForDelay(setTimeoutSpy: ReturnType<typeof vi.spyOn>, d
return flushTimer;
}
type ScheduledTimer = {
callback: () => unknown;
handle: ReturnType<typeof setTimeout>;
};
function resolveActiveScheduledTimersForDelay(
setTimeoutSpy: ReturnType<typeof vi.spyOn>,
clearTimeoutSpy: ReturnType<typeof vi.spyOn>,
delayMs: number,
): ScheduledTimer[] {
const clearedHandles = new Set(
(clearTimeoutSpy.mock.calls as Array<Parameters<typeof clearTimeout>>).map(
([handle]) => handle,
),
);
return (setTimeoutSpy.mock.calls as Array<Parameters<typeof setTimeout>>).flatMap(
(call, index) => {
if (call[1] !== delayMs) {
return [];
}
const handle = setTimeoutSpy.mock.results[index]?.value as ReturnType<typeof setTimeout>;
if (clearedHandles.has(handle) || typeof call[0] !== "function") {
return [];
}
return [{ callback: call[0] as () => unknown, handle }];
},
);
}
async function flushActiveScheduledTimersForDelay(params: {
setTimeoutSpy: ReturnType<typeof vi.spyOn>;
clearTimeoutSpy: ReturnType<typeof vi.spyOn>;
delayMs: number;
expectedCount: number;
}) {
const timers = resolveActiveScheduledTimersForDelay(
params.setTimeoutSpy,
params.clearTimeoutSpy,
params.delayMs,
);
expect(timers).toHaveLength(params.expectedCount);
for (const timer of timers) {
clearTimeout(timer.handle);
await timer.callback();
}
}
function createImageFetchSpy(params?: { body?: Uint8Array; contentType?: string }) {
return vi.spyOn(globalThis, "fetch").mockImplementation(
async () =>
@@ -139,12 +186,13 @@ async function waitForBufferedProcessing() {
}
async function waitForMockCalls(mock: { mock: { calls: unknown[] } }, count: number) {
for (let index = 0; index < 80; index++) {
for (let index = 0; index < 400; index++) {
if (mock.mock.calls.length >= count) {
return;
}
await delay(25);
}
throw new Error(`Timed out waiting for ${count} mock call(s); got ${mock.mock.calls.length}`);
}
function createChannelPostContext(params: {
@@ -271,8 +319,13 @@ describe("createTelegramBot channel_post media", () => {
setOpenChannelPostConfig();
const fetchSpy = createImageFetchSpy();
const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout");
let nextTimerHandle = 1;
const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout").mockImplementation(() => {
const handle = nextTimerHandle;
nextTimerHandle += 1;
return handle as unknown as ReturnType<typeof setTimeout>;
});
const clearTimeoutSpy = vi.spyOn(globalThis, "clearTimeout");
try {
const handler = getChannelPostHandler();
await queueChannelPostAlbum(handler, {
@@ -282,7 +335,12 @@ describe("createTelegramBot channel_post media", () => {
secondMessageId: 202,
});
expect(replySpy).not.toHaveBeenCalled();
await flushChannelPostMediaGroup(setTimeoutSpy);
await flushActiveScheduledTimersForDelay({
setTimeoutSpy,
clearTimeoutSpy,
delayMs: TELEGRAM_TEST_TIMINGS.mediaGroupFlushMs,
expectedCount: 1,
});
await waitForMockCalls(replySpy, 1);
await vi.waitFor(() => expect(replySpy).toHaveBeenCalledTimes(1));
@@ -290,6 +348,7 @@ describe("createTelegramBot channel_post media", () => {
expect(payload.Body).toContain("album caption");
} finally {
setTimeoutSpy.mockRestore();
clearTimeoutSpy.mockRestore();
fetchSpy.mockRestore();
}
});
@@ -311,7 +370,13 @@ describe("createTelegramBot channel_post media", () => {
});
const fetchSpy = createImageFetchSpy();
const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout");
let nextTimerHandle = 1;
const setTimeoutSpy = vi.spyOn(globalThis, "setTimeout").mockImplementation(() => {
const handle = nextTimerHandle;
nextTimerHandle += 1;
return handle as unknown as ReturnType<typeof setTimeout>;
});
const clearTimeoutSpy = vi.spyOn(globalThis, "clearTimeout");
try {
const handler = getChannelPostHandlerWithRuntimeTimings();
await queueChannelPostAlbum(handler, {
@@ -321,7 +386,12 @@ describe("createTelegramBot channel_post media", () => {
secondMessageId: 212,
});
expect(replySpy).not.toHaveBeenCalled();
await flushChannelPostMediaGroupForDelay(setTimeoutSpy, 75);
await flushActiveScheduledTimersForDelay({
setTimeoutSpy,
clearTimeoutSpy,
delayMs: 75,
expectedCount: 1,
});
await waitForMockCalls(replySpy, 1);
await vi.waitFor(() => expect(replySpy).toHaveBeenCalledTimes(1));
@@ -329,6 +399,7 @@ describe("createTelegramBot channel_post media", () => {
expect(payload.Body).toContain("configured album");
} finally {
setTimeoutSpy.mockRestore();
clearTimeoutSpy.mockRestore();
fetchSpy.mockRestore();
}
});

View File

@@ -10,7 +10,7 @@ import { handleInvoke } from "./invoke.js";
describe("node host invoke", () => {
it.runIf(process.platform !== "win32")(
"reports current allow-always coverage for prepared shell-wrapped system.run commands",
"reports current allow-always coverage for prepared system.run commands",
async () => {
const request = vi.fn<GatewayClient["request"]>().mockResolvedValue(null);
const skillBins: SkillBinsProvider = { current: async () => [] };
@@ -21,7 +21,7 @@ describe("node host invoke", () => {
nodeId: "node-1",
command: "system.run.prepare",
paramsJSON: JSON.stringify({
command: ["/bin/sh", "-lc", "/bin/echo ok"],
command: ["/bin/echo", "ok"],
rawCommand: "/bin/echo ok",
}),
},
@@ -29,7 +29,9 @@ describe("node host invoke", () => {
skillBins,
);
const result = request.mock.calls[0]?.[1] as { payloadJSON?: string } | undefined;
const result = request.mock.calls.find(([method]) => method === "node.invoke.result")?.[1] as
| { payloadJSON?: string }
| undefined;
const payload = JSON.parse(result?.payloadJSON ?? "{}") as {
allowAlwaysCoverage?: {
complete?: boolean;

View File

@@ -60,7 +60,7 @@ describe("E2E temp state dirs", () => {
}
});
it.runIf(process.platform !== "win32")(
it.runIf(process.platform !== "win32" && process.getuid?.() !== 0)(
"retries generated state cleanup after a failed removal",
async () => {
const root = mkdtempSync(path.join(tmpdir(), "openclaw-e2e-temp-state-retry-"));

View File

@@ -78,7 +78,7 @@ describe("package-mac-app plist stamping", () => {
writeFileSync(
corepackPath,
[
"#!/usr/bin/env bash",
"#!/bin/bash",
"set -euo pipefail",
'printf \'%s|%s\\n\' "$PWD" "$*" >> "$OPENCLAW_TEST_LOG"',
'if [[ "${1:-}" == "pnpm" && "${2:-}" == "--version" ]]; then',
@@ -95,7 +95,7 @@ describe("package-mac-app plist stamping", () => {
ROOT_DIR=${JSON.stringify(tempRoot)}
OPENCLAW_TEST_LOG=${JSON.stringify(logPath)}
export OPENCLAW_TEST_LOG
PATH=${JSON.stringify(`${toolsDir}:/usr/bin:/bin`)}
PATH=${JSON.stringify(toolsDir)}
${helperBlock}
run_pnpm install --frozen-lockfile --config.node-linker=hoisted
run_pnpm build
@@ -118,7 +118,7 @@ describe("package-mac-app plist stamping", () => {
const result = runHelper(`
set -euo pipefail
ROOT_DIR=${JSON.stringify(tempRoot)}
PATH=${JSON.stringify(`${toolsDir}:/usr/bin:/bin`)}
PATH=${JSON.stringify(toolsDir)}
${helperBlock}
run_pnpm build
`);