import assert from "node:assert/strict"; import test from "node:test"; import { formatFailure, startCraftos, startSandbox, waitFor } from "./harness.js"; // Two real computers with the same traposId (id:label): newest-wins. After both // complete hello, exactly one registration exists; aborting the displaced first // computer does not affect the live registration, and a gateway->computer ping is // still answered by the newest computer. test("duplicate traposId is resolved newest-wins", async () => { const sandbox = await startSandbox(); const TRAPOS_ID = "9:dup"; // Newest-wins is decided by the order hello frames reach the gateway, which is // independent of the client-side READY print order. Spawn the two computers // sequentially — only start `second` once `first` is registered server-side — // so `second` is unambiguously the newer registration. const first = startCraftos("gateway-client.lua", { computerId: 9, computerLabel: "dup", shellArgs: [sandbox.baseUrl, "-", "idle", "60"], }); let second: ReturnType | undefined; try { await waitFor(() => first.snapshot().includes("__SANDBOX_READY__"), 12_000, "first connected"); await waitFor(() => sandbox.registry.has("local", TRAPOS_ID), 2_000, "first registered server-side"); const secondHandle = startCraftos("gateway-client.lua", { computerId: 9, computerLabel: "dup", shellArgs: [sandbox.baseUrl, "-", "idle"], }); second = secondHandle; await waitFor(() => secondHandle.snapshot().includes("__SANDBOX_READY__"), 12_000, "second connected"); // Newest-wins: still exactly one registration for the shared id. assert.equal(sandbox.registry.count(), 1, "exactly one registration after the duplicate"); assert.ok(sandbox.registry.has("local", TRAPOS_ID)); first.abort(); await first.done.catch(() => undefined); const payload = await sandbox.registry.request("local", TRAPOS_ID, "ping", {}, 2_000); assert.deepEqual(payload, { traposId: TRAPOS_ID }, "newest stayed registered after first exited"); } catch (error) { throw new Error( formatFailure( error instanceof Error ? error.message : String(error), `first:\n${first.snapshot()}\nsecond:\n${second?.snapshot() ?? "(not started)"}`, ), { cause: error }, ); } finally { first.abort(); second?.abort(); await Promise.all([first.done.catch(() => undefined), second?.done.catch(() => undefined)]); await sandbox.close(); } });