import fs from "node:fs/promises" ;
import os from "node:os" ;
import path from "node:path" ;
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest" ;
import { captureEnv } from "../test-utils/env.js" ;
const note = vi.hoisted(() => vi.fn());
vi.mock("../terminal/note.js" , () => ({
note,
}));
import { noteSessionLockHealth } from "./doctor-session-locks.js" ;
describe("noteSessionLockHealth" , () => {
let root: string;
let envSnapshot: ReturnType<typeof captureEnv>;
beforeEach(async () => {
note.mockClear();
envSnapshot = captureEnv(["OPENCLAW_STATE_DIR" ]);
root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-doctor-locks-" ));
process.env.OPENCLAW_STATE_DIR = root;
});
afterEach(async () => {
envSnapshot.restore();
await fs.rm(root, { recursive: true , force: true });
});
it("reports existing lock files with pid status and age" , async () => {
const sessionsDir = path.join(root, "agents" , "main" , "sessions" );
await fs.mkdir(sessionsDir, { recursive: true });
const lockPath = path.join(sessionsDir, "active.jsonl.lock" );
await fs.writeFile(
lockPath,
JSON.stringify({ pid: process.pid, createdAt: new Date(Date.now() - 1500 ).toISOString() }),
"utf8" ,
);
await noteSessionLockHealth({ shouldRepair: false , staleMs: 60 _000 });
expect(note).toHaveBeenCalledTimes(1 );
const [message, title] = note.mock.calls[0 ] as [string, string];
expect(title).toBe("Session locks" );
expect(message).toContain("Found 1 session lock file" );
expect(message).toContain(`pid=${process.pid} (alive)`);
expect(message).toContain("stale=no" );
await expect(fs.access(lockPath)).resolves.toBeUndefined();
});
it("removes stale locks in repair mode" , async () => {
const sessionsDir = path.join(root, "agents" , "main" , "sessions" );
await fs.mkdir(sessionsDir, { recursive: true });
const staleLock = path.join(sessionsDir, "stale.jsonl.lock" );
const freshLock = path.join(sessionsDir, "fresh.jsonl.lock" );
await fs.writeFile(
staleLock,
JSON.stringify({ pid: -1 , createdAt: new Date(Date.now() - 120 _000 ).toISOString() }),
"utf8" ,
);
await fs.writeFile(
freshLock,
JSON.stringify({ pid: process.pid, createdAt: new Date().toISOString() }),
"utf8" ,
);
await noteSessionLockHealth({ shouldRepair: true , staleMs: 30 _000 });
expect(note).toHaveBeenCalledTimes(1 );
const [message] = note.mock.calls[0 ] as [string, string];
expect(message).toContain("[removed]" );
expect(message).toContain("Removed 1 stale session lock file" );
await expect(fs.access(staleLock)).rejects.toThrow();
await expect(fs.access(freshLock)).resolves.toBeUndefined();
});
});
Messung V0.5 in Prozent C=100 H=100 G=100
¤ Dauer der Verarbeitung: 0.9 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland