142 lines
3.8 KiB
TypeScript
142 lines
3.8 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { getDatabaseCredentials } from "../../command/db";
|
|
import { runDown } from "../../command/down";
|
|
import { runPs } from "../../command/ps";
|
|
import { runRestart } from "../../command/restart";
|
|
import { runRollback } from "../../command/rollback";
|
|
import { getRemoteS3Credentials } from "../../command/s3";
|
|
import { runStop } from "../../command/stop";
|
|
import type { ApiRequestInit } from "../../lib/api";
|
|
|
|
type Call = { path: string; init?: ApiRequestInit };
|
|
|
|
function requestReturning<T>(result: T, calls: Call[]) {
|
|
return async <R>(path: string, init?: ApiRequestInit): Promise<R> => {
|
|
calls.push({ path, init });
|
|
return result as unknown as R;
|
|
};
|
|
}
|
|
|
|
describe("workspace API command runners", () => {
|
|
test("ps requests structured status and renders it locally", async () => {
|
|
const calls: Call[] = [];
|
|
const output = await runPs(
|
|
"shop/demo",
|
|
true,
|
|
requestReturning(
|
|
[
|
|
{
|
|
namespace: "shop-demo",
|
|
roots: [
|
|
{
|
|
id: "Deployment/web",
|
|
status: { label: "1/1", level: "good" as const },
|
|
children: [],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
calls,
|
|
),
|
|
);
|
|
|
|
expect(calls).toEqual([
|
|
{
|
|
path: "/workspaces/shop%2Fdemo/status?includeIdle=true",
|
|
init: undefined,
|
|
},
|
|
]);
|
|
expect(output).toContain("Deployment/web");
|
|
expect(output).toContain("\u001b[42m");
|
|
});
|
|
|
|
test("stop and restart use lifecycle actions with optional targeting", async () => {
|
|
const calls: Call[] = [];
|
|
const request = requestReturning({ deployments: ["web"] }, calls);
|
|
|
|
await runStop("shop", request);
|
|
await runRestart("shop", undefined, request);
|
|
await runRestart("shop", "worker", request);
|
|
|
|
expect(calls).toEqual([
|
|
{
|
|
path: "/workspaces/shop/lifecycle",
|
|
init: { method: "POST", json: { action: "stop" } },
|
|
},
|
|
{
|
|
path: "/workspaces/shop/lifecycle",
|
|
init: { method: "POST", json: { action: "restart" } },
|
|
},
|
|
{
|
|
path: "/workspaces/shop/lifecycle",
|
|
init: {
|
|
method: "POST",
|
|
json: { action: "restart", services: ["worker"] },
|
|
},
|
|
},
|
|
]);
|
|
});
|
|
|
|
test("rollback and down delegate complete server-side operations", async () => {
|
|
const calls: Call[] = [];
|
|
await runRollback(
|
|
"shop",
|
|
"web",
|
|
45_000,
|
|
requestReturning({ deployments: ["web"] }, calls),
|
|
);
|
|
await runDown(
|
|
"shop",
|
|
true,
|
|
requestReturning({ full: true, retained: [], delete: [] }, calls),
|
|
);
|
|
|
|
expect(calls).toEqual([
|
|
{
|
|
path: "/workspaces/shop/rollback",
|
|
init: {
|
|
method: "POST",
|
|
json: { services: ["web"], timeoutMs: 45_000 },
|
|
},
|
|
},
|
|
{
|
|
path: "/workspaces/shop/down",
|
|
init: { method: "POST", json: { full: true } },
|
|
},
|
|
]);
|
|
});
|
|
|
|
test("database and S3 credential requests send resolved local claims", async () => {
|
|
const calls: Call[] = [];
|
|
const databaseClaim = {
|
|
service: "web",
|
|
username: "app",
|
|
database: "app",
|
|
secretName: "postgres-app",
|
|
};
|
|
const s3Claim = { service: "web", key: "assets", bucket: "assets" };
|
|
|
|
await getDatabaseCredentials(
|
|
"shop",
|
|
databaseClaim,
|
|
requestReturning({ username: "app", password: "secret" }, calls),
|
|
);
|
|
await getRemoteS3Credentials(
|
|
"shop",
|
|
s3Claim,
|
|
requestReturning({ AWS_ACCESS_KEY_ID: "key" }, calls),
|
|
);
|
|
|
|
expect(calls).toEqual([
|
|
{
|
|
path: "/workspaces/shop/databases/credentials",
|
|
init: { method: "POST", json: { claim: databaseClaim } },
|
|
},
|
|
{
|
|
path: "/workspaces/shop/storage/credentials",
|
|
init: { method: "POST", json: { claim: s3Claim } },
|
|
},
|
|
]);
|
|
});
|
|
});
|