Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
86 lines
3.5 KiB
TypeScript
86 lines
3.5 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
import { enqueueUnseenJobs, extractErrorSummary, shouldSendLiveUpdate, yieldAfterChunk } from "../execute";
|
|
|
|
describe("extractErrorSummary", () => {
|
|
test("pulls the real error line out of ffmpeg's banner", () => {
|
|
const lines = [
|
|
"[stderr] ffmpeg version 7.1.3 ...",
|
|
"[stderr] built with gcc 14",
|
|
"[stderr] Stream #0:2(eng): Subtitle: dvd_subtitle (dvdsub), 1280x720",
|
|
"[stderr] Stream mapping:",
|
|
"[stderr] Stream #0:2 -> #0:0 (copy)",
|
|
"[stderr] [srt @ 0x55] Unsupported subtitles codec: dvd_subtitle",
|
|
"[stderr] [out#0/srt @ 0x55] Could not write header (incorrect codec parameters ?): Invalid argument",
|
|
"[stderr] Conversion failed!",
|
|
];
|
|
const summary = extractErrorSummary(lines, new Error("FFmpeg exited with code 234"));
|
|
expect(summary).toContain("Unsupported subtitles codec: dvd_subtitle");
|
|
expect(summary).toContain("Invalid argument");
|
|
expect(summary).toContain("Conversion failed!");
|
|
// Should NOT include the banner lines.
|
|
expect(summary).not.toContain("ffmpeg version");
|
|
expect(summary).not.toContain("Stream #0:2");
|
|
});
|
|
|
|
test("dedupes identical fatal lines (e.g. repeated warnings)", () => {
|
|
const lines = ["[stderr] Conversion failed!", "[stderr] Conversion failed!", "[stderr] Conversion failed!"];
|
|
const summary = extractErrorSummary(lines);
|
|
expect(summary?.split("\n").length).toBe(1);
|
|
});
|
|
|
|
test("falls back to the thrown error when no fatal line is found", () => {
|
|
const lines = ["[stderr] ffmpeg version 7", "[stderr] Duration: 00:10:00"];
|
|
const summary = extractErrorSummary(lines, new Error("FFmpeg exited with code 1"));
|
|
expect(summary).toBe("Error: FFmpeg exited with code 1");
|
|
});
|
|
|
|
test("returns null when neither a fatal line nor a thrown error is available", () => {
|
|
expect(extractErrorSummary([])).toBe(null);
|
|
expect(extractErrorSummary(["[stderr] ffmpeg version 7"])).toBe(null);
|
|
});
|
|
|
|
test("only scans the tail — a banner from a prior run doesn't leak through", () => {
|
|
// 70 filler lines, real error at the very end; scan window is 60.
|
|
const filler = Array.from({ length: 70 }, (_, i) => `[stderr] banner line ${i}`);
|
|
const lines = [...filler, "[stderr] Error: no space left on device"];
|
|
const summary = extractErrorSummary(lines);
|
|
expect(summary).toBe("Error: no space left on device");
|
|
});
|
|
});
|
|
|
|
describe("shouldSendLiveUpdate", () => {
|
|
test("throttles updates until interval passes", () => {
|
|
expect(shouldSendLiveUpdate(1_000, 800, 500)).toBe(false);
|
|
expect(shouldSendLiveUpdate(1_301, 800, 500)).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("yieldAfterChunk", () => {
|
|
test("yields once threshold is reached, resets chunk counter", async () => {
|
|
let yieldCalls = 0;
|
|
const sleep = async (_ms: number) => {
|
|
yieldCalls += 1;
|
|
};
|
|
let chunks = 0;
|
|
chunks = await yieldAfterChunk(chunks, 3, sleep);
|
|
expect(chunks).toBe(1);
|
|
chunks = await yieldAfterChunk(chunks, 3, sleep);
|
|
expect(chunks).toBe(2);
|
|
chunks = await yieldAfterChunk(chunks, 3, sleep);
|
|
expect(chunks).toBe(0);
|
|
expect(yieldCalls).toBe(1);
|
|
});
|
|
});
|
|
|
|
describe("enqueueUnseenJobs", () => {
|
|
test("appends only unseen job ids to the active queue", () => {
|
|
const queue = [{ id: 1 }, { id: 2 }] as { id: number }[];
|
|
const seen = new Set([1, 2]);
|
|
const added = enqueueUnseenJobs(queue, seen, [{ id: 2 }, { id: 3 }, { id: 4 }] as { id: number }[]);
|
|
expect(added).toBe(2);
|
|
expect(queue.map((j) => j.id)).toEqual([1, 2, 3, 4]);
|
|
expect(seen.has(3)).toBeTrue();
|
|
expect(seen.has(4)).toBeTrue();
|
|
});
|
|
});
|