import { describe, expect, test } from "bun:test"; import { parseLogTailLines, runLogs, type LogApiEvent, type LogEventWriter, type LogsApiStream, } from "../../command/logs"; describe("logs API command runner", () => { test("uses the authenticated workspace NDJSON route and preserves prefixes", async () => { const calls: Array<{ path: string; signal?: AbortSignal; timeout?: number; }> = []; const events: LogApiEvent[] = [ { type: "heartbeat", timestamp: "now" }, { type: "log", targetName: "web", pod: "web-1", container: "web", message: "ready", }, { type: "error", pod: "web-1", container: "web", message: "disconnected", retryable: true, }, ]; const stream: LogsApiStream = async function* (path, init, options) { calls.push({ path, signal: init?.signal ?? undefined, timeout: options?.timeoutMs, }); yield* events as never[]; }; const output: Parameters[] = []; const controller = new AbortController(); await runLogs( "shop/demo", "web api", true, controller.signal, stream, (...entry) => output.push(entry), ); expect(calls).toEqual([ { path: "/workspaces/shop%2Fdemo/logs?service=web+api&follow=true", signal: controller.signal, timeout: 0, }, ]); expect(output).toEqual([ ["web-1", "ready", false], ["web api", "disconnected", true], ]); }); test("omits follow for finite collection and passes cancellation", async () => { const controller = new AbortController(); let receivedSignal: AbortSignal | null | undefined; const stream: LogsApiStream = async function* (path, init, options) { expect(path).toBe("/workspaces/shop/logs"); expect(options?.timeoutMs).toBeUndefined(); receivedSignal = init?.signal; yield* []; }; await runLogs( "shop", undefined, false, controller.signal, stream, () => {}, ); expect(receivedSignal).toBe(controller.signal); }); test.each([false, true])("sends -n with follow=%s", async (follow) => { const paths: string[] = []; const stream: LogsApiStream = async function* (path, _init, options) { paths.push(path); expect(options?.timeoutMs).toBe(follow ? 0 : undefined); yield* [] as never[]; }; await runLogs("shop", "web", follow, undefined, stream, () => {}, 0); expect(paths).toEqual([ `/workspaces/shop/logs?service=web${follow ? "&follow=true" : ""}&tailLines=0`, ]); }); test("accepts only non-negative safe integer line counts", async () => { expect(parseLogTailLines("25")).toBe(25); expect(parseLogTailLines("0")).toBe(0); for (const invalid of ["-1", "1.5", "2abc", "", "1e3", "9007199254740992"]) expect(() => parseLogTailLines(invalid)).toThrow("non-negative integer"); let called = false; const stream: LogsApiStream = async function* () { called = true; yield* [] as never[]; }; await expect( runLogs("shop", undefined, false, undefined, stream, () => {}, -1), ).rejects.toThrow("non-negative integer"); expect(called).toBe(false); }); });