105 lines
2.9 KiB
JavaScript
105 lines
2.9 KiB
JavaScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
import {
|
|
resolveHeartbeatProjectsFromSnapshot,
|
|
runHeartbeatProjectDiscoveryWithTimeout,
|
|
storeHeartbeatProjectsSnapshot,
|
|
} from "./heartbeat-project-snapshot.mjs";
|
|
|
|
test("active master task heartbeat reuses the last discovered project snapshot", () => {
|
|
const runtime = {
|
|
masterTaskBusy: true,
|
|
lastHeartbeatProjectsSnapshot: {
|
|
projects: ["test"],
|
|
projectCandidates: [{ threadId: "thread-test", folderName: "test" }],
|
|
guiConnected: true,
|
|
capturedAt: "2026-06-07T10:39:00.000Z",
|
|
},
|
|
};
|
|
|
|
const result = resolveHeartbeatProjectsFromSnapshot({
|
|
config: {
|
|
projects: ["static"],
|
|
projectCandidates: [{ threadId: "static-thread", folderName: "static" }],
|
|
},
|
|
runtime,
|
|
});
|
|
|
|
assert.deepEqual(result, {
|
|
shouldUseSnapshot: true,
|
|
projects: ["test"],
|
|
projectCandidates: [{ threadId: "thread-test", folderName: "test" }],
|
|
guiConnected: true,
|
|
});
|
|
});
|
|
|
|
test("active master task heartbeat falls back to static projects without a snapshot", () => {
|
|
const result = resolveHeartbeatProjectsFromSnapshot({
|
|
config: {
|
|
projects: ["static"],
|
|
projectCandidates: [{ threadId: "static-thread", folderName: "static" }],
|
|
},
|
|
runtime: {
|
|
masterTaskBusy: true,
|
|
},
|
|
});
|
|
|
|
assert.deepEqual(result, {
|
|
shouldUseSnapshot: true,
|
|
projects: ["static"],
|
|
projectCandidates: [{ threadId: "static-thread", folderName: "static" }],
|
|
guiConnected: false,
|
|
});
|
|
});
|
|
|
|
test("idle heartbeat does not use the cached project snapshot", () => {
|
|
const result = resolveHeartbeatProjectsFromSnapshot({
|
|
config: {
|
|
projects: ["static"],
|
|
},
|
|
runtime: {
|
|
masterTaskBusy: false,
|
|
lastHeartbeatProjectsSnapshot: {
|
|
projects: ["cached"],
|
|
projectCandidates: [],
|
|
},
|
|
},
|
|
});
|
|
|
|
assert.equal(result.shouldUseSnapshot, false);
|
|
});
|
|
|
|
test("project snapshot stores only lightweight fields", () => {
|
|
const runtime = {};
|
|
storeHeartbeatProjectsSnapshot(runtime, {
|
|
projects: ["test"],
|
|
projectCandidates: [{ threadId: "thread-test", folderName: "test" }],
|
|
guiConnected: true,
|
|
privateField: "should-not-store",
|
|
});
|
|
|
|
assert.deepEqual(Object.keys(runtime.lastHeartbeatProjectsSnapshot).sort(), [
|
|
"capturedAt",
|
|
"guiConnected",
|
|
"projectCandidates",
|
|
"projects",
|
|
]);
|
|
assert.equal(runtime.lastHeartbeatProjectsSnapshot.privateField, undefined);
|
|
});
|
|
|
|
test("project discovery timeout falls back instead of blocking heartbeat", async () => {
|
|
const result = await runHeartbeatProjectDiscoveryWithTimeout({
|
|
timeoutMs: 10,
|
|
fallback: { projects: ["cached"], projectCandidates: [], guiConnected: false },
|
|
discover: () => new Promise(() => {}),
|
|
});
|
|
|
|
assert.equal(result.timedOut, true);
|
|
assert.deepEqual(result.value, {
|
|
projects: ["cached"],
|
|
projectCandidates: [],
|
|
guiConnected: false,
|
|
});
|
|
});
|