107 lines
3.6 KiB
TypeScript
107 lines
3.6 KiB
TypeScript
import { describe, expect, spyOn, test } from "bun:test";
|
|
import { runMaintenance } from "../../command/maintenance";
|
|
import type { ApiRequestInit } from "../../lib/api";
|
|
|
|
describe("maintenance command", () => {
|
|
test("first call reads status and asks for confirmation without mutation", async () => {
|
|
const calls: string[] = [];
|
|
const output = spyOn(console, "log").mockImplementation(() => {});
|
|
try {
|
|
await runMaintenance(
|
|
"a.example.com",
|
|
async <T>(path: string) => {
|
|
calls.push(path);
|
|
return { host: "a.example.com", enabled: false, hosts: [] } as T;
|
|
},
|
|
async () => false,
|
|
);
|
|
expect(calls).toEqual(["/maintenance/a.example.com"]);
|
|
expect(output).toHaveBeenCalledWith(
|
|
expect.stringContaining("currently \x1b[32mOFF\x1b[0m"),
|
|
);
|
|
} finally {
|
|
output.mockRestore();
|
|
}
|
|
});
|
|
|
|
test("confirmed call posts an idempotent desired state and prints result", async () => {
|
|
const calls: Array<{
|
|
path: string;
|
|
init?: { method?: string; json?: unknown };
|
|
}> = [];
|
|
const output = spyOn(console, "log").mockImplementation(() => {});
|
|
try {
|
|
await runMaintenance(
|
|
"a.example.com",
|
|
async <T>(path: string, init?: ApiRequestInit) => {
|
|
calls.push({ path, init });
|
|
return (
|
|
calls.length === 1
|
|
? { host: "a.example.com", enabled: false, hosts: [] }
|
|
: {
|
|
host: "a.example.com",
|
|
enabled: true,
|
|
hosts: ["a.example.com"],
|
|
}
|
|
) as T;
|
|
},
|
|
async () => true,
|
|
);
|
|
expect(calls).toEqual([
|
|
{ path: "/maintenance/a.example.com", init: undefined },
|
|
{
|
|
path: "/maintenance/a.example.com",
|
|
init: { method: "POST", json: { enabled: true } },
|
|
},
|
|
]);
|
|
expect(output).toHaveBeenCalledWith(
|
|
"a.example.com maintenance is now \x1b[31mON\x1b[0m",
|
|
);
|
|
} finally {
|
|
output.mockRestore();
|
|
}
|
|
});
|
|
|
|
test("wildcard host requires a second call before posting the normalized host", async () => {
|
|
const calls: Array<{ path: string; init?: ApiRequestInit }> = [];
|
|
const confirmations: string[] = [];
|
|
const output = spyOn(console, "log").mockImplementation(() => {});
|
|
try {
|
|
const request = async <T>(path: string, init?: ApiRequestInit): Promise<T> => {
|
|
calls.push({ path, init });
|
|
return {
|
|
host: "*.example.com",
|
|
enabled: init?.method === "POST",
|
|
hosts: init?.method === "POST" ? ["*.example.com"] : [],
|
|
} as T;
|
|
};
|
|
const confirm = async (host: string) => {
|
|
confirmations.push(host);
|
|
return confirmations.length === 2;
|
|
};
|
|
|
|
await runMaintenance("*.EXAMPLE.COM.", request, confirm);
|
|
expect(calls).toEqual([{ path: "/maintenance/*.EXAMPLE.COM.", init: undefined }]);
|
|
expect(output).toHaveBeenCalledWith(
|
|
expect.stringContaining("*.example.com maintenance is currently"),
|
|
);
|
|
|
|
await runMaintenance("*.EXAMPLE.COM.", request, confirm);
|
|
expect(confirmations).toEqual(["*.example.com", "*.example.com"]);
|
|
expect(calls).toEqual([
|
|
{ path: "/maintenance/*.EXAMPLE.COM.", init: undefined },
|
|
{ path: "/maintenance/*.EXAMPLE.COM.", init: undefined },
|
|
{
|
|
path: "/maintenance/*.example.com",
|
|
init: { method: "POST", json: { enabled: true } },
|
|
},
|
|
]);
|
|
expect(output).toHaveBeenCalledWith(
|
|
"*.example.com maintenance is now \x1b[31mON\x1b[0m",
|
|
);
|
|
} finally {
|
|
output.mockRestore();
|
|
}
|
|
});
|
|
});
|