Files
openclaw/src/infra/pairing-state.test.ts
Peter Steinberger 8604da8e16 Reapply "refactor: move runtime state to SQLite"
This reverts commit 694ca50e97.
2026-05-27 13:27:43 +01:00

133 lines
3.9 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { withTempDir } from "../test-utils/temp-dir.js";
import {
pruneExpiredPending,
readPairingStateRecord,
reconcilePendingPairingRequests,
writePairingStateRecord,
} from "./pairing-state.js";
describe("pairing state helpers", () => {
it("prunes only entries older than the ttl", () => {
const pendingById = {
stale: { ts: 10, requestId: "stale" },
edge: { ts: 50, requestId: "edge" },
fresh: { ts: 70, requestId: "fresh" },
};
pruneExpiredPending(pendingById, 100, 50);
expect(pendingById).toEqual({
edge: { ts: 50, requestId: "edge" },
fresh: { ts: 70, requestId: "fresh" },
});
});
it("refreshes a single matching pending request in place", async () => {
const persist = vi.fn(async () => undefined);
const existing = { requestId: "req-1", deviceId: "device-1", ts: 1, version: 1 };
const pendingById = { "req-1": existing };
await expect(
reconcilePendingPairingRequests({
pendingById,
existing: [existing],
incoming: { version: 2 },
canRefreshSingle: () => true,
refreshSingle: (pending, incoming) => ({ ...pending, version: incoming.version, ts: 2 }),
buildReplacement: vi.fn(() => ({ requestId: "req-2", deviceId: "device-1", ts: 2 })),
persist,
}),
).resolves.toEqual({
status: "pending",
request: { requestId: "req-1", deviceId: "device-1", ts: 2, version: 2 },
created: false,
});
expect(persist).toHaveBeenCalledOnce();
});
it("replaces existing pending requests with one merged request", async () => {
const persist = vi.fn(async () => undefined);
const pendingById = {
"req-1": { requestId: "req-1", deviceId: "device-2", ts: 1 },
"req-2": { requestId: "req-2", deviceId: "device-2", ts: 2 },
};
await expect(
reconcilePendingPairingRequests({
pendingById,
existing: Object.values(pendingById).toSorted((left, right) => right.ts - left.ts),
incoming: { deviceId: "device-2" },
canRefreshSingle: () => false,
refreshSingle: (pending) => pending,
buildReplacement: vi.fn(() => ({
requestId: "req-3",
deviceId: "device-2",
ts: 3,
isRepair: true,
})),
persist,
}),
).resolves.toEqual({
status: "pending",
request: { requestId: "req-3", deviceId: "device-2", ts: 3, isRepair: true },
created: true,
});
expect(persist).toHaveBeenCalledOnce();
expect(pendingById).toEqual({
"req-3": { requestId: "req-3", deviceId: "device-2", ts: 3, isRepair: true },
});
});
it("prunes stale sqlite rows while retaining current pairing rows", async () => {
await withTempDir("openclaw-pairing-state-", async (baseDir) => {
writePairingStateRecord({
baseDir,
subdir: "devices",
key: "pending",
value: {
"req-stale": {
requestId: "req-stale",
deviceId: "device-stale",
publicKey: "stale-key",
ts: 1,
},
"req-retained": {
requestId: "req-retained",
deviceId: "device-retained",
publicKey: "retained-key",
ts: 2,
},
},
});
writePairingStateRecord({
baseDir,
subdir: "devices",
key: "pending",
value: {
"req-retained": {
requestId: "req-retained",
deviceId: "device-retained",
publicKey: "retained-key-2",
ts: 3,
},
},
});
expect(
readPairingStateRecord<{ publicKey: string }>({
baseDir,
subdir: "devices",
key: "pending",
}),
).toEqual({
"req-retained": expect.objectContaining({
publicKey: "retained-key-2",
ts: 3,
}),
});
});
});
});