Some checks failed
Release Workflow / determine-release-type (push) Has been cancelled
Release Workflow / checks (push) Has been cancelled
Release Workflow / e2e-tests (push) Has been cancelled
Release Workflow / build-images (push) Has been cancelled
Release Workflow / publish-release (push) Has been cancelled
Release Workflow / request-docs-version-update (push) Has been cancelled
97 lines
2.4 KiB
TypeScript
97 lines
2.4 KiB
TypeScript
import { afterEach, expect, test, vi } from "vitest";
|
|
import { Effect } from "effect";
|
|
import waitForExpect from "wait-for-expect";
|
|
import { fromPartial } from "@total-typescript/shoehorn";
|
|
import { createControllerMessage, parseAgentMessage } from "@zerobyte/contracts/agent-protocol";
|
|
import * as resticServer from "@zerobyte/core/restic/server";
|
|
import { createControllerSession } from "../controller-session";
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
test("emits backup.failed when a backup command hits a restic error", async () => {
|
|
vi.spyOn(resticServer, "createRestic").mockReturnValue(
|
|
fromPartial({
|
|
backup: () => Effect.fail("source path missing"),
|
|
}),
|
|
);
|
|
|
|
const outboundMessages: string[] = [];
|
|
const session = createControllerSession(
|
|
fromPartial({
|
|
send: (message: string) => {
|
|
outboundMessages.push(message);
|
|
},
|
|
}),
|
|
);
|
|
|
|
try {
|
|
session.onOpen();
|
|
session.onMessage(
|
|
createControllerMessage("backup.run", {
|
|
jobId: "job-1",
|
|
scheduleId: "schedule-1",
|
|
organizationId: "org-1",
|
|
sourcePath: "/tmp/missing-source",
|
|
repositoryConfig: {
|
|
backend: "local",
|
|
path: "/tmp/test-repository",
|
|
},
|
|
options: {},
|
|
runtime: {
|
|
password: "password",
|
|
cacheDir: "/tmp/restic-cache",
|
|
passFile: "/tmp/restic-pass",
|
|
defaultExcludes: [],
|
|
rcloneConfigFile: "/root/.config/rclone/rclone.conf",
|
|
},
|
|
webhooks: { pre: null, post: null },
|
|
webhookAllowedOrigins: [],
|
|
webhookTimeoutMs: 60_000,
|
|
}),
|
|
);
|
|
|
|
await waitForExpect(() => {
|
|
const failedMessage = outboundMessages
|
|
.map((message) => parseAgentMessage(message))
|
|
.find((message) => message?.success && message.data.type === "backup.failed");
|
|
|
|
expect(failedMessage?.success).toBe(true);
|
|
if (!failedMessage || !failedMessage.success || failedMessage.data.type !== "backup.failed") {
|
|
return;
|
|
}
|
|
|
|
expect(failedMessage.data.payload).toEqual({
|
|
jobId: "job-1",
|
|
scheduleId: "schedule-1",
|
|
error: "source path missing",
|
|
errorDetails: "source path missing",
|
|
});
|
|
});
|
|
} finally {
|
|
session.close();
|
|
}
|
|
});
|
|
|
|
test("closes the websocket when an outbound send throws", async () => {
|
|
const close = vi.fn(() => undefined);
|
|
const session = createControllerSession(
|
|
fromPartial({
|
|
send: () => {
|
|
throw new Error("socket write failed");
|
|
},
|
|
close,
|
|
}),
|
|
);
|
|
|
|
try {
|
|
session.onOpen();
|
|
|
|
await waitForExpect(() => {
|
|
expect(close).toHaveBeenCalledTimes(1);
|
|
});
|
|
} finally {
|
|
session.close();
|
|
}
|
|
});
|