Skip to content

Commit 601ab84

Browse files
committed
test(gateway): share configured global session stores
1 parent abc3fa0 commit 601ab84

3 files changed

Lines changed: 133 additions & 165 deletions

File tree

src/gateway/server.sessions.delete-lifecycle.test.ts

Lines changed: 11 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
writeAcpSessionMetaForMigration,
77
} from "../acp/runtime/session-meta.js";
88
import { closeOpenClawStateDatabaseForTest } from "../state/openclaw-state-db.js";
9-
import { embeddedRunMock, rpcReq, testState, writeSessionStore } from "./test-helpers.js";
9+
import { embeddedRunMock, rpcReq, writeSessionStore } from "./test-helpers.js";
1010
import {
1111
setupGatewaySessionsTestHarness,
1212
sessionLifecycleHookMocks,
@@ -22,7 +22,12 @@ import {
2222
directSessionReq,
2323
} from "./test/server-sessions.test-helpers.js";
2424

25-
const { createSessionStoreDir, openClient } = setupGatewaySessionsTestHarness();
25+
const {
26+
createConfiguredGlobalAgentSessionStore,
27+
createSessionStoreDir,
28+
openClient,
29+
resetConfiguredGlobalAgentSessionStore,
30+
} = setupGatewaySessionsTestHarness();
2631

2732
afterEach(() => {
2833
closeOpenClawStateDatabaseForTest();
@@ -178,66 +183,22 @@ test("sessions.delete limits plugin-runtime cleanup to sessions owned by that pl
178183
});
179184

180185
test("sessions.delete scopes selected global deletes to the requested agent", async () => {
181-
const { dir } = await createSessionStoreDir();
182-
const storeTemplate = path.join(dir, "{agentId}", "sessions.json");
183-
testState.sessionStorePath = storeTemplate;
184-
testState.sessionConfig = { scope: "global" };
185-
await writeSessionStore({
186-
entries: {},
187-
storePath: path.join(dir, "prime-sessions.json"),
188-
});
189-
const mainStorePath = storeTemplate.replace("{agentId}", "main");
190-
const workStorePath = storeTemplate.replace("{agentId}", "work");
191-
await fs.mkdir(path.dirname(mainStorePath), { recursive: true });
192-
await fs.mkdir(path.dirname(workStorePath), { recursive: true });
193-
await fs.writeFile(
194-
mainStorePath,
195-
JSON.stringify({ global: sessionStoreEntry("sess-main-global") }, null, 2),
196-
"utf-8",
197-
);
198-
await fs.writeFile(
199-
workStorePath,
200-
JSON.stringify({ global: sessionStoreEntry("sess-work-global") }, null, 2),
201-
"utf-8",
202-
);
203-
const configPath = process.env.OPENCLAW_CONFIG_PATH;
204-
if (!configPath) {
205-
throw new Error("OPENCLAW_CONFIG_PATH is required");
206-
}
207-
await fs.writeFile(
208-
configPath,
209-
`${JSON.stringify(
210-
{
211-
agents: { list: [{ id: "main", default: true }, { id: "work" }] },
212-
session: { scope: "global", store: storeTemplate },
213-
},
214-
null,
215-
2,
216-
)}\n`,
217-
"utf-8",
218-
);
219-
const { clearConfigCache, clearRuntimeConfigSnapshot } = await import("../config/config.js");
220-
clearRuntimeConfigSnapshot();
221-
clearConfigCache();
186+
const globalStores = await createConfiguredGlobalAgentSessionStore({ writePrimeStore: true });
222187

223188
await expectSessionDeleteSucceeds({
224189
key: "global",
225190
agentId: "work",
226191
deleteTranscript: false,
227192
});
228-
const mainStore = JSON.parse(await fs.readFile(mainStorePath, "utf-8")) as {
193+
const mainStore = JSON.parse(await fs.readFile(globalStores.mainStorePath, "utf-8")) as {
229194
global?: { sessionId?: string };
230195
};
231-
const workStore = JSON.parse(await fs.readFile(workStorePath, "utf-8")) as {
196+
const workStore = JSON.parse(await fs.readFile(globalStores.workStorePath, "utf-8")) as {
232197
global?: { sessionId?: string };
233198
};
234199
expect(mainStore.global?.sessionId).toBe("sess-main-global");
235200
expect(workStore.global).toBeUndefined();
236-
testState.sessionStorePath = undefined;
237-
testState.sessionConfig = undefined;
238-
await fs.writeFile(configPath, "{}\n", "utf-8");
239-
clearRuntimeConfigSnapshot();
240-
clearConfigCache();
201+
await resetConfiguredGlobalAgentSessionStore(globalStores);
241202
});
242203

243204
test("sessions.delete closes ACP runtime handles before removing ACP sessions", async () => {

src/gateway/server.sessions.list-changed.test.ts

Lines changed: 12 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@ import {
1010
sessionStoreEntry,
1111
} from "./test/server-sessions.test-helpers.js";
1212

13-
const { createSessionStoreDir, openClient } = setupGatewaySessionsTestHarness();
13+
const {
14+
createConfiguredGlobalAgentSessionStore,
15+
createSessionStoreDir,
16+
openClient,
17+
resetConfiguredGlobalAgentSessionStore,
18+
} = setupGatewaySessionsTestHarness();
1419

1520
type MockCalls = {
1621
mock: { calls: unknown[][] };
@@ -178,114 +183,6 @@ function expectMainPatchBroadcast(
178183
});
179184
}
180185

181-
async function setupGlobalAgentSessionStores({
182-
writePrimeStore = false,
183-
withTranscripts = false,
184-
}: {
185-
writePrimeStore?: boolean;
186-
withTranscripts?: boolean;
187-
} = {}) {
188-
const { dir } = await createSessionStoreDir();
189-
const storeTemplate = path.join(dir, "{agentId}", "sessions.json");
190-
testState.sessionStorePath = storeTemplate;
191-
testState.sessionConfig = { scope: "global" };
192-
if (writePrimeStore) {
193-
await writeSessionStore({
194-
entries: {},
195-
storePath: path.join(dir, "prime-sessions.json"),
196-
});
197-
}
198-
199-
const mainStorePath = storeTemplate.replace("{agentId}", "main");
200-
const workStorePath = storeTemplate.replace("{agentId}", "work");
201-
const mainTranscript = path.join(path.dirname(mainStorePath), "sess-main-global.jsonl");
202-
const workTranscript = path.join(path.dirname(workStorePath), "sess-work-global.jsonl");
203-
await fs.mkdir(path.dirname(mainStorePath), { recursive: true });
204-
await fs.mkdir(path.dirname(workStorePath), { recursive: true });
205-
if (withTranscripts) {
206-
await fs.writeFile(mainTranscript, "main one\nmain two\n", "utf-8");
207-
await fs.writeFile(workTranscript, "work one\nwork two\n", "utf-8");
208-
}
209-
await fs.writeFile(
210-
mainStorePath,
211-
JSON.stringify(
212-
{
213-
global: sessionStoreEntry(
214-
"sess-main-global",
215-
withTranscripts ? { sessionFile: mainTranscript } : undefined,
216-
),
217-
},
218-
null,
219-
2,
220-
),
221-
"utf-8",
222-
);
223-
await fs.writeFile(
224-
workStorePath,
225-
JSON.stringify(
226-
{
227-
global: sessionStoreEntry(
228-
"sess-work-global",
229-
withTranscripts
230-
? { authProfileOverride: "github-copilot:work", sessionFile: workTranscript }
231-
: undefined,
232-
),
233-
},
234-
null,
235-
2,
236-
),
237-
"utf-8",
238-
);
239-
240-
const configPath = process.env.OPENCLAW_CONFIG_PATH;
241-
if (!configPath) {
242-
throw new Error("OPENCLAW_CONFIG_PATH is required");
243-
}
244-
await fs.writeFile(
245-
configPath,
246-
`${JSON.stringify(
247-
{
248-
agents: { list: [{ id: "main", default: true }, { id: "work" }] },
249-
session: { scope: "global", store: storeTemplate },
250-
},
251-
null,
252-
2,
253-
)}\n`,
254-
"utf-8",
255-
);
256-
const { clearConfigCache, clearRuntimeConfigSnapshot, getRuntimeConfig } =
257-
await getGatewayConfigModule();
258-
clearRuntimeConfigSnapshot();
259-
clearConfigCache();
260-
261-
return {
262-
clearConfigCache,
263-
clearRuntimeConfigSnapshot,
264-
configPath,
265-
getRuntimeConfig,
266-
mainStorePath,
267-
mainTranscript,
268-
workStorePath,
269-
workTranscript,
270-
};
271-
}
272-
273-
async function resetGlobalAgentSessionStores({
274-
clearConfigCache,
275-
clearRuntimeConfigSnapshot,
276-
configPath,
277-
}: {
278-
clearConfigCache: () => void;
279-
clearRuntimeConfigSnapshot: () => void;
280-
configPath: string;
281-
}) {
282-
testState.sessionStorePath = undefined;
283-
testState.sessionConfig = undefined;
284-
await fs.writeFile(configPath, "{}\n", "utf-8");
285-
clearRuntimeConfigSnapshot();
286-
clearConfigCache();
287-
}
288-
289186
async function invokeSessionsCompact({
290187
getRuntimeConfig,
291188
params,
@@ -629,7 +526,7 @@ test("sessions.changed mutation events include sendPolicy metadata", async () =>
629526
});
630527

631528
test("sessions.patch scopes selected global mutations and events to the requested agent", async () => {
632-
const globalStores = await setupGlobalAgentSessionStores({ writePrimeStore: true });
529+
const globalStores = await createConfiguredGlobalAgentSessionStore({ writePrimeStore: true });
633530

634531
const { broadcastToConnIds, responsePayload } = await invokeSessionsPatch({
635532
key: "global",
@@ -652,11 +549,11 @@ test("sessions.patch scopes selected global mutations and events to the requeste
652549
};
653550
expect(mainStore.global?.label).toBeUndefined();
654551
expect(workStore.global?.label).toBe("Work global");
655-
await resetGlobalAgentSessionStores(globalStores);
552+
await resetConfiguredGlobalAgentSessionStore(globalStores);
656553
});
657554

658555
test("sessions.compact scopes selected global truncation to the requested agent", async () => {
659-
const globalStores = await setupGlobalAgentSessionStores({ withTranscripts: true });
556+
const globalStores = await createConfiguredGlobalAgentSessionStore({ withTranscripts: true });
660557
const { broadcastToConnIds, responsePayload } = await invokeSessionsCompact({
661558
getRuntimeConfig: globalStores.getRuntimeConfig,
662559
params: {
@@ -677,11 +574,11 @@ test("sessions.compact scopes selected global truncation to the requested agent"
677574
"main one\nmain two\n",
678575
);
679576
await expect(fs.readFile(globalStores.workTranscript, "utf-8")).resolves.toBe("work two\n");
680-
await resetGlobalAgentSessionStores(globalStores);
577+
await resetConfiguredGlobalAgentSessionStore(globalStores);
681578
});
682579

683580
test("sessions.compact passes the selected global agent into embedded compaction", async () => {
684-
const globalStores = await setupGlobalAgentSessionStores({ withTranscripts: true });
581+
const globalStores = await createConfiguredGlobalAgentSessionStore({ withTranscripts: true });
685582
const { responsePayload } = await invokeSessionsCompact({
686583
getRuntimeConfig: globalStores.getRuntimeConfig,
687584
params: {
@@ -699,7 +596,7 @@ test("sessions.compact passes the selected global agent into embedded compaction
699596
agentId: "work",
700597
authProfileId: "github-copilot:work",
701598
});
702-
await resetGlobalAgentSessionStores(globalStores);
599+
await resetConfiguredGlobalAgentSessionStore(globalStores);
703600
});
704601

705602
test("sessions.changed mutation events include subagent ownership metadata", async () => {

src/gateway/test/server-sessions.test-helpers.ts

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,114 @@ export function setupGatewaySessionsTestHarness() {
334334
};
335335
}
336336

337+
async function createConfiguredGlobalAgentSessionStore({
338+
writePrimeStore = false,
339+
withTranscripts = false,
340+
}: {
341+
writePrimeStore?: boolean;
342+
withTranscripts?: boolean;
343+
} = {}) {
344+
const { dir } = await createSessionStoreDir();
345+
const storeTemplate = path.join(dir, "{agentId}", "sessions.json");
346+
testState.sessionStorePath = storeTemplate;
347+
testState.sessionConfig = { scope: "global" };
348+
if (writePrimeStore) {
349+
await writeSessionStore({
350+
entries: {},
351+
storePath: path.join(dir, "prime-sessions.json"),
352+
});
353+
}
354+
355+
const mainStorePath = storeTemplate.replace("{agentId}", "main");
356+
const workStorePath = storeTemplate.replace("{agentId}", "work");
357+
const mainTranscript = path.join(path.dirname(mainStorePath), "sess-main-global.jsonl");
358+
const workTranscript = path.join(path.dirname(workStorePath), "sess-work-global.jsonl");
359+
await fs.mkdir(path.dirname(mainStorePath), { recursive: true });
360+
await fs.mkdir(path.dirname(workStorePath), { recursive: true });
361+
if (withTranscripts) {
362+
await fs.writeFile(mainTranscript, "main one\nmain two\n", "utf-8");
363+
await fs.writeFile(workTranscript, "work one\nwork two\n", "utf-8");
364+
}
365+
await fs.writeFile(
366+
mainStorePath,
367+
JSON.stringify(
368+
{
369+
global: sessionStoreEntry(
370+
"sess-main-global",
371+
withTranscripts ? { sessionFile: mainTranscript } : undefined,
372+
),
373+
},
374+
null,
375+
2,
376+
),
377+
"utf-8",
378+
);
379+
await fs.writeFile(
380+
workStorePath,
381+
JSON.stringify(
382+
{
383+
global: sessionStoreEntry(
384+
"sess-work-global",
385+
withTranscripts
386+
? { authProfileOverride: "github-copilot:work", sessionFile: workTranscript }
387+
: undefined,
388+
),
389+
},
390+
null,
391+
2,
392+
),
393+
"utf-8",
394+
);
395+
396+
const configPath = process.env.OPENCLAW_CONFIG_PATH;
397+
if (!configPath) {
398+
throw new Error("OPENCLAW_CONFIG_PATH is required");
399+
}
400+
await fs.writeFile(
401+
configPath,
402+
`${JSON.stringify(
403+
{
404+
agents: { list: [{ id: "main", default: true }, { id: "work" }] },
405+
session: { scope: "global", store: storeTemplate },
406+
},
407+
null,
408+
2,
409+
)}\n`,
410+
"utf-8",
411+
);
412+
const { clearConfigCache, clearRuntimeConfigSnapshot, getRuntimeConfig } =
413+
await getGatewayConfigModule();
414+
clearRuntimeConfigSnapshot();
415+
clearConfigCache();
416+
417+
return {
418+
clearConfigCache,
419+
clearRuntimeConfigSnapshot,
420+
configPath,
421+
getRuntimeConfig,
422+
mainStorePath,
423+
mainTranscript,
424+
workStorePath,
425+
workTranscript,
426+
};
427+
}
428+
429+
async function resetConfiguredGlobalAgentSessionStore({
430+
clearConfigCache,
431+
clearRuntimeConfigSnapshot,
432+
configPath,
433+
}: {
434+
clearConfigCache: () => void;
435+
clearRuntimeConfigSnapshot: () => void;
436+
configPath: string;
437+
}) {
438+
testState.sessionStorePath = undefined;
439+
testState.sessionConfig = undefined;
440+
await fs.writeFile(configPath, "{}\n", "utf-8");
441+
clearRuntimeConfigSnapshot();
442+
clearConfigCache();
443+
}
444+
337445
async function seedActiveMainSession() {
338446
const { dir, storePath } = await createSessionStoreDir();
339447
await writeSingleLineSession(dir, "sess-main", "hello");
@@ -346,10 +454,12 @@ export function setupGatewaySessionsTestHarness() {
346454
}
347455

348456
return {
457+
createConfiguredGlobalAgentSessionStore,
349458
createSessionStoreDir,
350459
createSelectedGlobalSessionStore,
351460
getHarness: requireHarness,
352461
openClient,
462+
resetConfiguredGlobalAgentSessionStore,
353463
seedActiveMainSession,
354464
};
355465
}

0 commit comments

Comments
 (0)