63 lines
2.1 KiB
TypeScript
63 lines
2.1 KiB
TypeScript
|
|
import { describe, expect, it, vi } from "vitest";
|
||
|
|
import type { AcpRuntime } from "../runtime/types.js";
|
||
|
|
import type { AcpRuntimeHandle } from "../runtime/types.js";
|
||
|
|
import type { CachedRuntimeState } from "./runtime-cache.js";
|
||
|
|
import { RuntimeCache } from "./runtime-cache.js";
|
||
|
|
|
||
|
|
function mockState(sessionKey: string): CachedRuntimeState {
|
||
|
|
const runtime = {
|
||
|
|
ensureSession: vi.fn(async () => ({
|
||
|
|
sessionKey,
|
||
|
|
backend: "acpx",
|
||
|
|
runtimeSessionName: `runtime:${sessionKey}`,
|
||
|
|
})),
|
||
|
|
runTurn: vi.fn(async function* () {
|
||
|
|
yield { type: "done" as const };
|
||
|
|
}),
|
||
|
|
cancel: vi.fn(async () => {}),
|
||
|
|
close: vi.fn(async () => {}),
|
||
|
|
} as unknown as AcpRuntime;
|
||
|
|
return {
|
||
|
|
runtime,
|
||
|
|
handle: {
|
||
|
|
sessionKey,
|
||
|
|
backend: "acpx",
|
||
|
|
runtimeSessionName: `runtime:${sessionKey}`,
|
||
|
|
} as AcpRuntimeHandle,
|
||
|
|
backend: "acpx",
|
||
|
|
agent: "codex",
|
||
|
|
mode: "persistent",
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
describe("RuntimeCache", () => {
|
||
|
|
it("tracks idle candidates with touch-aware lookups", () => {
|
||
|
|
vi.useFakeTimers();
|
||
|
|
try {
|
||
|
|
const cache = new RuntimeCache();
|
||
|
|
const actor = "agent:codex:acp:s1";
|
||
|
|
cache.set(actor, mockState(actor), { now: 1_000 });
|
||
|
|
|
||
|
|
expect(cache.collectIdleCandidates({ maxIdleMs: 1_000, now: 1_999 })).toHaveLength(0);
|
||
|
|
expect(cache.collectIdleCandidates({ maxIdleMs: 1_000, now: 2_000 })).toHaveLength(1);
|
||
|
|
|
||
|
|
cache.get(actor, { now: 2_500 });
|
||
|
|
expect(cache.collectIdleCandidates({ maxIdleMs: 1_000, now: 3_200 })).toHaveLength(0);
|
||
|
|
expect(cache.collectIdleCandidates({ maxIdleMs: 1_000, now: 3_500 })).toHaveLength(1);
|
||
|
|
} finally {
|
||
|
|
vi.useRealTimers();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
it("returns snapshot entries with idle durations", () => {
|
||
|
|
const cache = new RuntimeCache();
|
||
|
|
cache.set("a", mockState("a"), { now: 10 });
|
||
|
|
cache.set("b", mockState("b"), { now: 100 });
|
||
|
|
|
||
|
|
const snapshot = cache.snapshot({ now: 1_100 });
|
||
|
|
const byActor = new Map(snapshot.map((entry) => [entry.actorKey, entry]));
|
||
|
|
expect(byActor.get("a")?.idleMs).toBe(1_090);
|
||
|
|
expect(byActor.get("b")?.idleMs).toBe(1_000);
|
||
|
|
});
|
||
|
|
});
|