A network failure is printed and recorded with its reason (closes #196)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
Node's `fetch` rejects every failure below HTTP as `fetch failed` and puts the reason on `cause`, so quak printed and recorded only that, and `failures.json` called the failure `unknown`. `describeError` in `src/errors.ts` gives the message followed by the messages on the cause chain; `run` prints it, and the backup logs and records it. `classify` calls a failure transient when `hasTransportCode`, now exported by `src/retry.ts`, finds a transport errno on the chain. The bounded walk along the chain moved from `src/retry.ts` to `src/errors.ts`, so both use one walk. Every message the backup logs or records, `imageMetadataError` and `mlDataError` included, now carries its causes too. Model: opus-5-5
This commit is contained in:
@@ -48,6 +48,35 @@ describe("run", () => {
|
||||
);
|
||||
});
|
||||
|
||||
// Node's `fetch` rejects every failure below HTTP with a TypeError that
|
||||
// says only "fetch failed", and hangs the reason, with its errno, off
|
||||
// `cause`. The printed line carries the reason, so a cron log tells a
|
||||
// refused connection from a name that did not resolve.
|
||||
it("prints the reason a fetch failed, from the error's cause", async () => {
|
||||
const refused = new TypeError("fetch failed", {
|
||||
cause: Object.assign(
|
||||
new Error("connect ECONNREFUSED 1.2.3.4:443"),
|
||||
{ code: "ECONNREFUSED" },
|
||||
),
|
||||
});
|
||||
const result = await runToExit(Promise.reject(refused));
|
||||
expect(result).toEqual({
|
||||
code: 1,
|
||||
stdout: "",
|
||||
stderr: "quak: fetch failed: connect ECONNREFUSED 1.2.3.4:443\n",
|
||||
});
|
||||
});
|
||||
|
||||
// An error that already quotes its cause's message is printed as it is.
|
||||
it("does not print a cause's message twice", async () => {
|
||||
const reset = new Error("read ECONNRESET");
|
||||
const wrapped = new Error(`download: file 7: ${reset.message}`, {
|
||||
cause: reset,
|
||||
});
|
||||
const result = await runToExit(Promise.reject(wrapped));
|
||||
expect(result.stderr).toBe("quak: download: file 7: read ECONNRESET\n");
|
||||
});
|
||||
|
||||
it("prints a thrown value that is not an Error", async () => {
|
||||
const result = await runToExit(Promise.reject("offline"));
|
||||
expect(result).toEqual({
|
||||
|
||||
Reference in New Issue
Block a user