/** @file OCapN vats: a client on the admin socket creates a vat and passes it a remote object. */ import { mkdir, mkdtemp, readFile, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { after, before, test } from "node:test"; import assert from "node:assert/strict"; import { E, Far } from "@endo/far"; import { connectClient } from "../client.js"; import { freePort, here, startWorkerd } from "./workerd.js"; const vatSrc = (name) => readFile(join(here, "vats", name), "utf8"); let dir, port, server, client; before(async () => { dir = await mkdtemp(join(tmpdir(), "toybox-ocapn-")); await mkdir(join(dir, "state")); port = await freePort(); server = await startWorkerd( "config.capnp", [ "-s", `http=127.0.0.1:${port}`, "-s", `admin=unix:${join(dir, "admin.sock")}`, "-d", `state=${join(dir, "state")}`, "-e", `switchboard=unix:${join(dir, "no-switchboard.sock")}`, ], { port, host: "127.0.0.1" }, [join(dir, "admin.sock")], ); client = await connectClient(join(dir, "admin.sock"), "client-1", { verbose: !!process.env.OCAPN_LOG }); }); after(async () => { client?.close(); await server?.stop(); await rm(dir, { recursive: true, force: true }); }); test("createVat passes a remote object in; the vat's root comes back", async () => { const carol = Far("carol", { greet: (name) => `hi ${name}, from carol` }); const { id, root } = await E(client.vatAdmin).createVat(await vatSrc("greeter.js"), { carol }); assert.match(id, /^[0-9a-f]{64}$/); assert.equal(await E(root).hello(), "hello from the vat"); assert.equal(await E(root).greetVia("vat"), "hi vat, from carol"); }); test("a counter vat counts; two counter vats count apart", async () => { const src = await vatSrc("counter.js"); const { root: a } = await E(client.vatAdmin).createVat(src); const { root: b } = await E(client.vatAdmin).createVat(src); assert.equal(await E(a).increment(), 1); assert.equal(await E(a).increment(), 2); assert.equal(await E(b).increment(), 1); assert.equal(await E(a).read(), 2); assert.equal(await E(b).read(), 1); }); test("a vat serves the web through the ingress it is given", async () => { const ingress = await E(client.vatAdmin).makeIngress({ vat: "hello" }); await E(client.vatAdmin).createVat(await vatSrc("hello.js"), { ingress }); const resp = await fetch(`http://127.0.0.1:${port}/greet?vat=hello`); assert.equal(resp.status, 200); assert.equal(resp.headers.get("content-type"), "text/html; charset=utf-8"); assert.match(await resp.text(), /

Hello, world<\/h1>

from a toybox vat, at \/greet<\/p>/); }); test("an ingress nobody serves is a 503", async () => { await E(client.vatAdmin).makeIngress({ vat: "idle" }); assert.equal((await fetch(`http://127.0.0.1:${port}/?vat=idle`)).status, 503); });