test.deploy/core/steps/recovery.step.test.ts
test.deploy/core/steps/recovery.step.test.ts is a file in Codebase Testing. 75 lines of code and 0 definitions.
import {
FILE_TEST_COMMAND,
MAIN_CONFIG,
NGINX_ROOT,
RELOAD_COMMAND,
REMOTE_SCRIPTS,
REMOTE_SITE_CONFIG,
REMOVE_FILE_COMMAND,
TEST_COMMAND,
} from "@banes-lab/deploy/configuration/constants/nginx.constants.ts";
import { RELOAD_FAILED, RESTORED, RESTORE_TEST_FAILED } from "@banes-lab/deploy/configuration/strings/nginx.strings.ts";
import {
backupNameOf,
managedTargets,
pullManaged,
restoreManaged,
} from "@banes-lab/deploy/core/steps/recovery.step.ts";
import { describe, expect, it, vi } from "vitest";
import { fakeJournal, fakeShell, ok } from "./shell.fixture.ts";
import type { CommandResult } from "@banes-lab/deploy/types/deployment.types.ts";
import { absolutePath } from "@ssot/paths";
vi.mock("node:fs", async (importOriginal) => ({
...(await importOriginal<Record<string, unknown>>()),
mkdirSync: vi.fn(),
}));
const MAIN = `${NGINX_ROOT}/${MAIN_CONFIG}`;
const SCRIPT = `${REMOTE_SCRIPTS}/catalog.js`;
const failing = function failing(stderr: string): CommandResult {
return { code: 1, stderr, stdout: "" };
};
describe("managedTargets", () => {
it("lists every remote file a push replaces: the main config, each script and the site", () => {
expect(managedTargets()).toStrictEqual([MAIN, SCRIPT, REMOTE_SITE_CONFIG]);
});
});
describe("backupNameOf", () => {
it("stamps each backup and keeps the backup marker before its extension", () => {
expect(backupNameOf(SCRIPT, "t")).toBe("catalog-t.backup.js");
expect(backupNameOf(MAIN, "t")).toBe("nginx-t.backup.conf");
expect(backupNameOf(REMOTE_SITE_CONFIG, "t")).toBe("banes-lab-t.backup.conf");
});
});
describe("pullManaged", () => {
it("downloads each present file and records an absent one so a restore removes it", async () => {
const shell = fakeShell((command) => (command === `${FILE_TEST_COMMAND} ${SCRIPT}` ? failing("") : ok()));
const backups = await pullManaged(shell, fakeJournal());
expect(backups.map((backup) => backup.remote)).toStrictEqual([MAIN, SCRIPT, REMOTE_SITE_CONFIG]);
expect(backups.find((backup) => backup.remote === SCRIPT)?.local).toBeNull();
expect(shell.downloads.map(([, remote]) => remote)).toStrictEqual([MAIN, REMOTE_SITE_CONFIG]);
expect(shell.downloads.every(([local]) => local.startsWith(absolutePath("app.backups")))).toBe(true);
});
});
describe("restoreManaged", () => {
const backups = [
{ local: "main.backup.conf", remote: MAIN },
{ local: null, remote: SCRIPT },
];
it("puts every file back, removes one that did not exist, then tests and reloads", async () => {
const shell = fakeShell(() => ok());
const journal = fakeJournal();
await restoreManaged(shell, journal, backups);
expect(shell.uploads[0]?.[0]).toBe("main.backup.conf");
expect(shell.commands).toContain(`${REMOVE_FILE_COMMAND} ${SCRIPT}`);
expect(shell.commands.slice(-2)).toStrictEqual([TEST_COMMAND, RELOAD_COMMAND]);
expect(journal.lines).toContain(RESTORED);
});
it("fails loudly when the restored configuration does not pass its test", async () => {
const shell = fakeShell((command) => (command === TEST_COMMAND ? failing("bad") : ok()));
await expect(restoreManaged(shell, fakeJournal(), backups)).rejects.toThrow(`${RESTORE_TEST_FAILED}bad`);
});
it("fails loudly when nginx refuses the reload", async () => {
const shell = fakeShell((command) => (command === RELOAD_COMMAND ? failing("down") : ok()));
await expect(restoreManaged(shell, fakeJournal(), backups)).rejects.toThrow(`${RELOAD_FAILED}down`);
});
});