mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 07:10:43 +00:00
test: share auto-reply session fixtures
This commit is contained in:
@@ -14,6 +14,32 @@ import {
|
||||
|
||||
installQueueRuntimeErrorSilencer();
|
||||
|
||||
const collectSettings: QueueSettings = {
|
||||
mode: "collect",
|
||||
debounceMs: 0,
|
||||
cap: 50,
|
||||
dropPolicy: "summarize",
|
||||
};
|
||||
|
||||
function createFollowupCollector(expectedCalls = 1): {
|
||||
calls: FollowupRun[];
|
||||
done: ReturnType<typeof createDeferred<void>>;
|
||||
runFollowup: (run: FollowupRun) => Promise<void>;
|
||||
} {
|
||||
const calls: FollowupRun[] = [];
|
||||
const done = createDeferred<void>();
|
||||
return {
|
||||
calls,
|
||||
done,
|
||||
runFollowup: async (run: FollowupRun) => {
|
||||
calls.push(run);
|
||||
if (calls.length >= expectedCalls) {
|
||||
done.resolve();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
describe("followup queue deduplication", () => {
|
||||
beforeEach(() => {
|
||||
resetRecentQueuedMessageIdDedupe();
|
||||
@@ -21,21 +47,7 @@ describe("followup queue deduplication", () => {
|
||||
|
||||
it("deduplicates messages with same Discord message_id", async () => {
|
||||
const key = `test-dedup-message-id-${Date.now()}`;
|
||||
const calls: FollowupRun[] = [];
|
||||
const done = createDeferred<void>();
|
||||
const expectedCalls = 1;
|
||||
const runFollowup = async (run: FollowupRun) => {
|
||||
calls.push(run);
|
||||
if (calls.length >= expectedCalls) {
|
||||
done.resolve();
|
||||
}
|
||||
};
|
||||
const settings: QueueSettings = {
|
||||
mode: "collect",
|
||||
debounceMs: 0,
|
||||
cap: 50,
|
||||
dropPolicy: "summarize",
|
||||
};
|
||||
const { calls, done, runFollowup } = createFollowupCollector();
|
||||
|
||||
const first = enqueueFollowupRun(
|
||||
key,
|
||||
@@ -45,7 +57,7 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "discord",
|
||||
originatingTo: "channel:123",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
);
|
||||
expect(first).toBe(true);
|
||||
|
||||
@@ -57,7 +69,7 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "discord",
|
||||
originatingTo: "channel:123",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
);
|
||||
expect(second).toBe(false);
|
||||
|
||||
@@ -69,7 +81,7 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "discord",
|
||||
originatingTo: "channel:123",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
);
|
||||
expect(third).toBe(true);
|
||||
|
||||
@@ -80,18 +92,7 @@ describe("followup queue deduplication", () => {
|
||||
|
||||
it("deduplicates same message_id after queue drain restarts", async () => {
|
||||
const key = `test-dedup-after-drain-${Date.now()}`;
|
||||
const calls: FollowupRun[] = [];
|
||||
const done = createDeferred<void>();
|
||||
const runFollowup = async (run: FollowupRun) => {
|
||||
calls.push(run);
|
||||
done.resolve();
|
||||
};
|
||||
const settings: QueueSettings = {
|
||||
mode: "collect",
|
||||
debounceMs: 0,
|
||||
cap: 50,
|
||||
dropPolicy: "summarize",
|
||||
};
|
||||
const { calls, done, runFollowup } = createFollowupCollector();
|
||||
|
||||
const first = enqueueFollowupRun(
|
||||
key,
|
||||
@@ -101,7 +102,7 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "signal",
|
||||
originatingTo: "+10000000000",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
);
|
||||
expect(first).toBe(true);
|
||||
|
||||
@@ -116,7 +117,7 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "signal",
|
||||
originatingTo: "+10000000000",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
);
|
||||
|
||||
expect(redelivery).toBe(false);
|
||||
@@ -134,18 +135,7 @@ describe("followup queue deduplication", () => {
|
||||
);
|
||||
const { clearSessionQueues } = await import("./queue.js");
|
||||
const key = `test-dedup-cross-module-${Date.now()}`;
|
||||
const calls: FollowupRun[] = [];
|
||||
const done = createDeferred<void>();
|
||||
const runFollowup = async (run: FollowupRun) => {
|
||||
calls.push(run);
|
||||
done.resolve();
|
||||
};
|
||||
const settings: QueueSettings = {
|
||||
mode: "collect",
|
||||
debounceMs: 0,
|
||||
cap: 50,
|
||||
dropPolicy: "summarize",
|
||||
};
|
||||
const { calls, done, runFollowup } = createFollowupCollector();
|
||||
|
||||
enqueueA.resetRecentQueuedMessageIdDedupe();
|
||||
enqueueB.resetRecentQueuedMessageIdDedupe();
|
||||
@@ -160,7 +150,7 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "signal",
|
||||
originatingTo: "+10000000000",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
),
|
||||
).toBe(true);
|
||||
|
||||
@@ -177,7 +167,7 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "signal",
|
||||
originatingTo: "+10000000000",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
),
|
||||
).toBe(false);
|
||||
expect(calls).toHaveLength(1);
|
||||
@@ -190,18 +180,7 @@ describe("followup queue deduplication", () => {
|
||||
|
||||
it("does not collide recent message-id keys when routing contains delimiters", async () => {
|
||||
const key = `test-dedup-key-collision-${Date.now()}`;
|
||||
const calls: FollowupRun[] = [];
|
||||
const done = createDeferred<void>();
|
||||
const runFollowup = async (run: FollowupRun) => {
|
||||
calls.push(run);
|
||||
done.resolve();
|
||||
};
|
||||
const settings: QueueSettings = {
|
||||
mode: "collect",
|
||||
debounceMs: 0,
|
||||
cap: 50,
|
||||
dropPolicy: "summarize",
|
||||
};
|
||||
const { done, runFollowup } = createFollowupCollector();
|
||||
|
||||
const first = enqueueFollowupRun(
|
||||
key,
|
||||
@@ -211,7 +190,7 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "signal|group",
|
||||
originatingTo: "peer",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
);
|
||||
expect(first).toBe(true);
|
||||
|
||||
@@ -226,19 +205,13 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "signal",
|
||||
originatingTo: "group|peer",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
);
|
||||
expect(second).toBe(true);
|
||||
});
|
||||
|
||||
it("deduplicates exact prompt when routing matches and no message id", async () => {
|
||||
const key = `test-dedup-whatsapp-${Date.now()}`;
|
||||
const settings: QueueSettings = {
|
||||
mode: "collect",
|
||||
debounceMs: 0,
|
||||
cap: 50,
|
||||
dropPolicy: "summarize",
|
||||
};
|
||||
|
||||
const first = enqueueFollowupRun(
|
||||
key,
|
||||
@@ -247,7 +220,7 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "whatsapp",
|
||||
originatingTo: "+1234567890",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
);
|
||||
expect(first).toBe(true);
|
||||
|
||||
@@ -258,7 +231,7 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "whatsapp",
|
||||
originatingTo: "+1234567890",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
);
|
||||
expect(second).toBe(true);
|
||||
|
||||
@@ -269,19 +242,13 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "whatsapp",
|
||||
originatingTo: "+1234567890",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
);
|
||||
expect(third).toBe(true);
|
||||
});
|
||||
|
||||
it("does not deduplicate across different providers without message id", async () => {
|
||||
const key = `test-dedup-cross-provider-${Date.now()}`;
|
||||
const settings: QueueSettings = {
|
||||
mode: "collect",
|
||||
debounceMs: 0,
|
||||
cap: 50,
|
||||
dropPolicy: "summarize",
|
||||
};
|
||||
|
||||
const first = enqueueFollowupRun(
|
||||
key,
|
||||
@@ -290,7 +257,7 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "whatsapp",
|
||||
originatingTo: "+1234567890",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
);
|
||||
expect(first).toBe(true);
|
||||
|
||||
@@ -301,19 +268,13 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "discord",
|
||||
originatingTo: "channel:123",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
);
|
||||
expect(second).toBe(true);
|
||||
});
|
||||
|
||||
it("can opt-in to prompt-based dedupe when message id is absent", async () => {
|
||||
const key = `test-dedup-prompt-mode-${Date.now()}`;
|
||||
const settings: QueueSettings = {
|
||||
mode: "collect",
|
||||
debounceMs: 0,
|
||||
cap: 50,
|
||||
dropPolicy: "summarize",
|
||||
};
|
||||
|
||||
const first = enqueueFollowupRun(
|
||||
key,
|
||||
@@ -322,7 +283,7 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "whatsapp",
|
||||
originatingTo: "+1234567890",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
"prompt",
|
||||
);
|
||||
expect(first).toBe(true);
|
||||
@@ -334,7 +295,7 @@ describe("followup queue deduplication", () => {
|
||||
originatingChannel: "whatsapp",
|
||||
originatingTo: "+1234567890",
|
||||
}),
|
||||
settings,
|
||||
collectSettings,
|
||||
"prompt",
|
||||
);
|
||||
expect(second).toBe(false);
|
||||
|
||||
@@ -53,6 +53,50 @@ async function writeTranscript(
|
||||
return transcriptPath;
|
||||
}
|
||||
|
||||
async function createStoredSession(params: {
|
||||
prefix: string;
|
||||
sessionKey: string;
|
||||
sessionId: string;
|
||||
text?: string;
|
||||
updatedAt?: number;
|
||||
}): Promise<{ storePath: string; transcriptPath: string }> {
|
||||
const storePath = await createStorePath(params.prefix);
|
||||
const transcriptPath = await writeTranscript(storePath, params.sessionId, params.text);
|
||||
await writeStore(storePath, {
|
||||
[params.sessionKey]: {
|
||||
sessionId: params.sessionId,
|
||||
sessionFile: transcriptPath,
|
||||
updatedAt: params.updatedAt ?? Date.now(),
|
||||
},
|
||||
});
|
||||
return { storePath, transcriptPath };
|
||||
}
|
||||
|
||||
type SessionResetConfig = NonNullable<NonNullable<OpenClawConfig["session"]>["reset"]>;
|
||||
|
||||
async function initStoredSessionState(params: {
|
||||
prefix: string;
|
||||
sessionKey: string;
|
||||
sessionId: string;
|
||||
text: string;
|
||||
updatedAt: number;
|
||||
reset?: SessionResetConfig;
|
||||
}): Promise<void> {
|
||||
const { storePath } = await createStoredSession(params);
|
||||
const cfg = {
|
||||
session: {
|
||||
store: storePath,
|
||||
...(params.reset ? { reset: params.reset } : {}),
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
await initSessionState({
|
||||
ctx: { Body: "hello", SessionKey: params.sessionKey },
|
||||
cfg,
|
||||
commandAuthorized: true,
|
||||
});
|
||||
}
|
||||
|
||||
describe("session hook context wiring", () => {
|
||||
beforeEach(() => {
|
||||
hookRunnerMocks.hasHooks.mockReset();
|
||||
@@ -90,14 +134,10 @@ describe("session hook context wiring", () => {
|
||||
|
||||
it("passes sessionKey to session_end hook context on reset", async () => {
|
||||
const sessionKey = "agent:main:telegram:direct:123";
|
||||
const storePath = await createStorePath("openclaw-session-hook-end");
|
||||
const transcriptPath = await writeTranscript(storePath, "old-session");
|
||||
await writeStore(storePath, {
|
||||
[sessionKey]: {
|
||||
sessionId: "old-session",
|
||||
sessionFile: transcriptPath,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
const { storePath } = await createStoredSession({
|
||||
prefix: "openclaw-session-hook-end",
|
||||
sessionKey,
|
||||
sessionId: "old-session",
|
||||
});
|
||||
const cfg = { session: { store: storePath } } as OpenClawConfig;
|
||||
|
||||
@@ -127,14 +167,11 @@ describe("session hook context wiring", () => {
|
||||
|
||||
it("marks explicit /reset rollovers with reason reset", async () => {
|
||||
const sessionKey = "agent:main:telegram:direct:456";
|
||||
const storePath = await createStorePath("openclaw-session-hook-explicit-reset");
|
||||
const transcriptPath = await writeTranscript(storePath, "reset-session", "reset me");
|
||||
await writeStore(storePath, {
|
||||
[sessionKey]: {
|
||||
sessionId: "reset-session",
|
||||
sessionFile: transcriptPath,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
const { storePath } = await createStoredSession({
|
||||
prefix: "openclaw-session-hook-explicit-reset",
|
||||
sessionKey,
|
||||
sessionId: "reset-session",
|
||||
text: "reset me",
|
||||
});
|
||||
const cfg = { session: { store: storePath } } as OpenClawConfig;
|
||||
|
||||
@@ -150,14 +187,11 @@ describe("session hook context wiring", () => {
|
||||
|
||||
it("maps custom reset trigger aliases to the new-session reason", async () => {
|
||||
const sessionKey = "agent:main:telegram:direct:alias";
|
||||
const storePath = await createStorePath("openclaw-session-hook-reset-alias");
|
||||
const transcriptPath = await writeTranscript(storePath, "alias-session", "alias me");
|
||||
await writeStore(storePath, {
|
||||
[sessionKey]: {
|
||||
sessionId: "alias-session",
|
||||
sessionFile: transcriptPath,
|
||||
updatedAt: Date.now(),
|
||||
},
|
||||
const { storePath } = await createStoredSession({
|
||||
prefix: "openclaw-session-hook-reset-alias",
|
||||
sessionKey,
|
||||
sessionId: "alias-session",
|
||||
text: "alias me",
|
||||
});
|
||||
const cfg = {
|
||||
session: {
|
||||
@@ -181,21 +215,12 @@ describe("session hook context wiring", () => {
|
||||
try {
|
||||
vi.setSystemTime(new Date(2026, 0, 18, 5, 0, 0));
|
||||
const sessionKey = "agent:main:telegram:direct:daily";
|
||||
const storePath = await createStorePath("openclaw-session-hook-daily");
|
||||
const transcriptPath = await writeTranscript(storePath, "daily-session", "daily");
|
||||
await writeStore(storePath, {
|
||||
[sessionKey]: {
|
||||
sessionId: "daily-session",
|
||||
sessionFile: transcriptPath,
|
||||
updatedAt: new Date(2026, 0, 18, 3, 0, 0).getTime(),
|
||||
},
|
||||
});
|
||||
const cfg = { session: { store: storePath } } as OpenClawConfig;
|
||||
|
||||
await initSessionState({
|
||||
ctx: { Body: "hello", SessionKey: sessionKey },
|
||||
cfg,
|
||||
commandAuthorized: true,
|
||||
await initStoredSessionState({
|
||||
prefix: "openclaw-session-hook-daily",
|
||||
sessionKey,
|
||||
sessionId: "daily-session",
|
||||
text: "daily",
|
||||
updatedAt: new Date(2026, 0, 18, 3, 0, 0).getTime(),
|
||||
});
|
||||
|
||||
const [event] = hookRunnerMocks.runSessionEnd.mock.calls[0] ?? [];
|
||||
@@ -216,30 +241,17 @@ describe("session hook context wiring", () => {
|
||||
try {
|
||||
vi.setSystemTime(new Date(2026, 0, 18, 5, 0, 0));
|
||||
const sessionKey = "agent:main:telegram:direct:idle";
|
||||
const storePath = await createStorePath("openclaw-session-hook-idle");
|
||||
const transcriptPath = await writeTranscript(storePath, "idle-session", "idle");
|
||||
await writeStore(storePath, {
|
||||
[sessionKey]: {
|
||||
sessionId: "idle-session",
|
||||
sessionFile: transcriptPath,
|
||||
updatedAt: new Date(2026, 0, 18, 3, 0, 0).getTime(),
|
||||
await initStoredSessionState({
|
||||
prefix: "openclaw-session-hook-idle",
|
||||
sessionKey,
|
||||
sessionId: "idle-session",
|
||||
text: "idle",
|
||||
updatedAt: new Date(2026, 0, 18, 3, 0, 0).getTime(),
|
||||
reset: {
|
||||
mode: "idle",
|
||||
idleMinutes: 30,
|
||||
},
|
||||
});
|
||||
const cfg = {
|
||||
session: {
|
||||
store: storePath,
|
||||
reset: {
|
||||
mode: "idle",
|
||||
idleMinutes: 30,
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
await initSessionState({
|
||||
ctx: { Body: "hello", SessionKey: sessionKey },
|
||||
cfg,
|
||||
commandAuthorized: true,
|
||||
});
|
||||
|
||||
const [event] = hookRunnerMocks.runSessionEnd.mock.calls[0] ?? [];
|
||||
expect(event).toMatchObject({ reason: "idle" });
|
||||
@@ -253,31 +265,18 @@ describe("session hook context wiring", () => {
|
||||
try {
|
||||
vi.setSystemTime(new Date(2026, 0, 18, 5, 30, 0));
|
||||
const sessionKey = "agent:main:telegram:direct:overlap";
|
||||
const storePath = await createStorePath("openclaw-session-hook-overlap");
|
||||
const transcriptPath = await writeTranscript(storePath, "overlap-session", "overlap");
|
||||
await writeStore(storePath, {
|
||||
[sessionKey]: {
|
||||
sessionId: "overlap-session",
|
||||
sessionFile: transcriptPath,
|
||||
updatedAt: new Date(2026, 0, 18, 4, 45, 0).getTime(),
|
||||
await initStoredSessionState({
|
||||
prefix: "openclaw-session-hook-overlap",
|
||||
sessionKey,
|
||||
sessionId: "overlap-session",
|
||||
text: "overlap",
|
||||
updatedAt: new Date(2026, 0, 18, 4, 45, 0).getTime(),
|
||||
reset: {
|
||||
mode: "daily",
|
||||
atHour: 4,
|
||||
idleMinutes: 30,
|
||||
},
|
||||
});
|
||||
const cfg = {
|
||||
session: {
|
||||
store: storePath,
|
||||
reset: {
|
||||
mode: "daily",
|
||||
atHour: 4,
|
||||
idleMinutes: 30,
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
await initSessionState({
|
||||
ctx: { Body: "hello", SessionKey: sessionKey },
|
||||
cfg,
|
||||
commandAuthorized: true,
|
||||
});
|
||||
|
||||
const [event] = hookRunnerMocks.runSessionEnd.mock.calls[0] ?? [];
|
||||
expect(event).toMatchObject({ reason: "idle" });
|
||||
|
||||
@@ -3,7 +3,6 @@ import path from "node:path";
|
||||
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import { saveSessionStore } from "../../config/sessions/store.js";
|
||||
import type { SessionEntry } from "../../config/sessions/types.js";
|
||||
import type { MsgContext } from "../templating.js";
|
||||
import { initSessionState } from "./session.js";
|
||||
|
||||
@@ -63,19 +62,22 @@ describe("initSessionState - heartbeat should not trigger session reset", () =>
|
||||
...overrides,
|
||||
});
|
||||
|
||||
const saveExistingSession = async (sessionId: string, updatedAt: number): Promise<void> => {
|
||||
await saveSessionStore(storePath, {
|
||||
"main:user123": {
|
||||
sessionId,
|
||||
updatedAt,
|
||||
systemSent: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
it("should NOT reset session when Provider is 'heartbeat'", async () => {
|
||||
// Setup: Create a session entry that is "stale" (older than idle timeout)
|
||||
const now = Date.now();
|
||||
const staleTime = now - 10 * 60 * 1000; // 10 minutes ago (exceeds 5min idle timeout)
|
||||
|
||||
const initialStore: Record<string, SessionEntry> = {
|
||||
"main:user123": {
|
||||
sessionId: "original-session-id-12345",
|
||||
updatedAt: staleTime,
|
||||
systemSent: true,
|
||||
},
|
||||
};
|
||||
await saveSessionStore(storePath, initialStore);
|
||||
await saveExistingSession("original-session-id-12345", staleTime);
|
||||
|
||||
const cfg = createBaseConfig();
|
||||
const ctx = createBaseCtx({
|
||||
@@ -101,14 +103,7 @@ describe("initSessionState - heartbeat should not trigger session reset", () =>
|
||||
const now = Date.now();
|
||||
const staleTime = now - 10 * 60 * 1000; // 10 minutes ago (exceeds 5min idle timeout)
|
||||
|
||||
const initialStore: Record<string, SessionEntry> = {
|
||||
"main:user123": {
|
||||
sessionId: "original-session-id-12345",
|
||||
updatedAt: staleTime,
|
||||
systemSent: true,
|
||||
},
|
||||
};
|
||||
await saveSessionStore(storePath, initialStore);
|
||||
await saveExistingSession("original-session-id-12345", staleTime);
|
||||
|
||||
const cfg = createBaseConfig();
|
||||
const ctx = createBaseCtx({
|
||||
@@ -133,14 +128,7 @@ describe("initSessionState - heartbeat should not trigger session reset", () =>
|
||||
const now = Date.now();
|
||||
const yesterday = now - 25 * 60 * 60 * 1000; // 25 hours ago
|
||||
|
||||
const initialStore: Record<string, SessionEntry> = {
|
||||
"main:user123": {
|
||||
sessionId: "original-session-id-67890",
|
||||
updatedAt: yesterday,
|
||||
systemSent: true,
|
||||
},
|
||||
};
|
||||
await saveSessionStore(storePath, initialStore);
|
||||
await saveExistingSession("original-session-id-67890", yesterday);
|
||||
|
||||
const cfg = createBaseConfig();
|
||||
cfg.session!.reset = {
|
||||
@@ -169,14 +157,7 @@ describe("initSessionState - heartbeat should not trigger session reset", () =>
|
||||
const now = Date.now();
|
||||
const staleTime = now - 10 * 60 * 1000;
|
||||
|
||||
const initialStore: Record<string, SessionEntry> = {
|
||||
"main:user123": {
|
||||
sessionId: "cron-session-id-abcde",
|
||||
updatedAt: staleTime,
|
||||
systemSent: true,
|
||||
},
|
||||
};
|
||||
await saveSessionStore(storePath, initialStore);
|
||||
await saveExistingSession("cron-session-id-abcde", staleTime);
|
||||
|
||||
const cfg = createBaseConfig();
|
||||
const ctx = createBaseCtx({
|
||||
@@ -200,14 +181,7 @@ describe("initSessionState - heartbeat should not trigger session reset", () =>
|
||||
const now = Date.now();
|
||||
const staleTime = now - 10 * 60 * 1000;
|
||||
|
||||
const initialStore: Record<string, SessionEntry> = {
|
||||
"main:user123": {
|
||||
sessionId: "exec-session-id-fghij",
|
||||
updatedAt: staleTime,
|
||||
systemSent: true,
|
||||
},
|
||||
};
|
||||
await saveSessionStore(storePath, initialStore);
|
||||
await saveExistingSession("exec-session-id-fghij", staleTime);
|
||||
|
||||
const cfg = createBaseConfig();
|
||||
const ctx = createBaseCtx({
|
||||
|
||||
Reference in New Issue
Block a user