1
7import { describe, expect, it } from "vitest";
8import { S3Error } from "../../../lib/s3.js";
9import { classifyError, FatalError, RetryableError } from "../errors.js";
10
11describe("files pipeline error classification (TASK-0102 §1)", () => {
12 it("S3 5xx → retryable (transient server fault)", () => {
13 for (const code of [500, 502, 503, 504]) {
14 const e = classifyError(new S3Error("InternalError", "boom", code));
15 expect(e, `S3 ${code}`).toBeInstanceOf(RetryableError);
16 }
17 });
18
19 it("S3 404 → fatal 'upload_not_found' (the object is gone, retry can't fix it)", () => {
20 const e = classifyError(new S3Error("NoSuchKey", "no such key", 404));
21 expect(e).toBeInstanceOf(FatalError);
22 expect((e as FatalError).code).toBe("upload_not_found");
23 });
24
25 it("S3 400/401/403 → fatal 's3_client_error' (bad request/auth, not transient)", () => {
26 for (const code of [400, 401, 403]) {
27 const e = classifyError(new S3Error("AccessDenied", "denied", code));
28 expect(e, `S3 ${code}`).toBeInstanceOf(FatalError);
29 }
30 });
31
32 it("network / fetch failures → retryable", () => {
33 expect(classifyError(new TypeError("fetch failed"))).toBeInstanceOf(RetryableError);
34 expect(classifyError(new Error("connect ECONNREFUSED 127.0.0.1:9000"))).toBeInstanceOf(
35 RetryableError
36 );
37 expect(classifyError(new Error("socket hang up ECONNRESET"))).toBeInstanceOf(RetryableError);
38 expect(classifyError(new Error("UND_ERR_SOCKET socket error"))).toBeInstanceOf(RetryableError);
39 });
40
41 it("redis blips → retryable", () => {
42 expect(classifyError(new Error("Connection is closed."))).toBeInstanceOf(RetryableError);
43 expect(classifyError(new Error("Ready check failed"))).toBeInstanceOf(RetryableError);
44 });
45
46 it("pre-classified errors pass through unchanged", () => {
47 const r = new RetryableError("x");
48 expect(classifyError(r)).toBe(r);
49 const f = new FatalError("x", "corrupt_object");
50 expect(classifyError(f)).toBe(f);
51 });
52
53 it("anything else is fatal (a deterministic unknown failure is not worth a retry)", () => {
54 const e = classifyError(new Error("mupdf: cannot decode"));
55 expect(e).toBeInstanceOf(FatalError);
56 const c = classifyError(new Error("corrupt"));
57 expect(c).toBeInstanceOf(FatalError);
58 expect((c as FatalError).code).toBe("unclassified");
59 });
60});
61