import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import type { MsgContext } from "../auto-reply/templating.js"; const recordSessionMetaFromInboundMock = vi.fn((_args?: unknown) => Promise.resolve(undefined)); const updateLastRouteMock = vi.fn((_args?: unknown) => Promise.resolve(undefined)); vi.mock("../config/sessions/inbound.runtime.js", () => ({ recordSessionMetaFromInbound: (args: unknown) => recordSessionMetaFromInboundMock(args), updateLastRoute: (args: unknown) => updateLastRouteMock(args), })); type SessionModule = typeof import("./session.js"); let recordInboundSession: SessionModule["recordInboundSession"]; describe("recordInboundSession", () => { const ctx: MsgContext = { Provider: "demo-channel", From: "demo-channel:1234", SessionKey: "agent:main:demo-channel:1234:thread:42", OriginatingTo: "demo-channel:1234", }; beforeAll(async () => { ({ recordInboundSession } = await import("./session.js")); }); beforeEach(() => { recordSessionMetaFromInboundMock.mockClear(); updateLastRouteMock.mockClear(); }); it("does not pass ctx when updating a different session key", async () => { await recordInboundSession({ storePath: "/tmp/openclaw-session-store.json", sessionKey: "agent:main:demo-channel:1234:thread:42", ctx, updateLastRoute: { sessionKey: "agent:main:main", channel: "demo-channel", to: "demo-channel:1234", }, onRecordError: vi.fn(), }); expect(updateLastRouteMock).toHaveBeenCalledWith( expect.objectContaining({ sessionKey: "agent:main:main", ctx: undefined, deliveryContext: expect.objectContaining({ channel: "demo-channel", to: "demo-channel:1234", }), }), ); }); it("passes ctx when updating the same session key", async () => { await recordInboundSession({ storePath: "/tmp/openclaw-session-store.json", sessionKey: "agent:main:demo-channel:1234:thread:42", ctx, updateLastRoute: { sessionKey: "agent:main:demo-channel:1234:thread:42", channel: "demo-channel", to: "demo-channel:1234", }, onRecordError: vi.fn(), }); expect(updateLastRouteMock).toHaveBeenCalledWith( expect.objectContaining({ sessionKey: "agent:main:demo-channel:1234:thread:42", ctx, deliveryContext: expect.objectContaining({ channel: "demo-channel", to: "demo-channel:1234", }), }), ); }); it("normalizes mixed-case session keys before recording and route updates", async () => { await recordInboundSession({ storePath: "/tmp/openclaw-session-store.json", sessionKey: "Agent:Main:Demo-Channel:1234:Thread:42", ctx, updateLastRoute: { sessionKey: "agent:main:demo-channel:1234:thread:42", channel: "demo-channel", to: "demo-channel:1234", }, onRecordError: vi.fn(), }); expect(recordSessionMetaFromInboundMock).toHaveBeenCalledWith( expect.objectContaining({ sessionKey: "agent:main:demo-channel:1234:thread:42", }), ); expect(updateLastRouteMock).toHaveBeenCalledWith( expect.objectContaining({ sessionKey: "agent:main:demo-channel:1234:thread:42", ctx, }), ); }); it("skips last-route updates when main DM owner pin mismatches sender", async () => { const onSkip = vi.fn(); await recordInboundSession({ storePath: "/tmp/openclaw-session-store.json", sessionKey: "agent:main:demo-channel:1234:thread:42", ctx, updateLastRoute: { sessionKey: "agent:main:main", channel: "demo-channel", to: "demo-channel:1234", mainDmOwnerPin: { ownerRecipient: "1234", senderRecipient: "9999", onSkip, }, }, onRecordError: vi.fn(), }); expect(updateLastRouteMock).not.toHaveBeenCalled(); expect(onSkip).toHaveBeenCalledWith({ ownerRecipient: "1234", senderRecipient: "9999", }); }); });