From 996de610e8fa829fb181051f1ec814ec40c48110 Mon Sep 17 00:00:00 2001 From: Tyler Yust Date: Thu, 12 Mar 2026 18:36:49 -0700 Subject: [PATCH] Fix subagent spawn test config loading --- ...s.subagents.sessions-spawn.test-harness.ts | 1 + src/agents/subagent-spawn.attachments.test.ts | 52 +++++++++++++------ 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/agents/openclaw-tools.subagents.sessions-spawn.test-harness.ts b/src/agents/openclaw-tools.subagents.sessions-spawn.test-harness.ts index 8f7e695fb61..3f65ea0e47f 100644 --- a/src/agents/openclaw-tools.subagents.sessions-spawn.test-harness.ts +++ b/src/agents/openclaw-tools.subagents.sessions-spawn.test-harness.ts @@ -54,6 +54,7 @@ export function setSessionsSpawnConfigOverride(next: SessionsSpawnTestConfig): v export async function getSessionsSpawnTool(opts: CreateOpenClawToolsOpts) { // Dynamic import: ensure harness mocks are installed before tool modules load. + vi.resetModules(); const { createSessionsSpawnTool } = await import("./tools/sessions-spawn-tool.js"); return createSessionsSpawnTool(opts); } diff --git a/src/agents/subagent-spawn.attachments.test.ts b/src/agents/subagent-spawn.attachments.test.ts index 9fe774fa284..5b265709d4a 100644 --- a/src/agents/subagent-spawn.attachments.test.ts +++ b/src/agents/subagent-spawn.attachments.test.ts @@ -3,7 +3,6 @@ import os from "node:os"; import path from "node:path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { resetSubagentRegistryForTests } from "./subagent-registry.js"; -import { decodeStrictBase64, spawnSubagentDirect } from "./subagent-spawn.js"; const callGatewayMock = vi.fn(); @@ -33,14 +32,8 @@ let configOverride: Record = { }, }; let workspaceDirOverride = ""; - -vi.mock("../config/config.js", async (importOriginal) => { - const actual = await importOriginal(); - return { - ...actual, - loadConfig: () => configOverride, - }; -}); +let configPathOverride = ""; +let previousConfigPath = process.env.OPENCLAW_CONFIG_PATH; vi.mock("./subagent-registry.js", async (importOriginal) => { const actual = await importOriginal(); @@ -90,12 +83,17 @@ function setupGatewayMock() { }); } +async function loadSubagentSpawnModule() { + return import("./subagent-spawn.js"); +} + // --- decodeStrictBase64 --- describe("decodeStrictBase64", () => { const maxBytes = 1024; - it("valid base64 returns buffer with correct bytes", () => { + it("valid base64 returns buffer with correct bytes", async () => { + const { decodeStrictBase64 } = await loadSubagentSpawnModule(); const input = "hello world"; const encoded = Buffer.from(input).toString("base64"); const result = decodeStrictBase64(encoded, maxBytes); @@ -103,35 +101,42 @@ describe("decodeStrictBase64", () => { expect(result?.toString("utf8")).toBe(input); }); - it("empty string returns null", () => { + it("empty string returns null", async () => { + const { decodeStrictBase64 } = await loadSubagentSpawnModule(); expect(decodeStrictBase64("", maxBytes)).toBeNull(); }); - it("bad padding (length % 4 !== 0) returns null", () => { + it("bad padding (length % 4 !== 0) returns null", async () => { + const { decodeStrictBase64 } = await loadSubagentSpawnModule(); expect(decodeStrictBase64("abc", maxBytes)).toBeNull(); }); - it("non-base64 chars returns null", () => { + it("non-base64 chars returns null", async () => { + const { decodeStrictBase64 } = await loadSubagentSpawnModule(); expect(decodeStrictBase64("!@#$", maxBytes)).toBeNull(); }); - it("whitespace-only returns null (empty after strip)", () => { + it("whitespace-only returns null (empty after strip)", async () => { + const { decodeStrictBase64 } = await loadSubagentSpawnModule(); expect(decodeStrictBase64(" ", maxBytes)).toBeNull(); }); - it("pre-decode oversize guard: encoded string > maxEncodedBytes * 2 returns null", () => { + it("pre-decode oversize guard: encoded string > maxEncodedBytes * 2 returns null", async () => { + const { decodeStrictBase64 } = await loadSubagentSpawnModule(); // maxEncodedBytes = ceil(1024/3)*4 = 1368; *2 = 2736 const oversized = "A".repeat(2737); expect(decodeStrictBase64(oversized, maxBytes)).toBeNull(); }); - it("decoded byteLength exceeds maxDecodedBytes returns null", () => { + it("decoded byteLength exceeds maxDecodedBytes returns null", async () => { + const { decodeStrictBase64 } = await loadSubagentSpawnModule(); const bigBuf = Buffer.alloc(1025, 0x42); const encoded = bigBuf.toString("base64"); expect(decodeStrictBase64(encoded, maxBytes)).toBeNull(); }); - it("valid base64 at exact boundary returns Buffer", () => { + it("valid base64 at exact boundary returns Buffer", async () => { + const { decodeStrictBase64 } = await loadSubagentSpawnModule(); const exactBuf = Buffer.alloc(1024, 0x41); const encoded = exactBuf.toString("base64"); const result = decodeStrictBase64(encoded, maxBytes); @@ -150,9 +155,19 @@ describe("spawnSubagentDirect filename validation", () => { workspaceDirOverride = fs.mkdtempSync( path.join(os.tmpdir(), `openclaw-subagent-attachments-${process.pid}-${Date.now()}-`), ); + configPathOverride = path.join(workspaceDirOverride, "openclaw.test.json"); + fs.writeFileSync(configPathOverride, JSON.stringify(configOverride, null, 2)); + previousConfigPath = process.env.OPENCLAW_CONFIG_PATH; + process.env.OPENCLAW_CONFIG_PATH = configPathOverride; }); afterEach(() => { + if (previousConfigPath === undefined) { + delete process.env.OPENCLAW_CONFIG_PATH; + } else { + process.env.OPENCLAW_CONFIG_PATH = previousConfigPath; + } + configPathOverride = ""; if (workspaceDirOverride) { fs.rmSync(workspaceDirOverride, { recursive: true, force: true }); workspaceDirOverride = ""; @@ -169,6 +184,7 @@ describe("spawnSubagentDirect filename validation", () => { const validContent = Buffer.from("hello").toString("base64"); async function spawnWithName(name: string) { + const { spawnSubagentDirect } = await loadSubagentSpawnModule(); return spawnSubagentDirect( { task: "test", @@ -203,6 +219,7 @@ describe("spawnSubagentDirect filename validation", () => { }); it("duplicate name returns attachments_duplicate_name", async () => { + const { spawnSubagentDirect } = await loadSubagentSpawnModule(); const result = await spawnSubagentDirect( { task: "test", @@ -237,6 +254,7 @@ describe("spawnSubagentDirect filename validation", () => { return {}; }); + const { spawnSubagentDirect } = await loadSubagentSpawnModule(); const result = await spawnSubagentDirect( { task: "test",