Files
suaveplan/packages/persistence/storage/storage-uri-plugin-fallback/src/classify/classify.test.ts
2026-05-27 23:47:53 +01:00

123 lines
3.8 KiB
TypeScript

import { SuaveplanError } from "@suaveplan/error";
import { describe, expect, it } from "@suaveplan/testing/runner";
import {
FALLBACK_URI_CODES,
FallbackUriError,
} from "../error-codes/error-codes.js";
import { FallbackPolicySchema } from "../types/policy.schemas.js";
import type { FallbackPolicy } from "../types/policy.types.js";
import { classify } from "./classify.js";
const POLICY: FallbackPolicy = FallbackPolicySchema.parse({});
const ANY_POLICY: FallbackPolicy = FallbackPolicySchema.parse({
errorClass: "any",
});
class TestErr extends SuaveplanError<string> {
public constructor(code: string) {
super(code, "test");
}
}
describe("classify", () => {
it("classifies NOT_FOUND as fall-through-eligible", {
timeout: 5000,
}, () => {
expect(classify(new TestErr("STORAGE_URI.NOT_FOUND"), POLICY)).toBe(
"transient"
);
});
it("classifies UNKNOWN_SCHEME as semantic under default", {
timeout: 5000,
}, () => {
expect(
classify(new TestErr("STORAGE_URI.UNKNOWN_SCHEME"), POLICY)
).toBe("semantic");
});
it("classifies UNKNOWN_SCHEME as transient under errorClass=any", {
timeout: 5000,
}, () => {
expect(
classify(new TestErr("STORAGE_URI.UNKNOWN_SCHEME"), ANY_POLICY)
).toBe("transient");
});
it("treats MAX_DEPTH_EXCEEDED as semantic regardless of policy", {
timeout: 5000,
}, () => {
const err = new FallbackUriError(
FALLBACK_URI_CODES.MAX_DEPTH_EXCEEDED,
"x"
);
expect(classify(err, POLICY)).toBe("semantic");
expect(classify(err, ANY_POLICY)).toBe("semantic");
});
it("treats CIRCULAR_REFERENCE as semantic regardless of policy", {
timeout: 5000,
}, () => {
const err = new FallbackUriError(
FALLBACK_URI_CODES.CIRCULAR_REFERENCE,
"x"
);
expect(classify(err, ANY_POLICY)).toBe("semantic");
});
it("classifies ABORTED codes as abort", { timeout: 5000 }, () => {
expect(
classify(
new FallbackUriError(FALLBACK_URI_CODES.ABORTED, "x"),
POLICY
)
).toBe("abort");
expect(classify(new TestErr("STORAGE_URI.ABORTED"), POLICY)).toBe(
"abort"
);
});
it("classifies ADAPTER_ERROR as transient", { timeout: 5000 }, () => {
expect(classify(new TestErr("STORAGE_URI.ADAPTER_ERROR"), POLICY)).toBe(
"transient"
);
});
it("classifies generic semantic codes as semantic", {
timeout: 5000,
}, () => {
expect(classify(new TestErr("STORAGE_URI.INVALID_URI"), POLICY)).toBe(
"semantic"
);
expect(
classify(new TestErr("STORAGE_URI.WRITE_UNSUPPORTED"), POLICY)
).toBe("semantic");
expect(
classify(new TestErr("STORAGE_URI.LIST_UNSUPPORTED"), POLICY)
).toBe("semantic");
expect(
classify(new TestErr("STORAGE_URI.SCHEME_CONFLICT"), POLICY)
).toBe("semantic");
});
it("classifies unknown namespaced codes per policy", {
timeout: 5000,
}, () => {
expect(classify(new TestErr("FOO.BAR"), POLICY)).toBe("semantic");
expect(classify(new TestErr("FOO.BAR"), ANY_POLICY)).toBe("transient");
});
it("classifies AbortError name as abort", { timeout: 5000 }, () => {
const e = new Error("aborted");
e.name = "AbortError";
expect(classify(e, POLICY)).toBe("abort");
});
it("classifies unknown thrown values as transient", {
timeout: 5000,
}, () => {
expect(classify("boom", POLICY)).toBe("transient");
expect(classify(new Error("plain"), POLICY)).toBe("transient");
});
});