Add failing tests for the download retry policy
Tests only; the retry module they import does not exist yet, so the branch is red at this commit. New test/retry/retry.test.ts documents the classifier and the backoff: which errors are worth another attempt, which are not, and how the delay before each retry is derived. It asserts on the arguments handed to an injected sleep function rather than on elapsed time, so the suite never waits and the numbers are exact. test/api/client.test.ts gains the request-count contract for each of the six call sites, the deadline behaviour, the ApiError typing that the presigned PUT and the null-body paths need in order to be classified at all, and the replay rule for the two non-idempotent methods. test/download/download.test.ts gains the case that motivates the whole design: a socket reset after the response headers arrived, which happens below ApiClient and can only be caught by retrying the request, the stream consumption and the decryption together. It also pins that a retried download stages exactly one temp file, and that the two retry layers do not compose into a multiplied request budget. The existing truncation tests now assert on the error type rather than its wording, since that type is what the classifier reads. test/thumbnails/thumbnails.test.ts separates a genuine 404 from an exhausted retry, so a failing server can no longer make fix-missing-thumbnails re-upload thumbnails that already exist.
This commit is contained in:
@@ -411,11 +411,22 @@ describe("quak backup", () => {
|
||||
// File 101 (sunset.jpg) will return HTTP 500. The other two
|
||||
// files must still download. The result must report the failure
|
||||
// without throwing.
|
||||
//
|
||||
// A 500 is retryable, so this file now costs several requests before
|
||||
// it is given up on — that is the point of the retry policy, and
|
||||
// `runBackup`'s own resilience is unchanged by it: the retry lives
|
||||
// strictly below this loop, and an exhausted file is still logged,
|
||||
// counted, and stepped over rather than aborting the run. The
|
||||
// injected `sleep` is what keeps the suite from actually waiting out
|
||||
// the backoff.
|
||||
const outDir = join(testDir, "partial-failure");
|
||||
const client = await Client.login({
|
||||
email: TEST_EMAIL,
|
||||
password: TEST_PASSWORD,
|
||||
apiOptions: { fetch: buildMockFetch(mock, { failFileID: 101 }) },
|
||||
apiOptions: {
|
||||
fetch: buildMockFetch(mock, { failFileID: 101 }),
|
||||
retry: { sleep: () => Promise.resolve(), random: () => 0 },
|
||||
},
|
||||
});
|
||||
|
||||
const result = await runBackup(client, outDir);
|
||||
|
||||
Reference in New Issue
Block a user