import { describe, expect, it } from "bun:test"; import { Value } from "@sinclair/typebox/value"; import { EdgeClientMessageSchema, EdgeServerMessageSchema } from "@continuum/ts-types"; import currentCapture from "./fixtures/gateway_frames.json"; import legacyCapture from "./fixtures/gateway_frames_legacy_nulls.json"; /** * A contract test, not a unit test: it checks that what continuum-proxy * actually puts on the wire is what this backend's validator accepts. * * The fixtures are real captures from a live gateway talking to a real P1P and * H2C, not hand-written examples - which is the whole point. The two ends of * /ws/edge/v1 had silently drifted into completely different protocols * (different handshake, different telemetry shape, printer ids the gateway * could not know), and every hand-written example agreed with whichever side * wrote it. Re-capture with scripts/capture-gateway-frames.js when the protocol * changes, rather than editing these by hand. */ function check(schema: Parameters[0], value: unknown) { const ok = Value.Check(schema, value); if (!ok) { // Surface *why*, or a failure here is just "false !== true". const errors = [...Value.Errors(schema, value)].map( (e) => `${e.path || "/"}: ${e.message} (got ${JSON.stringify(e.value)})`, ); throw new Error(`validation failed:\n ${errors.join("\n ")}`); } } describe("gateway -> backend frames", () => { for (const frame of currentCapture.frames) { it(`accepts a real '${frame.type}' frame`, () => { check(EdgeClientMessageSchema, frame); }); } it("accepts the pre-fix capture, where empty fields were explicit nulls", () => { // Liberal reader: the gateway now omits these, but a serde-derived // producer emits null by default and one such field must not cost us a // whole farm's telemetry batch. for (const frame of legacyCapture.frames) { check(EdgeClientMessageSchema, frame); } }); it("carries the live telemetry this was captured from", () => { const telemetry = currentCapture.frames.find((f) => f.type === "telemetry"); expect(telemetry).toBeDefined(); const printers = (telemetry as { printers: Array<{ printer_id: string }> }).printers; expect(printers.length).toBeGreaterThan(0); // Guards against a fixture that validates because it is empty. expect(printers.every((p) => typeof p.printer_id === "string" && p.printer_id.length > 0)).toBe(true); }); it("rejects a telemetry batch whose printer has no id", () => { // printer_id and name are the only required fields; everything else is // genuinely unknowable for a printer that has only just connected. check(EdgeClientMessageSchema, { type: "telemetry", printers: [{ printer_id: "p1p", name: "P1P" }] }); expect(Value.Check(EdgeClientMessageSchema, { type: "telemetry", printers: [{ name: "P1P" }] })).toBe(false); }); it("rejects an unknown message type", () => { // The old protocol's handshake, which no gateway ever sent. expect(Value.Check(EdgeClientMessageSchema, { type: "auth", token: "x" })).toBe(false); }); }); describe("backend -> gateway frames", () => { // Exactly what src/routes/ws/edge.ts sends. If one of these stops // validating, the gateway's serde enum will have stopped accepting it too - // see the mirror of this test in continuum-proxy/tests/uplink_protocol.rs. const outbound = [ { type: "hello_ack", session_id: "3f2b1c5e-0000-4000-8000-000000000000" }, { type: "hello_error", message: "invalid edge token" }, { type: "heartbeat_ack", seq: 7 }, { type: "command", command_id: "9a7d2f10-0000-4000-8000-000000000000", printer_id: "p1p", command: { action: "set_fan_speed", percent: 40 }, }, { type: "command", command_id: "9a7d2f11-0000-4000-8000-000000000000", printer_id: "p1p", command: { action: "send_gcode_line", line: "M106 S0" }, }, ]; for (const frame of outbound) { it(`emits a valid '${frame.type}' (${(frame as { command?: { action: string } }).command?.action ?? "no command"})`, () => { check(EdgeServerMessageSchema, frame); }); } it("has no start-print command to send", () => { // Deliberate: the gateway can start an uploaded file, but that path has // never been run against real hardware. Delete this test when it has been, // and add the variant to the schema. expect( Value.Check(EdgeServerMessageSchema, { type: "command", command_id: "x", printer_id: "p1p", command: { action: "start_print", file_name: "plate_1.3mf" }, }), ).toBe(false); }); });