electron/cua-restart.test.mjs
Rama main · réplica de lectura del repositorio original.
import { afterEach, describe, expect, it, vi } from "vitest";
import { createHelperRestarts, followLinuxConnection, HELPER_KEEPS_CRASHING, HELPER_RESTARTING, RESTART_WAITS_MS } from "./cua-restart.mjs";
afterEach(() => vi.useRealTimers());
function restarts({ back = () => true } = {}) {
vi.useFakeTimers();
const reports = [];
const calls = [];
const keeper = createHelperRestarts({
restart: async () => { calls.push(Date.now()); return back(calls.length); },
report: (reason) => reports.push(reason),
});
return { keeper, reports, calls };
}
describe("restarting a helper that dies", () => {
it("says it is restarting at once and restarts after the first wait", async () => {
const { keeper, reports, calls } = restarts();
keeper.started();
keeper.exited("code 1");
expect(reports).toEqual([HELPER_RESTARTING]);
expect(calls).toHaveLength(0);
await vi.advanceTimersByTimeAsync(RESTART_WAITS_MS[0] - 1);
expect(calls).toHaveLength(0);
await vi.advanceTimersByTimeAsync(1);
expect(calls).toHaveLength(1);
});
it("waits longer each time, then stops and says so when it keeps dying", async () => {
const { keeper, reports, calls } = restarts();
keeper.started();
for (const wait of RESTART_WAITS_MS) {
keeper.exited("crash");
await vi.advanceTimersByTimeAsync(wait);
}
expect(calls).toHaveLength(RESTART_WAITS_MS.length);
keeper.exited("crash");
await vi.advanceTimersByTimeAsync(600_000);
expect(calls).toHaveLength(RESTART_WAITS_MS.length);
expect(reports.at(-1)).toBe(HELPER_KEEPS_CRASHING);
});
it("keeps trying while a restart fails, within the same bound", async () => {
const { keeper, reports, calls } = restarts({ back: () => false });
keeper.exited("crash");
await vi.advanceTimersByTimeAsync(600_000);
expect(calls).toHaveLength(RESTART_WAITS_MS.length);
expect(reports.at(-1)).toBe(HELPER_KEEPS_CRASHING);
});
it("starts a new count after the helper has run for a while", async () => {
const { keeper, reports, calls } = restarts();
keeper.started();
keeper.exited("crash");
await vi.advanceTimersByTimeAsync(RESTART_WAITS_MS[0]);
keeper.exited("crash");
await vi.advanceTimersByTimeAsync(RESTART_WAITS_MS[1]);
await vi.advanceTimersByTimeAsync(120_000);
keeper.exited("crash");
await vi.advanceTimersByTimeAsync(RESTART_WAITS_MS[0]);
expect(calls).toHaveLength(3);
expect(reports.every((reason) => reason === HELPER_RESTARTING)).toBe(true);
});
it("stops and leaves the published reason when only the person can fix it", async () => {
const { keeper, reports, calls } = restarts({ back: () => "needs-person" });
keeper.exited("crash");
await vi.advanceTimersByTimeAsync(600_000);
expect(calls).toHaveLength(1);
expect(reports).toEqual([HELPER_RESTARTING]);
});
it("a person's restart cancels the waiting restart and forgets the count", async () => {
const { keeper, calls } = restarts();
keeper.exited("crash");
keeper.reset();
await vi.advanceTimersByTimeAsync(600_000);
expect(calls).toHaveLength(0);
});
});
describe("following the Linux runtime", () => {
const spies = () => ({ started: vi.fn(), exited: vi.fn() });
it("counts a died daemon as an exit and a ready one as started", () => {
const restarts = spies();
followLinuxConnection(restarts, { status: "error", reasonCode: "daemon-exited", exitCode: 139 });
expect(restarts.exited).toHaveBeenCalledWith("exit 139");
followLinuxConnection(restarts, { status: "ready" });
expect(restarts.started).toHaveBeenCalledOnce();
});
it("ignores every other change, such as the person turning it off", () => {
const restarts = spies();
followLinuxConnection(restarts, { status: "disabled", reasonCode: "opt-in-required" });
followLinuxConnection(restarts, { status: "error", reasonCode: "wayland-health-lost" });
followLinuxConnection(restarts, null);
expect(restarts.started).not.toHaveBeenCalled();
expect(restarts.exited).not.toHaveBeenCalled();
});
});