import { describe, expect, test } from "bun:test"; import { Value } from "@sinclair/typebox/value"; import { EdgeClientMessageSchema } from "@continuum/ts-types"; import { NO_CAMERA_MESSAGE, NO_GATEWAY_MESSAGE, resolveStream } from "../src/stream"; const hello = { type: "hello", gateway_id: "gw-1", farm_id: "f1", token: "t" }; describe("hello stream_base_url", () => { test("is accepted when present", () => { const msg = { ...hello, stream_base_url: "http://gateway.local:1984" }; expect(Value.Check(EdgeClientMessageSchema, msg)).toBe(true); }); test("is accepted when absent, the normal case", () => { expect(Value.Check(EdgeClientMessageSchema, hello)).toBe(true); }); test("tolerates an explicit null from a serde producer", () => { expect(Value.Check(EdgeClientMessageSchema, { ...hello, stream_base_url: null })).toBe(true); }); }); describe("telemetry camera_stream", () => { const telemetry = (extra: object) => ({ type: "telemetry", printers: [{ printer_id: "p1", name: "X1", ...extra }], }); // The persistence step itself is `snapshot.camera_stream ?? null` inside // persistTelemetry, which needs a database; what is checked here is that // the value survives the validator that guards that path. test("survives validation with its value intact", () => { const msg = telemetry({ camera_stream: "p1" }); expect(Value.Check(EdgeClientMessageSchema, msg)).toBe(true); expect((msg.printers[0] as { camera_stream?: string }).camera_stream).toBe("p1"); }); test("is optional", () => { expect(Value.Check(EdgeClientMessageSchema, telemetry({}))).toBe(true); }); }); describe("resolveStream", () => { // No streamUrl any more, and its absence is the point: a browser cannot // play from a gateway's own address (no CORS, and a workshop NAT besides), // so handing one out only invited a player that could never load. What is // left is the camera name to negotiate for. test("returns the endpoint's success shape", () => { expect(resolveStream("p1", true)).toEqual({ ok: true, stream: { cameraId: "p1" } }); }); test("the two failures are distinguishable", () => { const noCamera = resolveStream(null, true); const offline = resolveStream("p1", false); if (noCamera.ok || offline.ok) throw new Error("expected both to fail"); expect(noCamera.reason).toBe("no_camera"); expect(offline.reason).toBe("gateway_offline"); expect(noCamera.message).toBe(NO_CAMERA_MESSAGE); expect(offline.message).toBe(NO_GATEWAY_MESSAGE); // Different problems for whoever is debugging: a P1/A1 that can never // stream, versus a gateway that is merely unplugged. expect(noCamera.message).not.toBe(offline.message); }); test("a printer with no camera is blamed first, even if the gateway is also absent", () => { const both = resolveStream(undefined, false); expect(!both.ok && both.reason).toBe("no_camera"); }); });