Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889import { describe, expect, it } from "vitest";import { decodeLogFrame, pipelineLogsUrl } from "./spindleLogs";
// captured off the spindle's own serializer: CiSubscribePipelineLogs_Event// .Serialize in api/tangled/cisubscribePipelineLogs_ext.go, hex-dumpedconst frames = { controlStart: "a261746823636f6e74726f6c626f7001a7646b696e6464757365726473746570016474696d6574323032362d30382d30365431323a30303a30305a6673746174757365737461727467636f6d6d616e64676563686f20686967636f6e74656e746952756e20746573747368776f726b666c6f77656275696c64", controlMinimal: "a261746823636f6e74726f6c626f7001a46473746570016474696d6574323032362d30382d30365431323a30303a30395a67636f6e74656e746952756e20746573747368776f726b666c6f77656275696c64", data: "a26174652364617461626f7001a56473746570016474696d6574323032362d30382d30365431323a30303a30315a6673747265616d6673746465727267636f6e74656e746e1b5b33316d626f6f6d1b5b306d0a68776f726b666c6f77656275696c64", error: "a1626f7020a2656572726f7270576f726b666c6f774e6f74466f756e64676d657373616765706e6f207375636820776f726b666c6f77"} as const;
const bytes = (hex: string): Uint8Array => Uint8Array.from(hex.match(/../g)!.map((pair) => parseInt(pair, 16)));
describe("decodeLogFrame", () => { it("reads a step start with its command and kind", () => { expect(decodeLogFrame(bytes(frames.controlStart))).toEqual({ kind: "control", control: { time: "2026-08-06T12:00:00Z", workflow: "build", step: 1, content: "Run tests", command: "echo hi", status: "start", kind: "user" } }); });
it("leaves the optional control fields off when the spindle omits them", () => { const frame = decodeLogFrame(bytes(frames.controlMinimal)); expect(frame).toEqual({ kind: "control", control: { time: "2026-08-06T12:00:09Z", workflow: "build", step: 1, content: "Run tests" } }); });
it("keeps a data line's ansi bytes and trailing newline intact", () => { expect(decodeLogFrame(bytes(frames.data))).toEqual({ kind: "data", data: { time: "2026-08-06T12:00:01Z", workflow: "build", step: 1, content: "\u001b[31mboom\u001b[0m\n", stream: "stderr" } }); });
it("surfaces the stream's error frame", () => { expect(decodeLogFrame(bytes(frames.error))).toEqual({ kind: "error", error: "WorkflowNotFound", message: "no such workflow" }); });
it("ignores a message type it doesn't know", () => { // same header shape, unknown t const unknown = "a2617464236e6577626f7001a0"; expect(decodeLogFrame(bytes(unknown))).toBeNull(); });});
describe("pipelineLogsUrl", () => { it("upgrades the spindle's scheme and repeats the workflow param", () => { expect(pipelineLogsUrl("spindle.tangled.org", "3lz", ["build", "test"])).toBe( "wss://spindle.tangled.org/xrpc/sh.tangled.ci.subscribePipelineLogs?pipeline=3lz&workflows=build&workflows=test" ); });
it("stays plaintext for a local spindle", () => { expect(pipelineLogsUrl("localhost:6555", "3lz", ["build"])).toBe( "ws://localhost:6555/xrpc/sh.tangled.ci.subscribePipelineLogs?pipeline=3lz&workflows=build" ); });});