Files
openclaw/src/process/supervisor/registry.test.ts
T
Onur cd44a0d01e fix: codex and similar processes keep dying on pty, solved by refactoring process spawning (#14257)
* exec: clean up PTY resources on timeout and exit

* cli: harden resume cleanup and watchdog stalled runs

* cli: productionize PTY and resume reliability paths

* docs: add PTY process supervision architecture plan

* docs: rewrite PTY supervision plan as pre-rewrite baseline

* docs: switch PTY supervision plan to one-go execution

* docs: add one-line root cause to PTY supervision plan

* docs: add OS contracts and test matrix to PTY supervision plan

* docs: define process-supervisor package placement and scope

* docs: tie supervisor plan to existing CI lanes

* docs: place PTY supervisor plan under src/process

* refactor(process): route exec and cli runs through supervisor

* docs(process): refresh PTY supervision plan

* wip

* fix(process): harden supervisor timeout and PTY termination

* fix(process): harden supervisor adapters env and wait handling

* ci: avoid failing formal conformance on comment permissions

* test(ui): fix cron request mock argument typing

* fix(ui): remove leftover conflict marker

* fix: supervise PTY processes (#14257) (openclaw#14257) (thanks @onutc)
2026-02-16 02:32:05 +01:00

84 lines
2.4 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { createRunRegistry } from "./registry.js";
describe("process supervisor run registry", () => {
it("finalize is idempotent and preserves first terminal metadata", () => {
const registry = createRunRegistry();
registry.add({
runId: "r1",
sessionId: "s1",
backendId: "b1",
state: "running",
startedAtMs: 1,
lastOutputAtMs: 1,
createdAtMs: 1,
updatedAtMs: 1,
});
const first = registry.finalize("r1", {
reason: "overall-timeout",
exitCode: null,
exitSignal: "SIGKILL",
});
const second = registry.finalize("r1", {
reason: "manual-cancel",
exitCode: 0,
exitSignal: null,
});
expect(first).not.toBeNull();
expect(first?.firstFinalize).toBe(true);
expect(first?.record.terminationReason).toBe("overall-timeout");
expect(first?.record.exitCode).toBeNull();
expect(first?.record.exitSignal).toBe("SIGKILL");
expect(second).not.toBeNull();
expect(second?.firstFinalize).toBe(false);
expect(second?.record.terminationReason).toBe("overall-timeout");
expect(second?.record.exitCode).toBeNull();
expect(second?.record.exitSignal).toBe("SIGKILL");
});
it("prunes oldest exited records once retention cap is exceeded", () => {
const registry = createRunRegistry({ maxExitedRecords: 2 });
registry.add({
runId: "r1",
sessionId: "s1",
backendId: "b1",
state: "running",
startedAtMs: 1,
lastOutputAtMs: 1,
createdAtMs: 1,
updatedAtMs: 1,
});
registry.add({
runId: "r2",
sessionId: "s2",
backendId: "b1",
state: "running",
startedAtMs: 2,
lastOutputAtMs: 2,
createdAtMs: 2,
updatedAtMs: 2,
});
registry.add({
runId: "r3",
sessionId: "s3",
backendId: "b1",
state: "running",
startedAtMs: 3,
lastOutputAtMs: 3,
createdAtMs: 3,
updatedAtMs: 3,
});
registry.finalize("r1", { reason: "exit", exitCode: 0, exitSignal: null });
registry.finalize("r2", { reason: "exit", exitCode: 0, exitSignal: null });
registry.finalize("r3", { reason: "exit", exitCode: 0, exitSignal: null });
expect(registry.get("r1")).toBeUndefined();
expect(registry.get("r2")?.state).toBe("exited");
expect(registry.get("r3")?.state).toBe("exited");
});
});