From 7dd37bda4f161aaa09afe4d5d9e29a738f67a0ff Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 23 Apr 2026 14:32:51 +0100 Subject: [PATCH] perf(test): trim hot gateway and infra tests --- ...sessions.gateway-server-sessions-a.test.ts | 121 ++++++++++++------ .../heartbeat-runner.ghost-reminder.test.ts | 2 +- src/infra/heartbeat-runner.ts | 2 +- src/infra/system-events.test.ts | 6 +- 4 files changed, 86 insertions(+), 45 deletions(-) diff --git a/src/gateway/server.sessions.gateway-server-sessions-a.test.ts b/src/gateway/server.sessions.gateway-server-sessions-a.test.ts index 1a0d1e20d16..1f0abbcf078 100644 --- a/src/gateway/server.sessions.gateway-server-sessions-a.test.ts +++ b/src/gateway/server.sessions.gateway-server-sessions-a.test.ts @@ -1035,6 +1035,48 @@ describe("gateway server sessions", () => { "sessions.compact", ]), ); + const sessionsHandlers = await getSessionsHandlers(); + const directContext = { + broadcastToConnIds: vi.fn(), + getSessionEventSubscriberConnIds: () => new Set(), + loadGatewayModelCatalog: async () => piSdkMock.models, + } as never; + async function directSessionReq( + method: keyof typeof sessionsHandlers, + params: Record, + coercePayload?: (payload: unknown) => TPayload, + ): Promise<{ ok: boolean; payload?: TPayload; error?: unknown }> { + let result: + | { + ok: boolean; + payload?: TPayload; + error?: unknown; + } + | undefined; + await sessionsHandlers[method]({ + req: {} as never, + params, + respond: (ok, payload, error) => { + result = { + ok, + payload: + payload === undefined + ? undefined + : coercePayload + ? coercePayload(payload) + : (payload as TPayload), + error, + }; + }, + context: directContext, + client: null, + isWebchatConnect: () => false, + }); + if (!result) { + throw new Error(`${method} did not respond`); + } + return result; + } const resolvedByKey = await rpcReq<{ ok: true; key: string }>(ws, "sessions.resolve", { key: "main", @@ -1047,8 +1089,9 @@ describe("gateway server sessions", () => { }); expect(resolvedBySessionId.ok).toBe(true); expect(resolvedBySessionId.payload?.key).toBe("agent:main:discord:group:dev"); + ws.close(); - const list1 = await rpcReq<{ + const list1 = await directSessionReq<{ path: string; defaults?: { model?: string | null; modelProvider?: string | null }; sessions: Array<{ @@ -1060,7 +1103,7 @@ describe("gateway server sessions", () => { lastAccountId?: string; deliveryContext?: { channel?: string; to?: string; accountId?: string }; }>; - }>(ws, "sessions.list", { includeGlobal: false, includeUnknown: false }); + }>("sessions.list", { includeGlobal: false, includeUnknown: false }); expect(list1.ok).toBe(true); expect(list1.payload?.path).toBe(storePath); @@ -1079,9 +1122,9 @@ describe("gateway server sessions", () => { threadId: "1737500000.123456", }); - const active = await rpcReq<{ + const active = await directSessionReq<{ sessions: Array<{ key: string }>; - }>(ws, "sessions.list", { + }>("sessions.list", { includeGlobal: false, includeUnknown: false, activeMinutes: 5, @@ -1089,9 +1132,9 @@ describe("gateway server sessions", () => { expect(active.ok).toBe(true); expect(active.payload?.sessions.map((s) => s.key)).toEqual(["agent:main:main"]); - const limited = await rpcReq<{ + const limited = await directSessionReq<{ sessions: Array<{ key: string }>; - }>(ws, "sessions.list", { + }>("sessions.list", { includeGlobal: true, includeUnknown: false, limit: 1, @@ -1100,7 +1143,7 @@ describe("gateway server sessions", () => { expect(limited.payload?.sessions).toHaveLength(1); expect(limited.payload?.sessions[0]?.key).toBe("global"); - const patched = await rpcReq<{ ok: true; key: string }>(ws, "sessions.patch", { + const patched = await directSessionReq<{ ok: true; key: string }>("sessions.patch", { key: "agent:main:main", thinkingLevel: "medium", verboseLevel: "off", @@ -1109,30 +1152,30 @@ describe("gateway server sessions", () => { expect(patched.payload?.ok).toBe(true); expect(patched.payload?.key).toBe("agent:main:main"); - const sendPolicyPatched = await rpcReq<{ + const sendPolicyPatched = await directSessionReq<{ ok: true; entry: { sendPolicy?: string }; - }>(ws, "sessions.patch", { key: "agent:main:main", sendPolicy: "deny" }); + }>("sessions.patch", { key: "agent:main:main", sendPolicy: "deny" }); expect(sendPolicyPatched.ok).toBe(true); expect(sendPolicyPatched.payload?.entry.sendPolicy).toBe("deny"); - const labelPatched = await rpcReq<{ + const labelPatched = await directSessionReq<{ ok: true; entry: { label?: string }; - }>(ws, "sessions.patch", { + }>("sessions.patch", { key: "agent:main:subagent:one", label: "Briefing", }); expect(labelPatched.ok).toBe(true); expect(labelPatched.payload?.entry.label).toBe("Briefing"); - const labelPatchedDuplicate = await rpcReq(ws, "sessions.patch", { + const labelPatchedDuplicate = await directSessionReq("sessions.patch", { key: "agent:main:discord:group:dev", label: "Briefing", }); expect(labelPatchedDuplicate.ok).toBe(false); - const list2 = await rpcReq<{ + const list2 = await directSessionReq<{ sessions: Array<{ key: string; thinkingLevel?: string; @@ -1141,7 +1184,7 @@ describe("gateway server sessions", () => { label?: string; displayName?: string; }>; - }>(ws, "sessions.list", {}); + }>("sessions.list", {}); expect(list2.ok).toBe(true); const main2 = list2.payload?.sessions.find((s) => s.key === "agent:main:main"); expect(main2?.thinkingLevel).toBe("medium"); @@ -1151,25 +1194,25 @@ describe("gateway server sessions", () => { expect(subagent?.label).toBe("Briefing"); expect(subagent?.displayName).toBe("Briefing"); - const clearedVerbose = await rpcReq<{ ok: true; key: string }>(ws, "sessions.patch", { + const clearedVerbose = await directSessionReq<{ ok: true; key: string }>("sessions.patch", { key: "agent:main:main", verboseLevel: null, }); expect(clearedVerbose.ok).toBe(true); - const list3 = await rpcReq<{ + const list3 = await directSessionReq<{ sessions: Array<{ key: string; verboseLevel?: string; }>; - }>(ws, "sessions.list", {}); + }>("sessions.list", {}); expect(list3.ok).toBe(true); const main3 = list3.payload?.sessions.find((s) => s.key === "agent:main:main"); expect(main3?.verboseLevel).toBeUndefined(); - const listByLabel = await rpcReq<{ + const listByLabel = await directSessionReq<{ sessions: Array<{ key: string }>; - }>(ws, "sessions.list", { + }>("sessions.list", { includeGlobal: false, includeUnknown: false, label: "Briefing", @@ -1177,16 +1220,16 @@ describe("gateway server sessions", () => { expect(listByLabel.ok).toBe(true); expect(listByLabel.payload?.sessions.map((s) => s.key)).toEqual(["agent:main:subagent:one"]); - const resolvedByLabel = await rpcReq<{ ok: true; key: string }>(ws, "sessions.resolve", { + const resolvedByLabel = await directSessionReq<{ ok: true; key: string }>("sessions.resolve", { label: "Briefing", agentId: "main", }); expect(resolvedByLabel.ok).toBe(true); expect(resolvedByLabel.payload?.key).toBe("agent:main:subagent:one"); - const spawnedOnly = await rpcReq<{ + const spawnedOnly = await directSessionReq<{ sessions: Array<{ key: string }>; - }>(ws, "sessions.list", { + }>("sessions.list", { includeGlobal: true, includeUnknown: true, spawnedBy: "agent:main:main", @@ -1194,20 +1237,20 @@ describe("gateway server sessions", () => { expect(spawnedOnly.ok).toBe(true); expect(spawnedOnly.payload?.sessions.map((s) => s.key)).toEqual(["agent:main:subagent:one"]); - const spawnedPatched = await rpcReq<{ + const spawnedPatched = await directSessionReq<{ ok: true; entry: { spawnedBy?: string }; - }>(ws, "sessions.patch", { + }>("sessions.patch", { key: "agent:main:subagent:two", spawnedBy: "agent:main:main", }); expect(spawnedPatched.ok).toBe(true); expect(spawnedPatched.payload?.entry.spawnedBy).toBe("agent:main:main"); - const acpPatched = await rpcReq<{ + const acpPatched = await directSessionReq<{ ok: true; entry: { spawnedBy?: string; spawnDepth?: number }; - }>(ws, "sessions.patch", { + }>("sessions.patch", { key: "agent:main:acp:child", spawnedBy: "agent:main:main", spawnDepth: 1, @@ -1216,7 +1259,7 @@ describe("gateway server sessions", () => { expect(acpPatched.payload?.entry.spawnedBy).toBe("agent:main:main"); expect(acpPatched.payload?.entry.spawnDepth).toBe(1); - const spawnedPatchedInvalidKey = await rpcReq(ws, "sessions.patch", { + const spawnedPatchedInvalidKey = await directSessionReq("sessions.patch", { key: "agent:main:main", spawnedBy: "agent:main:main", }); @@ -1224,7 +1267,7 @@ describe("gateway server sessions", () => { piSdkMock.enabled = true; piSdkMock.models = [{ id: "gpt-test-a", name: "A", provider: "openai" }]; - const modelPatched = await rpcReq<{ + const modelPatched = await directSessionReq<{ ok: true; entry: { modelOverride?: string; @@ -1233,7 +1276,7 @@ describe("gateway server sessions", () => { modelProvider?: string; }; resolved?: { model?: string; modelProvider?: string }; - }>(ws, "sessions.patch", { + }>("sessions.patch", { key: "agent:main:main", model: "openai/gpt-test-a", }); @@ -1245,9 +1288,9 @@ describe("gateway server sessions", () => { expect(modelPatched.payload?.resolved?.modelProvider).toBe("openai"); expect(modelPatched.payload?.resolved?.model).toBe("gpt-test-a"); - const listAfterModelPatch = await rpcReq<{ + const listAfterModelPatch = await directSessionReq<{ sessions: Array<{ key: string; modelProvider?: string; model?: string }>; - }>(ws, "sessions.list", {}); + }>("sessions.list", {}); expect(listAfterModelPatch.ok).toBe(true); const mainAfterModelPatch = listAfterModelPatch.payload?.sessions.find( (session) => session.key === "agent:main:main", @@ -1255,7 +1298,7 @@ describe("gateway server sessions", () => { expect(mainAfterModelPatch?.modelProvider).toBe("openai"); expect(mainAfterModelPatch?.model).toBe("gpt-test-a"); - const compacted = await rpcReq<{ ok: true; compacted: boolean }>(ws, "sessions.compact", { + const compacted = await directSessionReq<{ ok: true; compacted: boolean }>("sessions.compact", { key: "agent:main:main", maxLines: 3, }); @@ -1268,14 +1311,14 @@ describe("gateway server sessions", () => { const filesAfterCompact = await fs.readdir(dir); expect(filesAfterCompact.some((f) => f.startsWith("sess-main.jsonl.bak."))).toBe(true); - const deleted = await rpcReq<{ ok: true; deleted: boolean }>(ws, "sessions.delete", { + const deleted = await directSessionReq<{ ok: true; deleted: boolean }>("sessions.delete", { key: "agent:main:discord:group:dev", }); expect(deleted.ok).toBe(true); expect(deleted.payload?.deleted).toBe(true); - const listAfterDelete = await rpcReq<{ + const listAfterDelete = await directSessionReq<{ sessions: Array<{ key: string }>; - }>(ws, "sessions.list", {}); + }>("sessions.list", {}); expect(listAfterDelete.ok).toBe(true); expect( listAfterDelete.payload?.sessions.some((s) => s.key === "agent:main:discord:group:dev"), @@ -1283,7 +1326,7 @@ describe("gateway server sessions", () => { const filesAfterDelete = await fs.readdir(dir); expect(filesAfterDelete.some((f) => f.startsWith("sess-group.jsonl.deleted."))).toBe(true); - const reset = await rpcReq<{ + const reset = await directSessionReq<{ ok: true; key: string; entry: { @@ -1293,7 +1336,7 @@ describe("gateway server sessions", () => { lastAccountId?: string; lastThreadId?: string | number; }; - }>(ws, "sessions.reset", { key: "agent:main:main" }); + }>("sessions.reset", { key: "agent:main:main" }); expect(reset.ok).toBe(true); expect(reset.payload?.key).toBe("agent:main:main"); expect(reset.payload?.entry.sessionId).not.toBe("sess-main"); @@ -1310,7 +1353,7 @@ describe("gateway server sessions", () => { const filesAfterReset = await fs.readdir(dir); expect(filesAfterReset.some((f) => f.startsWith("sess-main.jsonl.reset."))).toBe(true); - const badThinking = await rpcReq(ws, "sessions.patch", { + const badThinking = await directSessionReq("sessions.patch", { key: "agent:main:main", thinkingLevel: "banana", }); @@ -1318,8 +1361,6 @@ describe("gateway server sessions", () => { expect((badThinking.error as { message?: unknown } | undefined)?.message ?? "").toMatch( /invalid thinkinglevel/i, ); - - ws.close(); }); test("sessions.compaction.* lists checkpoints and branches or restores from pre-compaction snapshots", async () => { diff --git a/src/infra/heartbeat-runner.ghost-reminder.test.ts b/src/infra/heartbeat-runner.ghost-reminder.test.ts index 083e63b0c99..029ab8af694 100644 --- a/src/infra/heartbeat-runner.ghost-reminder.test.ts +++ b/src/infra/heartbeat-runner.ghost-reminder.test.ts @@ -1,7 +1,7 @@ import fs from "node:fs/promises"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; -import { resolveMainSessionKey } from "../config/sessions.js"; +import { resolveMainSessionKey } from "../config/sessions/main-session.js"; import { runHeartbeatOnce } from "./heartbeat-runner.js"; import { seedMainSessionStore, diff --git a/src/infra/heartbeat-runner.ts b/src/infra/heartbeat-runner.ts index 2f886163319..4a4ca1b0493 100644 --- a/src/infra/heartbeat-runner.ts +++ b/src/infra/heartbeat-runner.ts @@ -12,7 +12,7 @@ import { } from "../agents/agent-scope.js"; import { appendCronStyleCurrentTimeLine } from "../agents/current-time.js"; import { resolveEffectiveMessagesConfig } from "../agents/identity.js"; -import { resolveEmbeddedSessionLane } from "../agents/pi-embedded-runner.js"; +import { resolveEmbeddedSessionLane } from "../agents/pi-embedded-runner/lanes.js"; import { DEFAULT_HEARTBEAT_FILENAME } from "../agents/workspace.js"; import { resolveHeartbeatReplyPayload } from "../auto-reply/heartbeat-reply-payload.js"; import { diff --git a/src/infra/system-events.test.ts b/src/infra/system-events.test.ts index 3116e3ee121..398cd9087a1 100644 --- a/src/infra/system-events.test.ts +++ b/src/infra/system-events.test.ts @@ -1,8 +1,8 @@ import { beforeEach, describe, expect, it } from "vitest"; -import { drainFormattedSystemEvents } from "../auto-reply/reply/session-updates.js"; +import { drainFormattedSystemEvents } from "../auto-reply/reply/session-system-events.js"; import type { OpenClawConfig } from "../config/config.js"; -import { resolveMainSessionKey } from "../config/sessions.js"; -import { isCronSystemEvent } from "./heartbeat-runner.js"; +import { resolveMainSessionKey } from "../config/sessions/main-session.js"; +import { isCronSystemEvent } from "./heartbeat-events-filter.js"; import { consumeSystemEventEntries, drainSystemEventEntries,