mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-18 21:40:53 +00:00
test: extract exec approval session target coverage
This commit is contained in:
@@ -1,6 +1,3 @@
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { telegramOutbound } from "../channels/plugins/outbound/telegram.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
@@ -380,58 +377,6 @@ describe("exec approval forwarder", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("prefers turn-source routing over stale session last route", async () => {
|
||||
vi.useFakeTimers();
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-exec-approval-forwarder-test-"));
|
||||
try {
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
fs.writeFileSync(
|
||||
storePath,
|
||||
JSON.stringify({
|
||||
"agent:main:main": {
|
||||
updatedAt: 1,
|
||||
channel: "slack",
|
||||
to: "U1",
|
||||
lastChannel: "slack",
|
||||
lastTo: "U1",
|
||||
},
|
||||
}),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const cfg = {
|
||||
session: { store: storePath },
|
||||
approvals: { exec: { enabled: true, mode: "session" } },
|
||||
} as OpenClawConfig;
|
||||
|
||||
const { deliver, forwarder } = createForwarder({ cfg });
|
||||
await expect(
|
||||
forwarder.handleRequested({
|
||||
...baseRequest,
|
||||
request: {
|
||||
...baseRequest.request,
|
||||
turnSourceChannel: "whatsapp",
|
||||
turnSourceTo: "+15555550123",
|
||||
turnSourceAccountId: "work",
|
||||
turnSourceThreadId: "1739201675.123",
|
||||
},
|
||||
}),
|
||||
).resolves.toBe(true);
|
||||
|
||||
expect(deliver).toHaveBeenCalledTimes(1);
|
||||
expect(deliver).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
channel: "whatsapp",
|
||||
to: "+15555550123",
|
||||
accountId: "work",
|
||||
threadId: 1739201675,
|
||||
}),
|
||||
);
|
||||
} finally {
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
it("can forward resolved notices without pending cache when request payload is present", async () => {
|
||||
vi.useFakeTimers();
|
||||
const cfg = {
|
||||
|
||||
189
src/infra/exec-approval-session-target.test.ts
Normal file
189
src/infra/exec-approval-session-target.test.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import type { SessionEntry } from "../config/sessions.js";
|
||||
import { resolveExecApprovalSessionTarget } from "./exec-approval-session-target.js";
|
||||
import type { ExecApprovalRequest } from "./exec-approvals.js";
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
afterEach(() => {
|
||||
for (const dir of tempDirs.splice(0)) {
|
||||
fs.rmSync(dir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
const baseRequest: ExecApprovalRequest = {
|
||||
id: "req-1",
|
||||
request: {
|
||||
command: "echo hello",
|
||||
sessionKey: "agent:main:main",
|
||||
},
|
||||
createdAtMs: 1000,
|
||||
expiresAtMs: 6000,
|
||||
};
|
||||
|
||||
function createTempDir(): string {
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-exec-approval-session-target-"));
|
||||
tempDirs.push(dir);
|
||||
return dir;
|
||||
}
|
||||
|
||||
function writeStoreFile(
|
||||
storePath: string,
|
||||
entries: Record<string, Partial<SessionEntry>>,
|
||||
): OpenClawConfig {
|
||||
fs.mkdirSync(path.dirname(storePath), { recursive: true });
|
||||
fs.writeFileSync(storePath, JSON.stringify(entries), "utf-8");
|
||||
return {
|
||||
session: { store: storePath },
|
||||
} as OpenClawConfig;
|
||||
}
|
||||
|
||||
describe("exec approval session target", () => {
|
||||
it("returns null for blank session keys, missing entries, and unresolved targets", () => {
|
||||
const tmpDir = createTempDir();
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const cfg = writeStoreFile(storePath, {
|
||||
"agent:main:main": {
|
||||
sessionId: "main",
|
||||
updatedAt: 1,
|
||||
lastChannel: "slack",
|
||||
},
|
||||
});
|
||||
|
||||
const cases = [
|
||||
{
|
||||
request: {
|
||||
...baseRequest,
|
||||
request: {
|
||||
...baseRequest.request,
|
||||
sessionKey: " ",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
request: {
|
||||
...baseRequest,
|
||||
request: {
|
||||
...baseRequest.request,
|
||||
sessionKey: "agent:main:missing",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
request: baseRequest,
|
||||
},
|
||||
];
|
||||
|
||||
for (const testCase of cases) {
|
||||
expect(
|
||||
resolveExecApprovalSessionTarget({
|
||||
cfg,
|
||||
request: testCase.request,
|
||||
}),
|
||||
).toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it("prefers turn-source routing over stale session delivery state", () => {
|
||||
const tmpDir = createTempDir();
|
||||
const storePath = path.join(tmpDir, "sessions.json");
|
||||
const cfg = writeStoreFile(storePath, {
|
||||
"agent:main:main": {
|
||||
sessionId: "main",
|
||||
updatedAt: 1,
|
||||
channel: "slack",
|
||||
to: "U1",
|
||||
lastChannel: "slack",
|
||||
lastTo: "U1",
|
||||
},
|
||||
});
|
||||
|
||||
expect(
|
||||
resolveExecApprovalSessionTarget({
|
||||
cfg,
|
||||
request: baseRequest,
|
||||
turnSourceChannel: " whatsapp ",
|
||||
turnSourceTo: " +15555550123 ",
|
||||
turnSourceAccountId: " work ",
|
||||
turnSourceThreadId: "1739201675.123",
|
||||
}),
|
||||
).toEqual({
|
||||
channel: "whatsapp",
|
||||
to: "+15555550123",
|
||||
accountId: "work",
|
||||
threadId: 1739201675,
|
||||
});
|
||||
});
|
||||
|
||||
it("uses the parsed session-key agent id for store-path placeholders", () => {
|
||||
const tmpDir = createTempDir();
|
||||
const storePath = path.join(tmpDir, "{agentId}", "sessions.json");
|
||||
const cfg = writeStoreFile(path.join(tmpDir, "helper", "sessions.json"), {
|
||||
"agent:helper:main": {
|
||||
sessionId: "main",
|
||||
updatedAt: 1,
|
||||
lastChannel: "discord",
|
||||
lastTo: "channel:123",
|
||||
lastAccountId: " Work ",
|
||||
lastThreadId: "55",
|
||||
},
|
||||
});
|
||||
cfg.session = { store: storePath };
|
||||
|
||||
expect(
|
||||
resolveExecApprovalSessionTarget({
|
||||
cfg,
|
||||
request: {
|
||||
...baseRequest,
|
||||
request: {
|
||||
...baseRequest.request,
|
||||
sessionKey: "agent:helper:main",
|
||||
},
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
channel: "discord",
|
||||
to: "channel:123",
|
||||
accountId: "work",
|
||||
threadId: 55,
|
||||
});
|
||||
});
|
||||
|
||||
it("falls back to request agent id for legacy session keys", () => {
|
||||
const tmpDir = createTempDir();
|
||||
const storePath = path.join(tmpDir, "{agentId}", "sessions.json");
|
||||
const cfg = writeStoreFile(path.join(tmpDir, "worker-1", "sessions.json"), {
|
||||
"legacy-main": {
|
||||
sessionId: "legacy-main",
|
||||
updatedAt: 1,
|
||||
lastChannel: "telegram",
|
||||
lastTo: "-100123",
|
||||
lastThreadId: 77,
|
||||
},
|
||||
});
|
||||
cfg.session = { store: storePath };
|
||||
|
||||
expect(
|
||||
resolveExecApprovalSessionTarget({
|
||||
cfg,
|
||||
request: {
|
||||
...baseRequest,
|
||||
request: {
|
||||
...baseRequest.request,
|
||||
agentId: "Worker 1",
|
||||
sessionKey: "legacy-main",
|
||||
},
|
||||
},
|
||||
}),
|
||||
).toEqual({
|
||||
channel: "telegram",
|
||||
to: "-100123",
|
||||
accountId: undefined,
|
||||
threadId: 77,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user