openskynet / src /config /sessions /store.session-key-normalization.test.ts
Darochin's picture
Mirror OpenSkyNet workspace snapshot from Git HEAD
fc93158 verified
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import type { MsgContext } from "../../auto-reply/templating.js";
import {
clearSessionStoreCacheForTest,
loadSessionStore,
recordSessionMetaFromInbound,
updateLastRoute,
} from "../sessions.js";
const CANONICAL_KEY = "agent:main:webchat:dm:mixed-user";
const MIXED_CASE_KEY = "Agent:Main:WebChat:DM:MiXeD-User";
function createInboundContext(): MsgContext {
return {
Provider: "webchat",
Surface: "webchat",
ChatType: "direct",
From: "WebChat:User-1",
To: "webchat:agent",
SessionKey: MIXED_CASE_KEY,
OriginatingTo: "webchat:user-1",
};
}
describe("session store key normalization", () => {
let tempDir = "";
let storePath = "";
beforeEach(async () => {
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-session-key-normalize-"));
storePath = path.join(tempDir, "sessions.json");
await fs.writeFile(storePath, "{}", "utf-8");
});
afterEach(async () => {
clearSessionStoreCacheForTest();
if (tempDir) {
await fs.rm(tempDir, { recursive: true, force: true });
}
});
it("records inbound metadata under a canonical lowercase key", async () => {
await recordSessionMetaFromInbound({
storePath,
sessionKey: MIXED_CASE_KEY,
ctx: createInboundContext(),
});
const store = loadSessionStore(storePath, { skipCache: true });
expect(Object.keys(store)).toEqual([CANONICAL_KEY]);
expect(store[CANONICAL_KEY]?.origin?.provider).toBe("webchat");
});
it("does not create a duplicate mixed-case key when last route is updated", async () => {
await recordSessionMetaFromInbound({
storePath,
sessionKey: CANONICAL_KEY,
ctx: createInboundContext(),
});
await updateLastRoute({
storePath,
sessionKey: MIXED_CASE_KEY,
channel: "webchat",
to: "webchat:user-1",
});
const store = loadSessionStore(storePath, { skipCache: true });
expect(Object.keys(store)).toEqual([CANONICAL_KEY]);
expect(store[CANONICAL_KEY]).toEqual(
expect.objectContaining({
lastChannel: "webchat",
lastTo: "webchat:user-1",
}),
);
});
it("migrates legacy mixed-case entries to the canonical key on update", async () => {
await fs.writeFile(
storePath,
JSON.stringify(
{
[MIXED_CASE_KEY]: {
sessionId: "legacy-session",
updatedAt: 1,
chatType: "direct",
channel: "webchat",
},
},
null,
2,
),
"utf-8",
);
clearSessionStoreCacheForTest();
await updateLastRoute({
storePath,
sessionKey: CANONICAL_KEY,
channel: "webchat",
to: "webchat:user-2",
});
const store = loadSessionStore(storePath, { skipCache: true });
expect(store[CANONICAL_KEY]?.sessionId).toBe("legacy-session");
expect(store[MIXED_CASE_KEY]).toBeUndefined();
});
it("preserves updatedAt when recording inbound metadata for an existing session", async () => {
await fs.writeFile(
storePath,
JSON.stringify(
{
[CANONICAL_KEY]: {
sessionId: "existing-session",
updatedAt: 1111,
chatType: "direct",
channel: "webchat",
origin: {
provider: "webchat",
chatType: "direct",
from: "WebChat:User-1",
to: "webchat:user-1",
},
},
},
null,
2,
),
"utf-8",
);
clearSessionStoreCacheForTest();
await recordSessionMetaFromInbound({
storePath,
sessionKey: CANONICAL_KEY,
ctx: createInboundContext(),
});
const store = loadSessionStore(storePath, { skipCache: true });
expect(store[CANONICAL_KEY]?.sessionId).toBe("existing-session");
expect(store[CANONICAL_KEY]?.updatedAt).toBe(1111);
expect(store[CANONICAL_KEY]?.origin?.provider).toBe("webchat");
});
});