test(release): repair plugin prerelease coverage

This commit is contained in:
Peter Steinberger
2026-07-17 13:43:12 +01:00
parent 363e8b09ec
commit f341a013af
8 changed files with 66 additions and 53 deletions
@@ -240,6 +240,7 @@ describe("codex media understanding provider", () => {
"You are OpenClaw's bounded image-understanding worker. Describe only the provided image content. Do not call tools, edit files, or ask follow-up questions.",
config: {
"features.apps": false,
"features.goals": false,
"features.code_mode": false,
"features.code_mode_only": false,
"features.image_generation": false,
@@ -535,6 +536,7 @@ describe("codex media understanding provider", () => {
"You are OpenClaw's bounded structured-extraction worker. Return only the requested extraction. Do not call tools, edit files, ask follow-up questions, or include secrets.",
config: {
"features.apps": false,
"features.goals": false,
"features.code_mode": false,
"features.code_mode_only": false,
"features.image_generation": false,
@@ -1,4 +1,8 @@
import type { AuthProfileStore } from "openclaw/plugin-sdk/agent-runtime";
import {
clearRuntimeAuthProfileStoreSnapshots,
replaceRuntimeAuthProfileStoreSnapshots,
type AuthProfileStore,
} from "openclaw/plugin-sdk/agent-runtime";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
fingerprintCodexAppServerAuthBinding,
@@ -6,9 +10,12 @@ import {
} from "./auth-binding.js";
describe("Codex app-server auth binding", () => {
afterEach(() => vi.unstubAllEnvs());
afterEach(() => {
clearRuntimeAuthProfileStoreSnapshots();
vi.unstubAllEnvs();
});
it("materializes a SecretRef once and fingerprints the executed store", async () => {
it("uses the materialized runtime SecretRef snapshot and fingerprints the executed store", async () => {
const profileId = "openai:work";
const store: AuthProfileStore = {
version: 1,
@@ -28,7 +35,25 @@ describe("Codex app-server auth binding", () => {
auth: { profiles: { [profileId]: { provider: "openai", mode: "api_key" as const } } },
},
};
vi.stubEnv("OPENAI_WORK_KEY", "work-key-a");
const publishRuntimeKey = (key: string) => {
replaceRuntimeAuthProfileStoreSnapshots([
{
agentDir: params.agentDir,
store: {
version: 1,
profiles: {
[profileId]: {
type: "api_key",
provider: "openai",
keyRef: { source: "env", provider: "default", id: "OPENAI_WORK_KEY" },
key,
},
},
},
},
]);
};
publishRuntimeKey("work-key-a");
const prepared = await prepareCodexAppServerAuthBinding(params);
expect(prepared?.authProfileStore).not.toBe(store);
@@ -44,7 +69,7 @@ describe("Codex app-server auth binding", () => {
});
expect(await fingerprintCodexAppServerAuthBinding(params)).toBe(prepared?.fingerprint);
vi.stubEnv("OPENAI_WORK_KEY", "work-key-b");
publishRuntimeKey("work-key-b");
expect(await fingerprintCodexAppServerAuthBinding(params)).not.toBe(prepared?.fingerprint);
});
});
@@ -640,6 +640,7 @@ describe("runCodexAppServerSideQuestion", () => {
expect(forkParams?.approvalsReviewer).toBe("user");
expect(forkParams?.cwd).toBe("/tmp/workspace");
expect(forkParams?.config).toEqual({
"features.goals": false,
"features.code_mode": true,
"features.code_mode_only": false,
"features.apply_patch_streaming_events": true,
@@ -92,6 +92,7 @@ function createParams(sessionFile: string, workspaceDir: string) {
}
const DEFAULT_CODEX_RUNTIME_THREAD_CONFIG = {
"features.goals": false,
"features.code_mode": true,
"features.code_mode_only": false,
"features.apply_patch_streaming_events": true,
@@ -3,6 +3,7 @@ import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import type { GetReplyOptions, MsgContext } from "openclaw/plugin-sdk/reply-runtime";
import { getSessionEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
import type { waitForTransportReady } from "openclaw/plugin-sdk/transport-ready-runtime";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { createIMessageRpcClient } from "./client.js";
@@ -37,7 +38,6 @@ const waitForTransportReadyMock = vi.hoisted(() =>
);
const createIMessageRpcClientMock = vi.hoisted(() => vi.fn<typeof createIMessageRpcClient>());
const readChannelAllowFromStoreMock = vi.hoisted(() => vi.fn(async () => [] as string[]));
const recordInboundSessionMock = vi.hoisted(() => vi.fn(async (_params: unknown) => {}));
const dispatchInboundMessageMock = vi.hoisted(() =>
vi.fn(
async (_params: DispatchInboundMessageParams) =>
@@ -92,7 +92,6 @@ vi.mock("openclaw/plugin-sdk/conversation-runtime", async (importOriginal) => {
return {
...actual,
readChannelAllowFromStore: readChannelAllowFromStoreMock,
recordInboundSession: recordInboundSessionMock,
upsertChannelPairingRequest: vi.fn(),
};
});
@@ -130,7 +129,6 @@ describe("iMessage monitor last-route updates", () => {
waitForTransportReadyMock.mockReset().mockResolvedValue(undefined);
createIMessageRpcClientMock.mockReset();
readChannelAllowFromStoreMock.mockReset().mockResolvedValue([]);
recordInboundSessionMock.mockClear();
dispatchInboundMessageMock.mockClear();
createChannelInboundDebouncerMock.mockClear();
debouncerControl.reset();
@@ -933,6 +931,11 @@ describe("iMessage monitor last-route updates", () => {
);
it("keeps per-channel-peer direct-message last-route writes on the isolated session", async () => {
const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-imsg-last-route-"));
tempDirs.push(stateDir);
const configuredStore = path.join(stateDir, "sessions.json");
const storePath = resolveStorePath(configuredStore, { agentId: "main" });
const sessionKey = "agent:main:imessage:direct:+15550001111";
const runtimeErrorMock = vi.fn();
let onNotification: ((message: { method: string; params: unknown }) => void) | undefined;
const client = {
@@ -969,7 +972,7 @@ describe("iMessage monitor last-route updates", () => {
config: {
channels: { imessage: { dmPolicy: "allowlist", allowFrom: ["+15550001111"] } },
messages: { inbound: { debounceMs: 0 } },
session: { dmScope: "per-channel-peer", mainKey: "main" },
session: { dmScope: "per-channel-peer", mainKey: "main", store: configuredStore },
} as never,
runtime: { error: runtimeErrorMock, exit: vi.fn(), log: vi.fn() },
});
@@ -979,25 +982,13 @@ describe("iMessage monitor last-route updates", () => {
});
expect(runtimeErrorMock).not.toHaveBeenCalled();
await vi.waitFor(() => {
expect(recordInboundSessionMock).toHaveBeenCalledTimes(1);
expect(getSessionEntry({ storePath, sessionKey })).toMatchObject({
lastChannel: "imessage",
lastTo: "imessage:+15550001111",
lastAccountId: "default",
});
});
const recordParams = recordInboundSessionMock.mock.calls.at(0)?.[0] as
| {
sessionKey?: string;
updateLastRoute?: {
channel?: string;
mainDmOwnerPin?: unknown;
sessionKey?: string;
to?: string;
};
}
| undefined;
expect(recordParams?.sessionKey).toBe("agent:main:imessage:direct:+15550001111");
expect(recordParams?.updateLastRoute?.sessionKey).toBe(recordParams?.sessionKey);
expect(recordParams?.updateLastRoute?.sessionKey).not.toBe("agent:main:main");
expect(recordParams?.updateLastRoute?.channel).toBe("imessage");
expect(recordParams?.updateLastRoute?.to).toBe("imessage:+15550001111");
expect(recordParams?.updateLastRoute?.mainDmOwnerPin).toBeUndefined();
expect(getSessionEntry({ storePath, sessionKey: "agent:main:main" })).toBeUndefined();
});
it("suppresses stale backlog rows but dispatches fresh live rows", async () => {
@@ -18,8 +18,8 @@ describe("ConsoleLogger", () => {
);
const message = spy.mock.calls[0]?.[0];
expect(message).toBe(
"[MatrixHttpClient] Authorization: Bearer ***:abcdefghijklmnopqrstuvwxyzABCDEFG",
);
expect(message).toContain("[MatrixHttpClient] Authorization: Bearer ");
expect(message).not.toContain("123456:abcdefghijklmnopqrstuvwxyzABCDEFG");
expect(message).not.toContain("abcdefghijklmnopqrstuvwxyzABCDEFG");
});
});
@@ -976,12 +976,8 @@ describe("msteams monitor handler authz", () => {
);
const ctx = recordFromMockCall(ctxPayload);
expect(ctx.SupplementalContext).toMatchObject({
quote: {
body: "Quoted body",
sender: "Alice",
},
});
expect(ctx.ReplyToBody).toBe("Quoted body");
expect(ctx.ReplyToSender).toBe("Alice");
});
it("drops quote context when attachment metadata disagrees with a blocked parent sender", async () => {
@@ -994,7 +990,8 @@ describe("msteams monitor handler authz", () => {
);
const ctx = recordFromMockCall(ctxPayload);
expect(ctx.SupplementalContext).toEqual({});
expect(ctx.ReplyToBody).toBeUndefined();
expect(ctx.ReplyToSender).toBeUndefined();
expect(ctx.BodyForAgent).toBe("Current message");
});
@@ -1027,7 +1024,7 @@ describe("msteams monitor handler authz", () => {
// group chat: the fetched body would bypass the supplemental-quote visibility
// allowlist. Only 1:1 DMs may fetch full text.
const ctx = recordFromMockCall(firstSettledDispatch().ctxPayload);
expect(ctx.SupplementalContext).toMatchObject({ quote: { body: "secret snippet…" } });
expect(ctx.ReplyToBody).toBe("secret snippet…");
expect(graphThreadMockState.fetchChatMessageText).not.toHaveBeenCalled();
});
@@ -1067,10 +1064,9 @@ describe("msteams monitor handler authz", () => {
timeoutMs: 10_000,
}),
);
expect(recordFromMockCall(firstSettledDispatch().ctxPayload).SupplementalContext).toMatchObject(
{
quote: { id: "message-1", body: "complete quoted message", sender: "Bot" },
},
);
const ctx = recordFromMockCall(firstSettledDispatch().ctxPayload);
expect(ctx.ReplyToId).toBe("message-1");
expect(ctx.ReplyToBody).toBe("complete quoted message");
expect(ctx.ReplyToSender).toBe("Bot");
});
});
@@ -114,7 +114,9 @@ function makeInbound(overrides: Partial<InboundContext> = {}): InboundContext {
};
}
function makeInboundRuntime(): GatewayPluginRuntime["channel"]["inbound"] {
function makeInboundRuntime(
onResolvedContext?: (ctx: Record<string, unknown>) => void,
): GatewayPluginRuntime["channel"]["inbound"] {
return {
run: vi.fn(async (rawParams: unknown) => {
const params = rawParams as {
@@ -132,7 +134,8 @@ function makeInboundRuntime(): GatewayPluginRuntime["channel"]["inbound"] {
kind: "message",
},
{},
)) as { runDispatch: () => Promise<unknown> };
)) as { ctxPayload: Record<string, unknown>; runDispatch: () => Promise<unknown> };
onResolvedContext?.(turn.ctxPayload);
return { dispatchResult: await turn.runDispatch() };
}),
};
@@ -208,10 +211,7 @@ function makeRuntime(params: {
await dispatcherOptions.onFreshSettledDelivery?.();
}
}),
finalizeInboundContext: vi.fn((rawCtx: Record<string, unknown>) => {
params.onFinalize?.(rawCtx);
return rawCtx;
}),
finalizeInboundContext: vi.fn((rawCtx: Record<string, unknown>) => rawCtx),
formatInboundEnvelope: vi.fn(() => "voice"),
resolveEffectiveMessagesConfig: vi.fn(() => ({})),
resolveEnvelopeFormatOptions: vi.fn(() => ({})),
@@ -220,7 +220,7 @@ function makeRuntime(params: {
resolveStorePath: vi.fn(() => "/tmp/openclaw/qqbot-sessions.json"),
recordInboundSession: vi.fn(async () => undefined),
},
inbound: makeInboundRuntime(),
inbound: makeInboundRuntime(params.onFinalize),
text: {
chunkMarkdownText: (text: string) => [text],
},
@@ -575,9 +575,6 @@ describe("dispatchOutbound", () => {
expect.anything(),
"assistant",
);
expect(runtime.channel.session.resolveStorePath).toHaveBeenCalledWith(undefined, {
agentId: "assistant",
});
expect(finalized?.AgentId).toBe("assistant");
} finally {
await fs.rm(tmpRoot, { recursive: true, force: true });