Download packages/protocol/test/protocol.test.ts from SaylorTwift/pi: direct link, hf CLI and curl.
- Browser
- Download file 10 kB
-
https://huggingface.co/SaylorTwift/pi/resolve/main/packages/protocol/test/protocol.test.ts
- Command line
-
hf download hf://SaylorTwift/pi/packages/protocol/test/protocol.test.ts
-
curl -L -o protocol.test.ts https://huggingface.co/SaylorTwift/pi/resolve/main/packages/protocol/test/protocol.test.ts
10 kB
| import { describe, expect, test } from "vitest"; | |
| import { | |
| type ClientHello, | |
| type ClientMessage, | |
| ClientMessageDecoder, | |
| decodeCbor, | |
| encodeCbor, | |
| encodeClientMessage, | |
| encodeFrame, | |
| encodeServerMessage, | |
| FrameDecoder, | |
| isSupportedProtocolVersion, | |
| PROTOCOL_VERSION, | |
| ProtocolValidationError, | |
| parseClientMessage, | |
| parseServerMessage, | |
| type ServerHello, | |
| type ServerMessage, | |
| ServerMessageDecoder, | |
| } from "../src/index.ts"; | |
| const clientHello: ClientHello = { type: "hello", version: PROTOCOL_VERSION }; | |
| const serverHello: ServerHello = { | |
| type: "hello", | |
| version: PROTOCOL_VERSION, | |
| serverId: "00000000-0000-4000-8000-000000000001", | |
| }; | |
| describe("protocol validation", () => { | |
| test("negotiates protocol version 8", () => { | |
| expect(PROTOCOL_VERSION).toBe(8); | |
| expect(isSupportedProtocolVersion(8)).toBe(true); | |
| expect(isSupportedProtocolVersion(7)).toBe(false); | |
| expect(isSupportedProtocolVersion(8.5)).toBe(false); | |
| }); | |
| test.each([0, PROTOCOL_VERSION, PROTOCOL_VERSION + 1])( | |
| "accepts integer client hello version %s for negotiation", | |
| (version) => expect(parseClientMessage({ ...clientHello, version })).toEqual({ ...clientHello, version }), | |
| ); | |
| test.each([ | |
| { type: "hello", version: String(PROTOCOL_VERSION) }, | |
| { type: "hello", version: PROTOCOL_VERSION + 0.5 }, | |
| { type: "hello", version: PROTOCOL_VERSION, extra: true }, | |
| ])("rejects an invalid client hello", (message) => { | |
| expect(() => parseClientMessage(message)).toThrow(ProtocolValidationError); | |
| }); | |
| test.each([ | |
| "", | |
| "server-1", | |
| "00000000-0000-7000-8000-000000000001", | |
| "00000000-0000-4000-7000-000000000001", | |
| "00000000-0000-4000-8000-00000000000A", | |
| ])("rejects non-canonical UUIDv4 server ID %j", (serverId) => { | |
| expect(() => | |
| parseClientMessage({ | |
| type: "request", | |
| id: "request-1", | |
| target: { serverId }, | |
| call: { serviceId: "pi.models", member: "list", args: [] }, | |
| }), | |
| ).toThrow(ProtocolValidationError); | |
| }); | |
| test("keeps routed request and event payloads opaque", () => { | |
| const request: ClientMessage = { | |
| type: "request", | |
| id: "request-1", | |
| target: { | |
| serverId: "00000000-0000-4000-8000-000000000001", | |
| sessionId: "session-1", | |
| attachmentId: "attachment-1", | |
| }, | |
| call: { | |
| serviceId: "application.custom", | |
| instance: { key: "instance-1", generation: 2 }, | |
| member: "invoke", | |
| args: [{ arbitrary: true }, ["opaque"]], | |
| }, | |
| }; | |
| expect(parseClientMessage(request)).toEqual(request); | |
| expect( | |
| parseClientMessage({ | |
| ...request, | |
| call: { arbitrary: "strict JSON whose service meaning belongs to Chord" }, | |
| }), | |
| ).toMatchObject({ call: { arbitrary: expect.any(String) } }); | |
| expect( | |
| parseServerMessage({ | |
| type: "service_update", | |
| subscriptionId: "subscription-1", | |
| update: { applicationDefined: true }, | |
| }), | |
| ).toMatchObject({ update: { applicationDefined: true } }); | |
| }); | |
| test("rejects non-JSON opaque payloads", () => { | |
| const request = { | |
| type: "request", | |
| id: "request-1", | |
| target: { serverId: "00000000-0000-4000-8000-000000000001" }, | |
| call: { serviceId: "application.custom", member: "invoke", args: [] }, | |
| }; | |
| const cyclic: { self?: unknown } = {}; | |
| cyclic.self = cyclic; | |
| for (const [label, value] of [ | |
| ["byte array", new Uint8Array([1])], | |
| ["non-finite number", Number.NaN], | |
| ["undefined property", { value: undefined }], | |
| ["cycle", cyclic], | |
| ] as const) { | |
| expect(() => parseClientMessage({ ...request, call: { ...request.call, args: [value] } }), label).toThrow( | |
| ProtocolValidationError, | |
| ); | |
| expect( | |
| () => parseServerMessage({ type: "response", id: "request-1", ok: true, result: value }), | |
| label, | |
| ).toThrow(ProtocolValidationError); | |
| } | |
| }); | |
| test("validates request cancellation envelopes", () => { | |
| const cancel: ClientMessage = { | |
| type: "cancel", | |
| id: "request-1", | |
| target: { serverId: "00000000-0000-4000-8000-000000000001" }, | |
| }; | |
| expect(parseClientMessage(cancel)).toEqual(cancel); | |
| expect(() => parseClientMessage({ ...cancel, id: "" })).toThrow(ProtocolValidationError); | |
| expect(() => parseClientMessage({ ...cancel, extra: true })).toThrow(ProtocolValidationError); | |
| }); | |
| test("validates attachment route updates", () => { | |
| const attached: ServerMessage = { | |
| type: "attachment", | |
| attachment: { | |
| serverId: "00000000-0000-4000-8000-000000000001", | |
| sessionId: "session-1", | |
| attachmentId: "attachment-1", | |
| }, | |
| }; | |
| const detached: ServerMessage = { type: "attachment", attachment: null }; | |
| expect(parseServerMessage(attached)).toEqual(attached); | |
| expect(parseServerMessage(detached)).toEqual(detached); | |
| expect(() => parseServerMessage({ ...attached, attachment: { sessionId: "session-1" } })).toThrow( | |
| ProtocolValidationError, | |
| ); | |
| }); | |
| test.each([ | |
| [ | |
| "empty request id", | |
| { | |
| type: "request", | |
| id: "", | |
| target: { serverId: "00000000-0000-4000-8000-000000000001" }, | |
| call: { serviceId: "pi.models", member: "list", args: [] }, | |
| }, | |
| ], | |
| [ | |
| "extra envelope field", | |
| { | |
| type: "request", | |
| id: "request-1", | |
| target: { serverId: "00000000-0000-4000-8000-000000000001" }, | |
| call: { serviceId: "pi.models", member: "list", args: [] }, | |
| extra: true, | |
| }, | |
| ], | |
| ] as const)("rejects malformed request boundaries: %s", (_label, message) => { | |
| expect(() => parseClientMessage(message)).toThrow(ProtocolValidationError); | |
| }); | |
| test("accepts a successful void response without a result field", () => { | |
| expect(parseServerMessage({ type: "response", id: "request-1", ok: true })).toEqual({ | |
| type: "response", | |
| id: "request-1", | |
| ok: true, | |
| }); | |
| }); | |
| test.each([ | |
| ["invalid server id", { ...serverHello, serverId: "server-1" }], | |
| ["extra response field", { type: "response", id: "request-1", ok: true, result: [], extra: true }], | |
| ["empty error code", { type: "response", id: "request-1", ok: false, error: { code: "", message: "bad" } }], | |
| ] as const)("rejects malformed server boundaries: %s", (_label, message) => { | |
| expect(() => parseServerMessage(message)).toThrow(ProtocolValidationError); | |
| }); | |
| test.each(["wrong_server", "cancelled", "service_not_found", "application_error"] as const)( | |
| "accepts the opaque %s error code", | |
| (code) => { | |
| const message: ServerMessage = { | |
| type: "response", | |
| id: "request-1", | |
| ok: false, | |
| error: { code, message: "safe" }, | |
| }; | |
| expect(parseServerMessage(message)).toEqual(message); | |
| }, | |
| ); | |
| test("rejects unknown messages and fields", () => { | |
| expect(() => parseServerMessage({ ...serverHello, snapshot: {} })).toThrow(ProtocolValidationError); | |
| expect(() => parseServerMessage({ type: "unknown", event: {} })).toThrow(ProtocolValidationError); | |
| }); | |
| test("does not parse JSON strings as messages", () => { | |
| expect(() => parseClientMessage(JSON.stringify(clientHello))).toThrow(ProtocolValidationError); | |
| expect(() => parseServerMessage(JSON.stringify(serverHello))).toThrow(ProtocolValidationError); | |
| }); | |
| }); | |
| describe("validated framed protocol APIs", () => { | |
| test("encodes complete client and server frames", () => { | |
| const clientFrames = new FrameDecoder().push(encodeClientMessage(clientHello)); | |
| expect(parseClientMessage(decodeCbor(clientFrames[0]!))).toEqual(clientHello); | |
| const serverFrames = new FrameDecoder().push(encodeServerMessage(serverHello)); | |
| expect(parseServerMessage(decodeCbor(serverFrames[0]!))).toEqual(serverHello); | |
| }); | |
| test("enforces outbound frame limits", () => { | |
| expect(() => encodeClientMessage(clientHello, { maxFrameLength: 8 })).toThrow(ProtocolValidationError); | |
| expect(() => encodeServerMessage(serverHello, { maxFrameLength: 8 })).toThrow(ProtocolValidationError); | |
| }); | |
| test("incrementally decodes fragmented and coalesced client messages", () => { | |
| const request: ClientMessage = { | |
| type: "request", | |
| id: "request-1", | |
| target: { serverId: "00000000-0000-4000-8000-000000000001" }, | |
| call: { serviceId: "pi.session-directory", member: "list", args: [] }, | |
| }; | |
| const first = encodeClientMessage(clientHello); | |
| const second = encodeClientMessage(request); | |
| const wire = new Uint8Array(first.byteLength + second.byteLength); | |
| wire.set(first); | |
| wire.set(second, first.byteLength); | |
| for (let split = 0; split <= wire.byteLength; split++) { | |
| const decoder = new ClientMessageDecoder(); | |
| const messages = [...decoder.push(wire.subarray(0, split)), ...decoder.push(wire.subarray(split))]; | |
| decoder.end(); | |
| expect(messages).toEqual([clientHello, request]); | |
| } | |
| }); | |
| test("incrementally decodes fragmented and coalesced server messages", () => { | |
| const response: ServerMessage = { type: "response", id: "request-1", ok: true, result: [] }; | |
| const first = encodeServerMessage(serverHello); | |
| const second = encodeServerMessage(response); | |
| const wire = new Uint8Array(first.byteLength + second.byteLength); | |
| wire.set(first); | |
| wire.set(second, first.byteLength); | |
| const split = first.byteLength + Math.floor(second.byteLength / 2); | |
| const decoder = new ServerMessageDecoder(); | |
| expect(decoder.push(wire.subarray(0, split))).toEqual([serverHello]); | |
| expect(decoder.push(wire.subarray(split))).toEqual([response]); | |
| decoder.end(); | |
| }); | |
| test.each([ | |
| ["empty CBOR payload", encodeFrame(new Uint8Array())], | |
| ["malformed CBOR", encodeFrame(new Uint8Array([0xff]))], | |
| ["schema-invalid CBOR", encodeFrame(encodeCbor({ type: "hello", version: 1, extra: true }))], | |
| ] as const)("rejects invalid framed input: %s", (_label, wire) => { | |
| const decoder = new ClientMessageDecoder(); | |
| expect(() => decoder.push(wire)).toThrow(ProtocolValidationError); | |
| expect(() => decoder.push(encodeClientMessage(clientHello))).toThrow(/failed/i); | |
| }); | |
| test("rejects truncated and oversized framing", () => { | |
| const truncated = new ServerMessageDecoder(); | |
| expect(truncated.push(new Uint8Array([0, 0, 0, 2, 1]))).toEqual([]); | |
| expect(() => truncated.end()).toThrow(ProtocolValidationError); | |
| const oversized = new ClientMessageDecoder({ maxFrameLength: 3 }); | |
| expect(() => oversized.push(new Uint8Array([0, 0, 0, 4]))).toThrow(ProtocolValidationError); | |
| }); | |
| }); | |