import { describe, expect, test } from "bun:test"; import type { ApiRequestInit } from "../../lib/api"; import { KuberApiError } from "../../lib/api"; import type { ApiRequester } from "../../lib/build"; import { ensureWorkspace, reconcileResources, workspaceAdoptionRoute, } from "../../command/up"; import { workspaceManifestDigest } from "../../lib/workspace"; const manifest = { version: 1 as const, files: [] }; const snapshot = { manifest, digest: workspaceManifestDigest(manifest), blobs: [], }; describe("up API pipeline", () => { test("creates workspace metadata without embedding source blobs", async () => { const calls: Array<{ path: string; init?: ApiRequestInit }> = []; const request: ApiRequester = async ( path: string, init?: ApiRequestInit, ) => { calls.push({ path, init }); if (!init) throw new KuberApiError("missing", 404); return { metadata: { name: "shop", uid: "uid", resourceVersion: "1" }, } as T; }; await ensureWorkspace( "shop", { services: { web: { image: "nginx" } } }, snapshot, request, ); expect(calls.map(({ path }) => path)).toEqual([ "/workspaces/shop", "/workspaces", ]); const body = calls[1]!.init?.json as Record; expect(body).toMatchObject({ id: "shop", source: { uri: `cas://${snapshot.digest}`, digest: snapshot.digest }, }); expect(JSON.stringify(body)).not.toContain('"blob"'); expect(JSON.stringify(body)).not.toContain('"files"'); }); test("updates workspace metadata with the current resource-version ETag", async () => { const calls: Array<{ path: string; init?: ApiRequestInit }> = []; const request: ApiRequester = async ( path: string, init?: ApiRequestInit, ) => { calls.push({ path, init }); return { metadata: { name: "shop", uid: "uid", resourceVersion: init ? "8" : "7", }, } as T; }; await ensureWorkspace("shop", { services: {} }, snapshot, request); expect(calls[1]?.init?.method).toBe("PUT"); expect(new Headers(calls[1]?.init?.headers).get("if-match")).toBe('"7"'); }); test("plans, applies, runs the hook, waits, then deletes stale identities", async () => { const order: string[] = []; const desired = [ { apiVersion: "apps/v1", kind: "Deployment", metadata: { name: "web" } }, ]; const stale = [ { apiVersion: "v1", kind: "Secret", name: "old", uid: "secret-uid", workspaceUid: "workspace-uid", }, ]; const request: ApiRequester = async (path: string) => { order.push(path.split("/").at(-1)!); if (path.endsWith("/plan")) return { desired, stale } as T; return {} as T; }; await reconcileResources( "shop", desired, 42_000, () => { order.push("hook"); }, request, ); expect(order).toEqual(["plan", "apply", "hook", "wait", "delete"]); }); test("fails closed with the precise missing adoption route", async () => { const request: ApiRequester = async (path: string) => { if (path.endsWith("/plan")) throw new Error( "Namespace shop is external; refusing workspace mutation", ); return {} as T; }; await expect( reconcileResources("shop", [], 1, undefined, request), ).rejects.toThrow(`POST ${workspaceAdoptionRoute("shop")}`); }); });