import assert from "node:assert/strict"; import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import test from "node:test"; import { currentDockerPlatform, ensureKindDenReady, ensureRelease, exposeEndpointHandles, helmUpgradeArgs, kubeProfileConfig, kubeStackDown, manifestSupportsPlatform, portForwardArgs, resolveKubeImagePlan, rolloutStatusArgs, } from "../src/kind-stack.ts"; import type { KubeExec, KubeExecOptions, KubeExecResult, KubeImagePlan, KubeSpawnDetached } from "../src/kind-stack.ts"; interface ExecCall { command: string; args: string[]; options?: KubeExecOptions; } function success(stdout = ""): KubeExecResult { return { stdout, stderr: "", code: 0 }; } function createExec(handler: (call: ExecCall) => KubeExecResult): { exec: KubeExec; calls: ExecCall[] } { const calls: ExecCall[] = []; const exec: KubeExec = async (command, args, options) => { const call = { command, args: [...args], options }; calls.push(call); return handler(call); }; return { exec, calls }; } function imagePlan(mode: "published" | "local"): KubeImagePlan { return { mode, denApiRepository: mode === "local" ? "openwork-den-api" : "ghcr.io/different-ai/openwork-den-api", denWebRepository: mode === "local" ? "openwork-den-web" : "ghcr.io/different-ai/openwork-den-web", tag: mode === "local" ? "kube-lab" : "latest", pullPolicy: "IfNotPresent", reason: "test", }; } function manifestFor(architecture: string): unknown { return { manifests: [{ platform: { os: "linux", architecture } }] }; } function withCleanImageEnv(fn: () => Promise): Promise { const previous = process.env.OPENWORK_EVAL_KUBE_IMAGES; delete process.env.OPENWORK_EVAL_KUBE_IMAGES; return fn().finally(() => { if (previous === undefined) delete process.env.OPENWORK_EVAL_KUBE_IMAGES; else process.env.OPENWORK_EVAL_KUBE_IMAGES = previous; }); } test("kube profile selection maps values files and org modes", () => { assert.deepEqual(kubeProfileConfig("single-org"), { profile: "single-org", orgMode: "single_org", valuesPath: "evals/fixtures/kube/values/single-org.yaml", }); assert.deepEqual(kubeProfileConfig("multi-org"), { profile: "multi-org", orgMode: "multi_org", valuesPath: "evals/fixtures/kube/values/multi-org.yaml", }); }); test("helm upgrade argv includes release, chart, profile, context, and local image overrides", () => { const args = helmUpgradeArgs(kubeProfileConfig("multi-org"), imagePlan("local")); assert.deepEqual(args.slice(0, 7), [ "upgrade", "--install", "openwork-ee", "packaging/helm/openwork-ee", "-f", "evals/fixtures/kube/values/multi-org.yaml", "--set", ]); assert(args.includes("image.tag=kube-lab")); assert(args.includes("image.pullPolicy=IfNotPresent")); assert(args.includes("denApi.image.repository=openwork-den-api")); assert(args.includes("denWeb.image.repository=openwork-den-web")); assert(args.includes("--kube-context")); assert(args.includes("kind-openwork-kube-lab")); }); test("kubectl rollout and port-forward argv use the kind context", () => { assert.deepEqual(rolloutStatusArgs("openwork-ee-den-api", "300s"), [ "--context", "kind-openwork-kube-lab", "rollout", "status", "deployment/openwork-ee-den-api", "--timeout=300s", ]); assert.deepEqual(portForwardArgs("openwork-ee-den-web", 3005, 3005), [ "--context", "kind-openwork-kube-lab", "port-forward", "service/openwork-ee-den-web", "3005:3005", ]); }); test("published image decision uses manifest platform support", async () => { await withCleanImageEnv(async () => { const platform = currentDockerPlatform(); assert.equal(manifestSupportsPlatform(manifestFor(platform.architecture), platform), true); assert.equal(manifestSupportsPlatform(manifestFor("s390x"), platform), false); const { exec, calls } = createExec(() => success(JSON.stringify(manifestFor(platform.architecture)))); const plan = await resolveKubeImagePlan({ exec }); assert.equal(plan.mode, "published"); assert.equal(calls.filter((call) => call.command === "docker" && call.args.join(" ").includes("manifest inspect")).length, 2); }); }); test("local image decision skips manifest inspection when explicitly requested", async () => { await withCleanImageEnv(async () => { const { exec, calls } = createExec(() => { throw new Error("manifest inspection should not run"); }); const plan = await resolveKubeImagePlan({ exec, images: "local" }); assert.equal(plan.mode, "local"); assert.equal(calls.length, 0); }); }); test("explicit published image mode fails when manifests do not support this platform", async () => { await withCleanImageEnv(async () => { const { exec } = createExec(() => success(JSON.stringify(manifestFor("s390x")))); await assert.rejects( () => resolveKubeImagePlan({ exec, images: "published" }), /Published Den images do not advertise/, ); }); }); test("endpoint handles return credentials and stop only their recorded port-forwards", async () => { const stateDir = await mkdtemp(join(tmpdir(), "openwork-kind-endpoints-test-")); const spawned: { command: string; args: string[]; pid: number }[] = []; const killed: number[] = []; const pids = [987_651, 987_652]; const spawnDetached: KubeSpawnDetached = (command, args) => { const pid = pids[spawned.length]; if (pid === undefined) throw new Error("Unexpected extra detached process."); spawned.push({ command, args: [...args], pid }); return pid; }; const { exec } = createExec((call) => call.command === "lsof" ? { stdout: "", stderr: "", code: 1 } : success()); const previousFetch = globalThis.fetch; const fetchedUrls: string[] = []; const fakeFetch: typeof fetch = async (input) => { const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url; fetchedUrls.push(url); if (url.endsWith("/api/auth/sign-in/email")) { return new Response(JSON.stringify({ token: "kind-owner-token" }), { status: 200, headers: { "content-type": "application/json" }, }); } return new Response("ok", { status: 200 }); }; const envBefore = { apiUrl: process.env.OPENWORK_EVAL_DEN_API_URL, webUrl: process.env.OPENWORK_EVAL_DEN_WEB_URL, token: process.env.OPENWORK_EVAL_DEN_TOKEN, multiOrg: process.env.OPENWORK_EVAL_DEN_MULTI_ORG, }; globalThis.fetch = fakeFetch; try { const endpoints = await exposeEndpointHandles(kubeProfileConfig("single-org"), { stateDir, exec, spawnDetached, sleep: async () => undefined, killProcess: (pid) => killed.push(pid), }); assert.equal(endpoints.apiUrl, "http://127.0.0.1:8790"); assert.equal(endpoints.webUrl, "http://127.0.0.1:3005"); assert.equal(endpoints.token, "kind-owner-token"); assert.equal(endpoints.adminEmail, "alex@acme.test"); assert(fetchedUrls.includes("http://127.0.0.1:3005/api/ready")); assert(!fetchedUrls.includes("http://127.0.0.1:3005/api/den/health")); assert.deepEqual(spawned.map(({ command, pid }) => ({ command, pid })), [ { command: "kubectl", pid: 987_651 }, { command: "kubectl", pid: 987_652 }, ]); assert.equal(await readFile(join(stateDir, "api-port-forward.pid"), "utf8"), "987651"); assert.equal(await readFile(join(stateDir, "web-port-forward.pid"), "utf8"), "987652"); await endpoints.stop(); await endpoints.stop(); assert.deepEqual(killed, [-987_651, 987_651, -987_652, 987_652]); await assert.rejects(() => readFile(join(stateDir, "api-port-forward.pid"), "utf8"), /ENOENT/); await assert.rejects(() => readFile(join(stateDir, "web-port-forward.pid"), "utf8"), /ENOENT/); assert.deepEqual({ apiUrl: process.env.OPENWORK_EVAL_DEN_API_URL, webUrl: process.env.OPENWORK_EVAL_DEN_WEB_URL, token: process.env.OPENWORK_EVAL_DEN_TOKEN, multiOrg: process.env.OPENWORK_EVAL_DEN_MULTI_ORG, }, envBefore); } finally { globalThis.fetch = previousFetch; await rm(stateDir, { recursive: true, force: true }); } }); test("endpoint acquisition failure stops both newly started port-forwards", async () => { const stateDir = await mkdtemp(join(tmpdir(), "openwork-kind-endpoints-failure-test-")); const killed: number[] = []; const pids = [987_661, 987_662]; let spawned = 0; const spawnDetached: KubeSpawnDetached = () => { const pid = pids[spawned]; spawned += 1; if (pid === undefined) throw new Error("Unexpected extra detached process."); return pid; }; const { exec } = createExec((call) => call.command === "lsof" ? { stdout: "", stderr: "", code: 1 } : success()); const previousFetch = globalThis.fetch; globalThis.fetch = async (input) => { const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url; return new Response(url.endsWith("/api/auth/sign-in/email") ? "no" : "ok", { status: url.endsWith("/api/auth/sign-in/email") ? 401 : 200, }); }; try { await assert.rejects( () => exposeEndpointHandles(kubeProfileConfig("single-org"), { stateDir, exec, spawnDetached, sleep: async () => undefined, killProcess: (pid) => killed.push(pid), }), /Could not obtain a demo-owner session.*HTTP 401/, ); assert.deepEqual(killed, [-987_662, 987_662, -987_661, 987_661]); await assert.rejects(() => readFile(join(stateDir, "api-port-forward.pid"), "utf8"), /ENOENT/); await assert.rejects(() => readFile(join(stateDir, "web-port-forward.pid"), "utf8"), /ENOENT/); } finally { globalThis.fetch = previousFetch; await rm(stateDir, { recursive: true, force: true }); } }); test("ensureKindDenReady fails fast when the shared kind cluster is absent", async () => { const { exec, calls } = createExec(() => success("")); await assert.rejects( () => ensureKindDenReady({ exec }), /ensureKubeStack\(\{ cdpCandidates: \[\], skipApp: true \}\)/, ); assert.deepEqual(calls.map((call) => `${call.command} ${call.args.join(" ")}`), ["kind get clusters"]); }); test("ensureKindDenReady verifies both Den rollouts before reading shared state", async () => { const { exec, calls } = createExec((call) => { const text = `${call.command} ${call.args.join(" ")}`; if (text === "kind get clusters") return success("openwork-kube-lab\n"); if (text.includes("SHOW TABLES LIKE")) { return success("organization\ndesktop_connect_grant\nscim_group\ngroup_mapping_mode\n"); } if (text.includes("SELECT id FROM `user`")) return success("seeded-owner-id\n"); return success(); }); await ensureKindDenReady({ exec }); const commands = calls.map((call) => `${call.command} ${call.args.join(" ")}`); const apiRollout = commands.findIndex((command) => command.includes("rollout status deployment/openwork-ee-den-api")); const webRollout = commands.findIndex((command) => command.includes("rollout status deployment/openwork-ee-den-web")); const schemaQuery = commands.findIndex((command) => command.includes("SHOW TABLES LIKE")); assert(apiRollout >= 0); assert(webRollout > apiRollout); assert(schemaQuery > webRollout); }); test("kubeStackDown stops port-forwards before uninstalling the release", async () => { const stateDir = await mkdtemp(join(tmpdir(), "openwork-kube-stack-test-")); const order: string[] = []; const { exec } = createExec((call) => { order.push(`${call.command}:${call.args[0] ?? ""}`); return success(); }); try { await writeFile(join(stateDir, "api-port-forward.pid"), "111"); await writeFile(join(stateDir, "web-port-forward.pid"), "222"); await kubeStackDown({ stateDir, exec, sleep: async () => undefined, killProcess: (pid) => { order.push(`kill:${pid}`); }, }); const firstHelm = order.findIndex((entry) => entry === "helm:uninstall"); assert(firstHelm > 0, `expected helm uninstall after kills, got ${order.join(", ")}`); assert(order.slice(0, firstHelm).some((entry) => entry === "kill:-111")); assert(order.slice(0, firstHelm).some((entry) => entry === "kill:111")); assert(order.slice(0, firstHelm).some((entry) => entry === "kill:-222")); assert(order.slice(0, firstHelm).some((entry) => entry === "kill:222")); } finally { await rm(stateDir, { recursive: true, force: true }); } }); test("rollout failure surfaces pod status and recent logs", async () => { const { exec } = createExec((call) => { const text = `${call.command} ${call.args.join(" ")}`; if (text.includes("helm upgrade")) return success("release upgraded"); if (text.includes("rollout status deployment/openwork-ee-den-api")) return { stdout: "", stderr: "rollout failed", code: 1 }; if (text.includes("get pods")) return success("pod/openwork-ee-den-api pending"); if (text.includes("describe pods")) return success("Events: image pull backoff"); if (text.includes("logs")) return success("pod log line: config missing"); return success(); }); await assert.rejects( () => ensureRelease(kubeProfileConfig("single-org"), imagePlan("published"), { exec }), /pod log line: config missing/, ); });