import { afterEach, beforeEach, describe, expect, it } from "vitest" ;
import { createInMemorySessionStore } from "./session.js" ;
describe("acp session manager" , () => {
let nowMs = 0 ;
const now = () => nowMs;
const advance = (ms: number) => {
nowMs += ms;
};
let store = createInMemorySessionStore({ now });
beforeEach(() => {
nowMs = 1 _000 ;
store = createInMemorySessionStore({ now });
});
afterEach(() => {
store.clearAllSessionsForTest();
});
it("tracks active runs and clears on cancel" , () => {
const session = store.createSession({
sessionKey: "acp:test" ,
cwd: "/tmp" ,
});
const controller = new AbortController();
store.setActiveRun(session.sessionId, "run-1" , controller);
expect(store.getSessionByRunId("run-1" )?.sessionId).toBe(session.sessionId);
const cancelled = store.cancelActiveRun(session.sessionId);
expect(cancelled).toBe(true );
expect(store.getSessionByRunId("run-1" )).toBeUndefined();
});
it("refreshes existing session IDs instead of creating duplicates" , () => {
const first = store.createSession({
sessionId: "existing" ,
sessionKey: "acp:one" ,
cwd: "/tmp/one" ,
});
advance(500 );
const refreshed = store.createSession({
sessionId: "existing" ,
sessionKey: "acp:two" ,
cwd: "/tmp/two" ,
});
expect(refreshed).toBe(first);
expect(refreshed.sessionKey).toBe("acp:two" );
expect(refreshed.cwd).toBe("/tmp/two" );
expect(refreshed.createdAt).toBe(1 _000 );
expect(refreshed.lastTouchedAt).toBe(1 _500 );
expect(store.hasSession("existing" )).toBe(true );
});
it("reaps idle sessions before enforcing the max session cap" , () => {
const boundedStore = createInMemorySessionStore({
maxSessions: 1 ,
idleTtlMs: 1 _000 ,
now,
});
try {
boundedStore.createSession({
sessionId: "old" ,
sessionKey: "acp:old" ,
cwd: "/tmp" ,
});
advance(2 _000 );
const fresh = boundedStore.createSession({
sessionId: "fresh" ,
sessionKey: "acp:fresh" ,
cwd: "/tmp" ,
});
expect(fresh.sessionId).toBe("fresh" );
expect(boundedStore.getSession("old" )).toBeUndefined();
expect(boundedStore.hasSession("old" )).toBe(false );
} finally {
boundedStore.clearAllSessionsForTest();
}
});
it("uses soft-cap eviction for the oldest idle session when full" , () => {
const boundedStore = createInMemorySessionStore({
maxSessions: 2 ,
idleTtlMs: 24 * 60 * 60 * 1 _000 ,
now,
});
try {
const first = boundedStore.createSession({
sessionId: "first" ,
sessionKey: "acp:first" ,
cwd: "/tmp" ,
});
advance(100 );
const second = boundedStore.createSession({
sessionId: "second" ,
sessionKey: "acp:second" ,
cwd: "/tmp" ,
});
const controller = new AbortController();
boundedStore.setActiveRun(second.sessionId, "run-2" , controller);
advance(100 );
const third = boundedStore.createSession({
sessionId: "third" ,
sessionKey: "acp:third" ,
cwd: "/tmp" ,
});
expect(third.sessionId).toBe("third" );
expect(boundedStore.getSession(first.sessionId)).toBeUndefined();
expect(boundedStore.getSession(second.sessionId)).toBeDefined();
} finally {
boundedStore.clearAllSessionsForTest();
}
});
it("rejects when full and no session is evictable" , () => {
const boundedStore = createInMemorySessionStore({
maxSessions: 1 ,
idleTtlMs: 24 * 60 * 60 * 1 _000 ,
now,
});
try {
const only = boundedStore.createSession({
sessionId: "only" ,
sessionKey: "acp:only" ,
cwd: "/tmp" ,
});
boundedStore.setActiveRun(only.sessionId, "run-only" , new AbortController());
expect(() =>
boundedStore.createSession({
sessionId: "next" ,
sessionKey: "acp:next" ,
cwd: "/tmp" ,
}),
).toThrow(/session limit reached/i);
} finally {
boundedStore.clearAllSessionsForTest();
}
});
});
Messung V0.5 in Prozent C=99 H=97 G=97
¤ Dauer der Verarbeitung: 0.10 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland