import { describe, expect, it, vi } from "vitest"; vi.mock("../../../apps/api/src/config.js", () => ({ env: { PROCESSING_TIMEOUT_S: 0 }, })); import { computeExternalToolTimeout, computeTimeout } from "../../../apps/api/src/lib/timeout.js"; describe("computeTimeout", () => { it("returns correct timeout for sharp category", () => { const result = computeTimeout(50, "sharp"); expect(result).toBe(Math.max(60_000, 50 * 2 * 1000)); }); it("returns correct timeout for ai_cpu category", () => { const result = computeTimeout(10, "ai_cpu"); expect(result).toBe(Math.max(60_000, 10 * 30 * 1000)); }); it("returns correct timeout for ai_gpu category", () => { const result = computeTimeout(20, "ai_gpu"); expect(result).toBe(Math.max(60_000, 20 * 5 * 1000)); }); it("returns correct timeout for external category", () => { const result = computeTimeout(10, "external"); expect(result).toBe(Math.max(60_000, 10 * 10 * 1000)); }); it("returns correct timeout for python category", () => { const result = computeTimeout(10, "python"); expect(result).toBe(Math.max(60_000, 10 * 15 * 1000)); }); it("enforces minimum timeout of 60_000ms", () => { const result = computeTimeout(0.001, "sharp"); expect(result).toBe(60_000); }); it("enforces minimum timeout for small megapixel values", () => { const result = computeTimeout(1, "sharp"); expect(result).toBe(60_000); }); it("multiplies timeout by file count", () => { const single = computeTimeout(50, "sharp"); const triple = computeTimeout(50, "sharp", 3); expect(triple).toBe(single * 3); }); it("defaults to fileCount of 1", () => { const result = computeTimeout(50, "sharp"); const explicit = computeTimeout(50, "sharp", 1); expect(result).toBe(explicit); }); it("scales correctly for large megapixel values", () => { const result = computeTimeout(100, "ai_cpu"); expect(result).toBe(100 * 30 * 1000); }); it("uses override when PROCESSING_TIMEOUT_S > 0", async () => { const configMod = await import("../../../apps/api/src/config.js"); const saved = configMod.env.PROCESSING_TIMEOUT_S; configMod.env.PROCESSING_TIMEOUT_S = 120; try { const result = computeTimeout(999, "ai_gpu", 10); expect(result).toBe(120 * 1000); } finally { configMod.env.PROCESSING_TIMEOUT_S = saved; } }); it("override ignores megapixels and fileCount", async () => { const configMod = await import("../../../apps/api/src/config.js"); const saved = configMod.env.PROCESSING_TIMEOUT_S; configMod.env.PROCESSING_TIMEOUT_S = 60; try { const result = computeTimeout(200, "python", 5); expect(result).toBe(60 * 1000); } finally { configMod.env.PROCESSING_TIMEOUT_S = saved; } }); it("minimum applies per-file before multiplying by count", () => { const result = computeTimeout(0, "sharp", 3); expect(result).toBe(60_000 * 3); }); }); describe("computeExternalToolTimeout", () => { it("returns correct timeout for external category", () => { const result = computeExternalToolTimeout(10); expect(result).toBe(10 * 10 * 1000); }); it("enforces minimum timeout of 60_000ms", () => { const result = computeExternalToolTimeout(0); expect(result).toBe(60_000); }); it("scales with megapixels", () => { const result = computeExternalToolTimeout(50); expect(result).toBe(50 * 10 * 1000); }); it("uses override when PROCESSING_TIMEOUT_S > 0", async () => { const configMod = await import("../../../apps/api/src/config.js"); const saved = configMod.env.PROCESSING_TIMEOUT_S; configMod.env.PROCESSING_TIMEOUT_S = 300; try { const result = computeExternalToolTimeout(999); expect(result).toBe(300 * 1000); } finally { configMod.env.PROCESSING_TIMEOUT_S = saved; } }); it("enforces minimum for small megapixel values", () => { const result = computeExternalToolTimeout(0.5); expect(result).toBe(60_000); }); });