401 unmodified lines
Expand all
let originalExitCode: typeof process.exitCode;
async function performUpdateAndRunCoordinator(originActiveSessionId?: string): Promise<void> {
await handlePackageCommand(["update", "--self", "--daemon-socket", mockState.socketPath]);
// The coordinator is a new process. Its first hello observes the same
// predecessor; only the later startup hello belongs to the successor.
mockState.helloCount = 0;
const restartDirectory = join(agentDir, "update-restarts");
mkdirSync(restartDirectory, { recursive: true });
mockState.lastCoordinatorStatus = await runDaemonUpdateRestartCoordinator({
socketPath: mockState.socketPath,
193 unmodified lines
Expand all
errorSpy.mockRestore();
}
});
it("does not prepare or stop the daemon when the package update fails", async () => {
it("freezes the daemon before updating and recovers it when the package command fails", async () => {
mockState.spawnExitCodes = [23];
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
try {
await expect(handlePackageCommand(["update", "--self"])).resolves.toBe(true);
await expect(
handlePackageCommand(["update", "--self", "--daemon-socket", mockState.socketPath]),
).resolves.toBe(true);
expect(process.exitCode).toBe(1);
expect(mockState.calls).toContain("probe-daemon");
expect(mockState.calls.some((call) => call === "daemon-request:prepare_update_restart")).toBe(false);
expect(mockState.calls.some((call) => call === "shutdown-daemon")).toBe(false);
const prepareIndex = mockState.calls.indexOf("daemon-request:prepare_update_restart");
const spawnIndex = mockState.calls.findIndex((call) => call.startsWith("spawn:npm "));
const recoveryIndex = mockState.calls.indexOf(`launch-coordinator:${mockState.socketPath}`);
expect(prepareIndex).toBeGreaterThanOrEqual(0);
expect(spawnIndex).toBeGreaterThan(prepareIndex);
expect(recoveryIndex).toBeGreaterThan(spawnIndex);
} finally {
errorSpy.mockRestore();
logSpy.mockRestore();
}
252 unmodified lines
Expand all
errorSpy.mockRestore();
}
});
it("restarts the daemon only after the package update succeeds", async () => {
it("freezes daemon workers before package mutation and restarts them afterward", async () => {
useFixedOwnerHello();
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
const logSpy = vi.spyOn(console, "log").mockImplementation(() => {});
expect(process.exitCode).toBeUndefined();
const spawnIndex = mockState.calls.findIndex((call) => call.startsWith("spawn:npm "));
const launchIndex = mockState.calls.indexOf(`launch-coordinator:${mockState.socketPath}`);
const fenceIndex = mockState.calls.indexOf("persist-daemon-startup-fence");
const prepareIndex = mockState.calls.indexOf("daemon-request:prepare_update_restart");
const prepareIndices = mockState.calls.flatMap((call, index) =>
call === "daemon-request:prepare_update_restart" ? [index] : [],
);
const admissionIndex = mockState.calls.indexOf("acquire-daemon-shutdown-admission");
const shutdownIndex = mockState.calls.indexOf("shutdown-daemon");
const startupFenceIndex = mockState.calls.indexOf("wait-daemon-startup-fence");
const releaseAdmissionIndex = mockState.calls.indexOf("release-daemon-shutdown-admission");
const ensureIndex = mockState.calls.indexOf("ensure-daemon");
expect(spawnIndex).toBeGreaterThanOrEqual(0);
expect(prepareIndices[0]).toBeGreaterThanOrEqual(0);
expect(fenceIndex).toBeGreaterThan(prepareIndices[0]!);
expect(spawnIndex).toBeGreaterThan(fenceIndex);
expect(launchIndex).toBeGreaterThan(spawnIndex);
expect(admissionIndex).toBeGreaterThan(launchIndex);
expect(prepareIndex).toBeGreaterThan(admissionIndex);
expect(fenceIndex).toBeGreaterThan(prepareIndex);
expect(shutdownIndex).toBeGreaterThan(fenceIndex);
expect(prepareIndices.at(-1)).toBeGreaterThan(admissionIndex);
expect(shutdownIndex).toBeGreaterThan(admissionIndex);
expect(startupFenceIndex).toBeGreaterThan(shutdownIndex);
expect(releaseAdmissionIndex).toBeGreaterThan(startupFenceIndex);
expect(ensureIndex).toBeGreaterThan(releaseAdmissionIndex);
expect(ensureIndex).toBeGreaterThan(shutdownIndex);
expect(statSync(join(agentDir, "update-restarts", "test-status.json")).mode & 0o777).toBe(0o600);
} finally {
errorSpy.mockRestore();
logSpy.mockRestore();
531 unmodified lines
Expand all