import { test } from "node:test"; import assert from "node:assert/strict"; import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { catalogueModule } from "./integration/harness.ts"; import type { HeldImage } from "../src/pinning.ts"; /** * The shared loader thirteen beds install through (novox/hq 04-ISSUES/073, ADR 0089): it reads * the catalogue's manifest and rewrites only what the lab must. Checked here against a catalogue * written by the test, so the rules hold without a lab run. */ const digest = (c: string) => "sha256:" + c.repeat(64); const held: HeldImage[] = [ { requested: "mesh-runtime-thing:development", repository: "mesh-runtime-thing", reference: digest("a") }, { requested: "mesh-helper:development", repository: "mesh-helper", reference: digest("b") }, ]; function aCatalogueWith(manifest: object): () => void { const root = mkdtempSync(join(tmpdir(), "mesh-lab-catalogue-")); mkdirSync(join(root, "modules", "distribution"), { recursive: true }); writeFileSync(join(root, "modules", "distribution", "module.json"), "{}"); mkdirSync(join(root, "modules", "thing")); writeFileSync(join(root, "modules", "thing", "module.json"), JSON.stringify(manifest)); const before = process.env["MESH_LAB_CATALOG"]; process.env["MESH_LAB_CATALOG"] = root; return () => { if (before === undefined) delete process.env["MESH_LAB_CATALOG"]; else process.env["MESH_LAB_CATALOG"] = before; rmSync(root, { recursive: true, force: true }); }; } const thing = { module: "thing", version: "1", resources: [ { id: "server", type: "container", name: "thing", image: "postgres@" + digest("c"), ports: ["8080", "9090:9090"], env: { A: "1" } }, { id: "runtime", type: "container", name: "mesh-thing", artifact: "runtime" }, ], build: { artifacts: [{ name: "runtime", kind: "image", from: "Dockerfile" }] }, }; test("the runtime artifact becomes the image the machine holds, and the build section goes", () => { const restore = aCatalogueWith(thing); try { const m = JSON.parse(catalogueModule("thing", held)) as { build?: unknown; resources: Record[] }; assert.equal(m.build, undefined); const runtime = m.resources.find((r) => r["id"] === "runtime")!; assert.equal(runtime["image"], digest("a")); assert.equal(runtime["artifact"], undefined); // An image already pinned to a digest passes through as written. assert.equal(m.resources.find((r) => r["id"] === "server")!["image"], "postgres@" + digest("c")); } finally { restore(); } }); test("an artifact the bed did not name is refused, and a named one resolves to the stocked image", () => { const helper = { ...thing, resources: [{ id: "helper", type: "container", name: "h", artifact: "helper" }] }; const restore = aCatalogueWith(helper); try { assert.throws(() => catalogueModule("thing", held), /names the "helper" artifact/); const m = JSON.parse(catalogueModule("thing", held, { artifacts: { helper: "mesh-helper" } })) as { resources: Record[] }; assert.equal(m.resources[0]!["image"], digest("b")); assert.throws(() => catalogueModule("thing", held, { artifacts: { helper: "mesh-nothing" } }), /stocked no such image/); } finally { restore(); } }); test("a host-port remap and a lab address are the only other things that change", () => { const restore = aCatalogueWith(thing); try { const m = JSON.parse(catalogueModule("thing", held, { ports: { "8080": "8090:8080" }, env: { server: { B: "2" } }, })) as { resources: Record[] }; const server = m.resources.find((r) => r["id"] === "server")!; assert.deepEqual(server["ports"], ["8090:8080", "9090:9090"]); assert.deepEqual(server["env"], { A: "1", B: "2" }); } finally { restore(); } }); test("a manifest the catalogue does not have is refused by name", () => { const restore = aCatalogueWith(thing); try { assert.throws(() => catalogueModule("nothing", held), /no manifest for nothing/); } finally { restore(); } }); test("an upstream artifact resolves to the reference the manifest pins, as the machine pulls it", () => { const web = { module: "thing", version: "1", resources: [{ id: "server", type: "container", name: "web", artifact: "server" }], build: { artifacts: [{ name: "server", kind: "upstream", from: "alpine@" + digest("e") }] }, }; const restore = aCatalogueWith(web); try { const m = JSON.parse(catalogueModule("thing", held)) as { resources: Record[] }; assert.equal(m.resources[0]!["image"], "alpine@" + digest("e")); assert.equal(m.resources[0]!["artifact"], undefined); } finally { restore(); } });