Files
clawdbot/src/infra/restart-sentinel.test.ts
2026-01-08 01:30:02 +01:00

69 lines
2.1 KiB
TypeScript

import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import {
consumeRestartSentinel,
readRestartSentinel,
resolveRestartSentinelPath,
trimLogTail,
writeRestartSentinel,
} from "./restart-sentinel.js";
describe("restart sentinel", () => {
let prevStateDir: string | undefined;
let tempDir: string;
beforeEach(async () => {
prevStateDir = process.env.CLAWDBOT_STATE_DIR;
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-sentinel-"));
process.env.CLAWDBOT_STATE_DIR = tempDir;
});
afterEach(async () => {
if (prevStateDir) process.env.CLAWDBOT_STATE_DIR = prevStateDir;
else delete process.env.CLAWDBOT_STATE_DIR;
await fs.rm(tempDir, { recursive: true, force: true });
});
it("writes and consumes a sentinel", async () => {
const payload = {
kind: "update" as const,
status: "ok" as const,
ts: Date.now(),
sessionKey: "agent:main:whatsapp:dm:+15555550123",
stats: { mode: "git" },
};
const filePath = await writeRestartSentinel(payload);
expect(filePath).toBe(resolveRestartSentinelPath());
const read = await readRestartSentinel();
expect(read?.payload.kind).toBe("update");
const consumed = await consumeRestartSentinel();
expect(consumed?.payload.sessionKey).toBe(payload.sessionKey);
const empty = await readRestartSentinel();
expect(empty).toBeNull();
});
it("drops invalid sentinel payloads", async () => {
const filePath = resolveRestartSentinelPath();
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, "not-json", "utf-8");
const read = await readRestartSentinel();
expect(read).toBeNull();
await expect(fs.stat(filePath)).rejects.toThrow();
});
it("trims log tails", () => {
const text = "a".repeat(9000);
const trimmed = trimLogTail(text, 8000);
expect(trimmed?.length).toBeLessThanOrEqual(8001);
expect(trimmed?.startsWith("…")).toBe(true);
});
});