From b928f360a125d41b7098b02e98c100486f1358cc Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 18 Apr 2026 20:44:45 +0100 Subject: [PATCH] test: reduce auth and subagent control hotspots --- ...th-profiles.markauthprofilefailure.test.ts | 326 +++++++++--------- .../auth-profiles/oauth-refresh-queue.test.ts | 68 +--- src/agents/subagent-control.test.ts | 179 ++++------ 3 files changed, 247 insertions(+), 326 deletions(-) diff --git a/src/agents/auth-profiles.markauthprofilefailure.test.ts b/src/agents/auth-profiles.markauthprofilefailure.test.ts index 418bea977d3..8975d3d71b2 100644 --- a/src/agents/auth-profiles.markauthprofilefailure.test.ts +++ b/src/agents/auth-profiles.markauthprofilefailure.test.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; -import { describe, expect, it, vi } from "vitest"; +import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; vi.mock("./cli-credentials.js", () => ({ readCodexCliCredentialsCached: () => null, @@ -20,36 +20,51 @@ import { calculateAuthProfileCooldownMs, markAuthProfileFailure } from "./auth-p type AuthProfileStore = ReturnType; +let tempRoot = ""; +let tempCaseIndex = 0; + +beforeAll(() => { + tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-")); +}); + +afterAll(() => { + clearRuntimeAuthProfileStoreSnapshots(); + fs.rmSync(tempRoot, { recursive: true, force: true }); +}); + +function makeAgentDir(label = "case") { + tempCaseIndex += 1; + const agentDir = path.join(tempRoot, `${tempCaseIndex}-${label}`); + fs.mkdirSync(agentDir, { recursive: true }); + return agentDir; +} + async function withAuthProfileStore( fn: (ctx: { agentDir: string; store: AuthProfileStore }) => Promise, ): Promise { - const agentDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-")); - try { - const authPath = path.join(agentDir, "auth-profiles.json"); - fs.writeFileSync( - authPath, - JSON.stringify({ - version: 1, - profiles: { - "anthropic:default": { - type: "api_key", - provider: "anthropic", - key: "sk-default", - }, - "openrouter:default": { - type: "api_key", - provider: "openrouter", - key: "sk-or-default", - }, + const agentDir = makeAgentDir("store"); + const authPath = path.join(agentDir, "auth-profiles.json"); + fs.writeFileSync( + authPath, + JSON.stringify({ + version: 1, + profiles: { + "anthropic:default": { + type: "api_key", + provider: "anthropic", + key: "sk-default", }, - }), - ); + "openrouter:default": { + type: "api_key", + provider: "openrouter", + key: "sk-or-default", + }, + }, + }), + ); - const store = ensureAuthProfileStore(agentDir); - await fn({ agentDir, store }); - } finally { - fs.rmSync(agentDir, { recursive: true, force: true }); - } + const store = ensureAuthProfileStore(agentDir); + await fn({ agentDir, store }); } function expectCooldownInRange(remainingMs: number, minMs: number, maxMs: number): void { @@ -59,24 +74,11 @@ function expectCooldownInRange(remainingMs: number, minMs: number, maxMs: number describe("markAuthProfileFailure", () => { it("does not overwrite fresher on-disk credentials with a stale runtime snapshot", async () => { - const agentDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-")); - try { - const authPath = path.join(agentDir, "auth-profiles.json"); - fs.writeFileSync( - authPath, - JSON.stringify({ - version: 1, - profiles: { - "openai:default": { - type: "api_key", - provider: "openai", - key: "sk-expired-old", - }, - }, - }), - ); - - const staleRuntimeStore: AuthProfileStore = { + const agentDir = makeAgentDir("stale-snapshot"); + const authPath = path.join(agentDir, "auth-profiles.json"); + fs.writeFileSync( + authPath, + JSON.stringify({ version: 1, profiles: { "openai:default": { @@ -85,47 +87,55 @@ describe("markAuthProfileFailure", () => { key: "sk-expired-old", }, }, - }; + }), + ); - fs.writeFileSync( - authPath, - JSON.stringify({ - version: 1, - profiles: { - "openai:default": { - type: "api_key", - provider: "openai", - key: "sk-fresh-new", - }, + const staleRuntimeStore: AuthProfileStore = { + version: 1, + profiles: { + "openai:default": { + type: "api_key", + provider: "openai", + key: "sk-expired-old", + }, + }, + }; + + fs.writeFileSync( + authPath, + JSON.stringify({ + version: 1, + profiles: { + "openai:default": { + type: "api_key", + provider: "openai", + key: "sk-fresh-new", }, - }), - ); + }, + }), + ); - const staleCredential = staleRuntimeStore.profiles["openai:default"]; - expect(staleCredential?.type).toBe("api_key"); - expect(staleCredential && "key" in staleCredential ? staleCredential.key : undefined).toBe( - "sk-expired-old", - ); + const staleCredential = staleRuntimeStore.profiles["openai:default"]; + expect(staleCredential?.type).toBe("api_key"); + expect(staleCredential && "key" in staleCredential ? staleCredential.key : undefined).toBe( + "sk-expired-old", + ); - await markAuthProfileFailure({ - store: staleRuntimeStore, - profileId: "openai:default", - reason: "rate_limit", - agentDir, - }); + await markAuthProfileFailure({ + store: staleRuntimeStore, + profileId: "openai:default", + reason: "rate_limit", + agentDir, + }); - clearRuntimeAuthProfileStoreSnapshots(); - const reloaded = ensureAuthProfileStore(agentDir); - const reloadedCredential = reloaded.profiles["openai:default"]; - expect(reloadedCredential?.type).toBe("api_key"); - expect( - reloadedCredential && "key" in reloadedCredential ? reloadedCredential.key : undefined, - ).toBe("sk-fresh-new"); - expect(typeof reloaded.usageStats?.["openai:default"]?.cooldownUntil).toBe("number"); - } finally { - clearRuntimeAuthProfileStoreSnapshots(); - fs.rmSync(agentDir, { recursive: true, force: true }); - } + clearRuntimeAuthProfileStoreSnapshots(); + const reloaded = ensureAuthProfileStore(agentDir); + const reloadedCredential = reloaded.profiles["openai:default"]; + expect(reloadedCredential?.type).toBe("api_key"); + expect( + reloadedCredential && "key" in reloadedCredential ? reloadedCredential.key : undefined, + ).toBe("sk-fresh-new"); + expect(typeof reloaded.usageStats?.["openai:default"]?.cooldownUntil).toBe("number"); }); it("disables billing failures for ~5 hours by default", async () => { @@ -255,99 +265,91 @@ describe("markAuthProfileFailure", () => { }); }); it("resets backoff counters outside the failure window", async () => { - const agentDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-")); - try { - const authPath = path.join(agentDir, "auth-profiles.json"); - const now = Date.now(); - fs.writeFileSync( - authPath, - JSON.stringify({ - version: 1, - profiles: { - "anthropic:default": { - type: "api_key", - provider: "anthropic", - key: "sk-default", - }, + const agentDir = makeAgentDir("reset-window"); + const authPath = path.join(agentDir, "auth-profiles.json"); + const now = Date.now(); + fs.writeFileSync( + authPath, + JSON.stringify({ + version: 1, + profiles: { + "anthropic:default": { + type: "api_key", + provider: "anthropic", + key: "sk-default", }, - usageStats: { - "anthropic:default": { - errorCount: 9, - failureCounts: { billing: 3 }, - lastFailureAt: now - 48 * 60 * 60 * 1000, - }, + }, + usageStats: { + "anthropic:default": { + errorCount: 9, + failureCounts: { billing: 3 }, + lastFailureAt: now - 48 * 60 * 60 * 1000, }, - }), - ); + }, + }), + ); - const store = ensureAuthProfileStore(agentDir); - await markAuthProfileFailure({ - store, - profileId: "anthropic:default", - reason: "billing", - agentDir, - cfg: { - auth: { cooldowns: { failureWindowHours: 24 } }, - } as never, - }); + const store = ensureAuthProfileStore(agentDir); + await markAuthProfileFailure({ + store, + profileId: "anthropic:default", + reason: "billing", + agentDir, + cfg: { + auth: { cooldowns: { failureWindowHours: 24 } }, + } as never, + }); - expect(store.usageStats?.["anthropic:default"]?.errorCount).toBe(1); - expect(store.usageStats?.["anthropic:default"]?.failureCounts?.billing).toBe(1); - } finally { - fs.rmSync(agentDir, { recursive: true, force: true }); - } + expect(store.usageStats?.["anthropic:default"]?.errorCount).toBe(1); + expect(store.usageStats?.["anthropic:default"]?.failureCounts?.billing).toBe(1); }); it("resets error count when previous cooldown has expired to prevent escalation", async () => { - const agentDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-")); - try { - const authPath = path.join(agentDir, "auth-profiles.json"); - const now = Date.now(); - // Simulate state left on disk after 3 rapid failures within a 1-min cooldown - // window. The cooldown has since expired, but clearExpiredCooldowns() only - // ran in-memory and never persisted — so disk still carries errorCount: 3. - fs.writeFileSync( - authPath, - JSON.stringify({ - version: 1, - profiles: { - "anthropic:default": { - type: "api_key", - provider: "anthropic", - key: "sk-default", - }, + const agentDir = makeAgentDir("expired-cooldown"); + const authPath = path.join(agentDir, "auth-profiles.json"); + const now = Date.now(); + // Simulate state left on disk after 3 rapid failures within a 1-min cooldown + // window. The cooldown has since expired, but clearExpiredCooldowns() only + // ran in-memory and never persisted - so disk still carries errorCount: 3. + fs.writeFileSync( + authPath, + JSON.stringify({ + version: 1, + profiles: { + "anthropic:default": { + type: "api_key", + provider: "anthropic", + key: "sk-default", }, - usageStats: { - "anthropic:default": { - errorCount: 3, - failureCounts: { rate_limit: 3 }, - lastFailureAt: now - 120_000, // 2 minutes ago - cooldownUntil: now - 60_000, // expired 1 minute ago - }, + }, + usageStats: { + "anthropic:default": { + errorCount: 3, + failureCounts: { rate_limit: 3 }, + lastFailureAt: now - 120_000, // 2 minutes ago + cooldownUntil: now - 60_000, // expired 1 minute ago }, - }), - ); + }, + }), + ); - const store = ensureAuthProfileStore(agentDir); - await markAuthProfileFailure({ - store, - profileId: "anthropic:default", - reason: "rate_limit", - agentDir, - }); + const store = ensureAuthProfileStore(agentDir); + await markAuthProfileFailure({ + store, + profileId: "anthropic:default", + reason: "rate_limit", + agentDir, + }); - const stats = store.usageStats?.["anthropic:default"]; - // Error count should reset to 1 (not escalate to 4) because the - // previous cooldown expired. Cooldown should be ~30s, not ~5 min. - expect(stats?.errorCount).toBe(1); - expect(stats?.failureCounts?.rate_limit).toBe(1); - const cooldownMs = (stats?.cooldownUntil ?? 0) - now; - // calculateAuthProfileCooldownMs(1) = 30_000 (stepped: 30s → 1m → 5m) - expect(cooldownMs).toBeLessThan(60_000); - expect(cooldownMs).toBeGreaterThan(0); - } finally { - fs.rmSync(agentDir, { recursive: true, force: true }); - } + const stats = store.usageStats?.["anthropic:default"]; + // Error count should reset to 1 (not escalate to 4) because the + // previous cooldown expired. Cooldown should be ~30s, not ~5 min. + expect(stats?.errorCount).toBe(1); + expect(stats?.failureCounts?.rate_limit).toBe(1); + const cooldownMs = (stats?.cooldownUntil ?? 0) - now; + // calculateAuthProfileCooldownMs(1) = 30_000 (stepped: 30s -> 1m -> 5m) + expect(cooldownMs).toBeLessThan(60_000); + expect(cooldownMs).toBeGreaterThan(0); }); it("does not persist cooldown windows for OpenRouter profiles", async () => { diff --git a/src/agents/auth-profiles/oauth-refresh-queue.test.ts b/src/agents/auth-profiles/oauth-refresh-queue.test.ts index 84de0572e3c..7c219874f38 100644 --- a/src/agents/auth-profiles/oauth-refresh-queue.test.ts +++ b/src/agents/auth-profiles/oauth-refresh-queue.test.ts @@ -1,7 +1,7 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; -import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import { resetFileLockStateForTest } from "../../infra/file-lock.js"; import { captureEnv } from "../../test-utils/env.js"; import { resolveApiKeyForProfile, resetOAuthRefreshQueuesForTest } from "./oauth.js"; @@ -107,6 +107,11 @@ describe("OAuth refresh in-process queue", () => { ]); let tempRoot = ""; let agentDir = ""; + let caseIndex = 0; + + beforeAll(async () => { + tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-oauth-queue-")); + }); beforeEach(async () => { resetFileLockStateForTest(); @@ -115,9 +120,9 @@ describe("OAuth refresh in-process queue", () => { formatProviderAuthProfileApiKeyWithPluginMock.mockReset(); formatProviderAuthProfileApiKeyWithPluginMock.mockReturnValue(undefined); clearRuntimeAuthProfileStoreSnapshots(); - tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-oauth-queue-")); - process.env.OPENCLAW_STATE_DIR = tempRoot; - agentDir = path.join(tempRoot, "agents", "main", "agent"); + const caseRoot = path.join(tempRoot, `case-${++caseIndex}`); + process.env.OPENCLAW_STATE_DIR = caseRoot; + agentDir = path.join(caseRoot, "agents", "main", "agent"); process.env.OPENCLAW_AGENT_DIR = agentDir; process.env.PI_CODING_AGENT_DIR = agentDir; await fs.mkdir(agentDir, { recursive: true }); @@ -129,57 +134,10 @@ describe("OAuth refresh in-process queue", () => { resetFileLockStateForTest(); clearRuntimeAuthProfileStoreSnapshots(); resetOAuthRefreshQueuesForTest(); - if (tempRoot) { - await fs.rm(tempRoot, { recursive: true, force: true }); - } }); - it("serializes concurrent same-PID callers FIFO", async () => { - const profileId = "openai-codex:default"; - const provider = "openai-codex"; - saveAuthProfileStore(createExpiredOauthStore({ profileId, provider }), agentDir); - - const order: number[] = []; - let seq = 0; - refreshProviderOAuthCredentialWithPluginMock.mockImplementation(async () => { - const n = ++seq; - order.push(n); - // Small delay so concurrent callers have time to interleave if they can. - await new Promise((r) => setTimeout(r, 10)); - return { - type: "oauth", - provider, - access: `refreshed-${n}`, - refresh: `refreshed-refresh-${n}`, - // Each refresh returns a token already expired again, so the next - // queued caller also proceeds to refresh (proves the queue releases - // cleanly and the next caller actually runs). - expires: Date.now() - 1_000, - } as never; - }); - - // Fire three resolves concurrently against the same agent+profile. - const results = await Promise.all([ - resolveApiKeyForProfileInTest({ - store: ensureAuthProfileStore(agentDir), - profileId, - agentDir, - }).catch((e) => e), - resolveApiKeyForProfileInTest({ - store: ensureAuthProfileStore(agentDir), - profileId, - agentDir, - }).catch((e) => e), - resolveApiKeyForProfileInTest({ - store: ensureAuthProfileStore(agentDir), - profileId, - agentDir, - }).catch((e) => e), - ]); - - // All three should have completed in order (FIFO queue). - expect(order).toEqual([1, 2, 3]); - expect(results).toHaveLength(3); + afterAll(async () => { + await fs.rm(tempRoot, { recursive: true, force: true }); }); it("releases the queue even when the refresh throws", async () => { @@ -254,8 +212,8 @@ describe("OAuth refresh in-process queue", () => { startOrder.push(n); inFlight += 1; maxInFlight = Math.max(maxInFlight, inFlight); - // Small delay so any non-serialized overlap would be observable. - await new Promise((r) => setTimeout(r, 5)); + // Yield once so any non-serialized overlap is observable without wall-clock sleep. + await Promise.resolve(); inFlight -= 1; endOrder.push(n); return { diff --git a/src/agents/subagent-control.test.ts b/src/agents/subagent-control.test.ts index 1a69b686454..e0f8d11f12c 100644 --- a/src/agents/subagent-control.test.ts +++ b/src/agents/subagent-control.test.ts @@ -1,7 +1,7 @@ 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 { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import * as sessionStore from "../config/sessions/store.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import type { CallGatewayOptions } from "../gateway/call.js"; @@ -115,6 +115,34 @@ function setSubagentControlDepsForTest( }); } +let tempRoot = ""; +let tempStoreIndex = 0; + +beforeAll(() => { + tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-subagent-control-")); +}); + +afterAll(() => { + fs.rmSync(tempRoot, { recursive: true, force: true }); +}); + +function nextSessionStorePath(label: string) { + tempStoreIndex += 1; + return path.join(tempRoot, `${tempStoreIndex}-${label}.json`); +} + +function cfgWithSessionStore(storePath = nextSessionStorePath("sessions")): OpenClawConfig { + return { + session: { store: storePath }, + } as OpenClawConfig; +} + +function writeSessionStoreFixture(label: string, store: Record) { + const storePath = nextSessionStorePath(label); + fs.writeFileSync(storePath, JSON.stringify(store, null, 2), "utf-8"); + return storePath; +} + beforeEach(() => { setSubagentControlDepsForTest(); }); @@ -472,24 +500,13 @@ describe("killSubagentRunAdmin", () => { }); it("kills a subagent by session key without requester ownership checks", async () => { - const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-subagent-admin-kill-")); - const storePath = path.join(tmpDir, "sessions.json"); const childSessionKey = "agent:main:subagent:worker"; - - fs.writeFileSync( - storePath, - JSON.stringify( - { - [childSessionKey]: { - sessionId: "sess-worker", - updatedAt: Date.now(), - }, - }, - null, - 2, - ), - "utf-8", - ); + const storePath = writeSessionStoreFixture("admin-kill", { + [childSessionKey]: { + sessionId: "sess-worker", + updatedAt: Date.now(), + }, + }); addSubagentRunForTests({ runId: "run-worker", @@ -503,9 +520,7 @@ describe("killSubagentRunAdmin", () => { startedAt: Date.now() - 4_000, }); - const cfg = { - session: { store: storePath }, - } as OpenClawConfig; + const cfg = cfgWithSessionStore(storePath); const result = await killSubagentRunAdmin({ cfg, @@ -523,7 +538,7 @@ describe("killSubagentRunAdmin", () => { it("returns found=false when the session key is not tracked as a subagent run", async () => { const result = await killSubagentRunAdmin({ - cfg: {} as OpenClawConfig, + cfg: cfgWithSessionStore(), sessionKey: "agent:main:subagent:missing", }); @@ -559,7 +574,7 @@ describe("killSubagentRunAdmin", () => { }); const result = await killSubagentRunAdmin({ - cfg: {} as OpenClawConfig, + cfg: cfgWithSessionStore(), sessionKey: childSessionKey, }); @@ -572,24 +587,13 @@ describe("killSubagentRunAdmin", () => { }); it("still terminates the run when session store persistence fails during kill", async () => { - const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-subagent-admin-kill-store-")); - const storePath = path.join(tmpDir, "sessions.json"); const childSessionKey = "agent:main:subagent:worker-store-fail"; - - fs.writeFileSync( - storePath, - JSON.stringify( - { - [childSessionKey]: { - sessionId: "sess-worker-store-fail", - updatedAt: Date.now(), - }, - }, - null, - 2, - ), - "utf-8", - ); + const storePath = writeSessionStoreFixture("admin-kill-store-fail", { + [childSessionKey]: { + sessionId: "sess-worker-store-fail", + updatedAt: Date.now(), + }, + }); addSubagentRunForTests({ runId: "run-worker-store-fail", @@ -609,9 +613,7 @@ describe("killSubagentRunAdmin", () => { try { const result = await killSubagentRunAdmin({ - cfg: { - session: { store: storePath }, - } as OpenClawConfig, + cfg: cfgWithSessionStore(storePath), sessionKey: childSessionKey, }); @@ -635,23 +637,12 @@ describe("killControlledSubagentRun", () => { }); it("does not mutate the live session when the caller passes a stale run entry", async () => { - const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-subagent-stale-kill-")); - const storePath = path.join(tmpDir, "sessions.json"); const childSessionKey = "agent:main:subagent:stale-kill-worker"; - - fs.writeFileSync( - storePath, - JSON.stringify( - { - [childSessionKey]: { - updatedAt: Date.now(), - }, - }, - null, - 2, - ), - "utf-8", - ); + const storePath = writeSessionStoreFixture("stale-kill", { + [childSessionKey]: { + updatedAt: Date.now(), + }, + }); addSubagentRunForTests({ runId: "run-current", @@ -666,9 +657,7 @@ describe("killControlledSubagentRun", () => { }); const result = await killControlledSubagentRun({ - cfg: { - session: { store: storePath }, - } as OpenClawConfig, + cfg: cfgWithSessionStore(storePath), controller: { controllerSessionKey: "agent:main:main", callerSessionKey: "agent:main:main", @@ -758,7 +747,7 @@ describe("killControlledSubagentRun", () => { }); const result = await killControlledSubagentRun({ - cfg: {} as OpenClawConfig, + cfg: cfgWithSessionStore(), controller: { controllerSessionKey: "agent:main:main", callerSessionKey: "agent:main:main", @@ -859,7 +848,7 @@ describe("killControlledSubagentRun", () => { }); const result = await killControlledSubagentRun({ - cfg: {} as OpenClawConfig, + cfg: cfgWithSessionStore(), controller: { controllerSessionKey: "agent:main:main", callerSessionKey: "agent:main:main", @@ -899,23 +888,12 @@ describe("killAllControlledSubagentRuns", () => { }); it("ignores stale run snapshots in bulk kill requests", async () => { - const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-subagent-stale-kill-all-")); - const storePath = path.join(tmpDir, "sessions.json"); const childSessionKey = "agent:main:subagent:stale-kill-all-worker"; - - fs.writeFileSync( - storePath, - JSON.stringify( - { - [childSessionKey]: { - updatedAt: Date.now(), - }, - }, - null, - 2, - ), - "utf-8", - ); + const storePath = writeSessionStoreFixture("stale-kill-all", { + [childSessionKey]: { + updatedAt: Date.now(), + }, + }); addSubagentRunForTests({ runId: "run-current-bulk", @@ -930,9 +908,7 @@ describe("killAllControlledSubagentRuns", () => { }); const result = await killAllControlledSubagentRuns({ - cfg: { - session: { store: storePath }, - } as OpenClawConfig, + cfg: cfgWithSessionStore(storePath), controller: { controllerSessionKey: "agent:main:main", callerSessionKey: "agent:main:main", @@ -968,25 +944,12 @@ describe("killAllControlledSubagentRuns", () => { }); it("does not let a stale bulk entry suppress the current live entry for the same child key", async () => { - const tmpDir = fs.mkdtempSync( - path.join(os.tmpdir(), "openclaw-subagent-stale-kill-all-shadow-"), - ); - const storePath = path.join(tmpDir, "sessions.json"); const childSessionKey = "agent:main:subagent:stale-kill-all-shadow-worker"; - - fs.writeFileSync( - storePath, - JSON.stringify( - { - [childSessionKey]: { - updatedAt: Date.now(), - }, - }, - null, - 2, - ), - "utf-8", - ); + const storePath = writeSessionStoreFixture("stale-kill-all-shadow", { + [childSessionKey]: { + updatedAt: Date.now(), + }, + }); addSubagentRunForTests({ runId: "run-current-shadow", @@ -1001,9 +964,7 @@ describe("killAllControlledSubagentRuns", () => { }); const result = await killAllControlledSubagentRuns({ - cfg: { - session: { store: storePath }, - } as OpenClawConfig, + cfg: cfgWithSessionStore(storePath), controller: { controllerSessionKey: "agent:main:main", callerSessionKey: "agent:main:main", @@ -1073,7 +1034,7 @@ describe("killAllControlledSubagentRuns", () => { }); const result = await killAllControlledSubagentRuns({ - cfg: {} as OpenClawConfig, + cfg: cfgWithSessionStore(), controller: { controllerSessionKey: "agent:main:main", callerSessionKey: "agent:main:main", @@ -1145,7 +1106,7 @@ describe("killAllControlledSubagentRuns", () => { }); const result = await killAllControlledSubagentRuns({ - cfg: {} as OpenClawConfig, + cfg: cfgWithSessionStore(), controller: { controllerSessionKey: "agent:main:main", callerSessionKey: "agent:main:main", @@ -1215,7 +1176,7 @@ describe("steerControlledSubagentRun", () => { try { const result = await steerControlledSubagentRun({ - cfg: {} as OpenClawConfig, + cfg: cfgWithSessionStore(), controller: { controllerSessionKey: "agent:main:main", callerSessionKey: "agent:main:main", @@ -1260,7 +1221,7 @@ describe("steerControlledSubagentRun", () => { }); const result = await steerControlledSubagentRun({ - cfg: {} as OpenClawConfig, + cfg: cfgWithSessionStore(), controller: { controllerSessionKey: "agent:main:main", callerSessionKey: "agent:main:main", @@ -1340,7 +1301,7 @@ describe("steerControlledSubagentRun", () => { }); const result = await steerControlledSubagentRun({ - cfg: {} as OpenClawConfig, + cfg: cfgWithSessionStore(), controller: { controllerSessionKey: "agent:main:main", callerSessionKey: "agent:main:main",