2024-01-01 21:11:32 +00:00
|
|
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
2023-10-25 05:06:35 +00:00
|
|
|
import { retry, RetryError } from "./retry.ts";
|
2024-04-29 02:57:30 +00:00
|
|
|
import { assertEquals, assertRejects } from "@std/assert";
|
|
|
|
import { FakeTime } from "@std/testing/time";
|
2022-11-30 18:45:25 +00:00
|
|
|
|
|
|
|
function generateErroringFunction(errorsBeforeSucceeds: number) {
|
|
|
|
let errorCount = 0;
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
if (errorCount >= errorsBeforeSucceeds) {
|
|
|
|
return errorCount;
|
|
|
|
}
|
|
|
|
errorCount++;
|
|
|
|
throw `Only errored ${errorCount} times`;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-04-11 21:23:54 +00:00
|
|
|
Deno.test("retry()", async () => {
|
2022-11-30 18:45:25 +00:00
|
|
|
const threeErrors = generateErroringFunction(3);
|
|
|
|
const result = await retry(threeErrors, {
|
|
|
|
minTimeout: 100,
|
|
|
|
});
|
2023-05-20 12:14:18 +00:00
|
|
|
assertEquals(result, 3);
|
2022-11-30 18:45:25 +00:00
|
|
|
});
|
|
|
|
|
2024-09-03 08:57:27 +00:00
|
|
|
Deno.test("retry() fails after five errors by default", async () => {
|
2022-11-30 18:45:25 +00:00
|
|
|
const fiveErrors = generateErroringFunction(5);
|
|
|
|
await assertRejects(() =>
|
|
|
|
retry(fiveErrors, {
|
|
|
|
minTimeout: 100,
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2024-09-03 08:57:27 +00:00
|
|
|
Deno.test("retry() fails after five errors when undefined is passed", async () => {
|
|
|
|
const fiveErrors = generateErroringFunction(5);
|
|
|
|
await assertRejects(() =>
|
refactor(archive,async,cli,csv,dotenv,encoding,expect,fmt,front-matter,fs,http,internal,log,net,path,semver,testing,text,webgpu,yaml): enable `"exactOptionalPropertyTypes"` option (#5892)
2024-09-04 05:15:01 +00:00
|
|
|
// @ts-expect-error: explicitly giving undefined
|
2024-09-03 08:57:27 +00:00
|
|
|
retry(fiveErrors, {
|
|
|
|
maxAttempts: undefined,
|
|
|
|
minTimeout: 100,
|
|
|
|
})
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2024-04-11 21:23:54 +00:00
|
|
|
Deno.test("retry() waits four times by default", async () => {
|
2023-06-07 10:46:00 +00:00
|
|
|
let callCount = 0;
|
|
|
|
const onlyErrors = function () {
|
|
|
|
callCount++;
|
|
|
|
throw new Error("Failure");
|
|
|
|
};
|
2023-12-14 20:47:50 +00:00
|
|
|
using time = new FakeTime();
|
2023-06-07 10:46:00 +00:00
|
|
|
const callCounts: Array<number> = [];
|
2023-12-14 20:47:50 +00:00
|
|
|
const promise = retry(onlyErrors);
|
|
|
|
queueMicrotask(() => callCounts.push(callCount));
|
|
|
|
await time.next();
|
|
|
|
queueMicrotask(() => callCounts.push(callCount));
|
|
|
|
await time.next();
|
|
|
|
queueMicrotask(() => callCounts.push(callCount));
|
|
|
|
await time.next();
|
|
|
|
queueMicrotask(() => callCounts.push(callCount));
|
|
|
|
await time.next();
|
|
|
|
queueMicrotask(() => callCounts.push(callCount));
|
|
|
|
await assertRejects(() => promise, RetryError);
|
|
|
|
assertEquals(callCounts, [1, 2, 3, 4, 5]);
|
2023-06-07 10:46:00 +00:00
|
|
|
});
|
|
|
|
|
2023-05-20 12:14:18 +00:00
|
|
|
Deno.test(
|
2023-12-18 22:29:13 +00:00
|
|
|
"retry() throws if minTimeout is less than maxTimeout",
|
2024-04-11 21:23:54 +00:00
|
|
|
async () => {
|
2024-06-05 01:13:11 +00:00
|
|
|
await assertRejects(
|
|
|
|
() =>
|
|
|
|
retry(() => {}, {
|
|
|
|
minTimeout: 1000,
|
|
|
|
maxTimeout: 100,
|
|
|
|
}),
|
|
|
|
TypeError,
|
2024-08-22 06:02:58 +00:00
|
|
|
"Cannot retry as 'minTimeout' must be <= 'maxTimeout': current values 'minTimeout=1000', 'maxTimeout=100'",
|
2023-05-20 12:14:18 +00:00
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
Deno.test(
|
2023-12-18 22:29:13 +00:00
|
|
|
"retry() throws if maxTimeout is less than 0",
|
2024-04-11 21:23:54 +00:00
|
|
|
async () => {
|
2024-06-05 01:13:11 +00:00
|
|
|
await assertRejects(
|
|
|
|
() =>
|
|
|
|
retry(() => {}, {
|
|
|
|
maxTimeout: -1,
|
|
|
|
}),
|
|
|
|
TypeError,
|
2024-08-22 06:02:58 +00:00
|
|
|
"Cannot retry as 'maxTimeout' must be positive: current value is -1",
|
2023-05-20 12:14:18 +00:00
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
2023-06-07 10:46:00 +00:00
|
|
|
Deno.test(
|
2023-12-18 22:29:13 +00:00
|
|
|
"retry() throws if jitter is bigger than 1",
|
2024-04-11 21:23:54 +00:00
|
|
|
async () => {
|
2024-06-05 01:13:11 +00:00
|
|
|
await assertRejects(
|
|
|
|
() =>
|
|
|
|
retry(() => {}, {
|
|
|
|
jitter: 2,
|
|
|
|
}),
|
|
|
|
TypeError,
|
2024-08-22 06:02:58 +00:00
|
|
|
"Cannot retry as 'jitter' must be <= 1: current value is 2",
|
2023-06-07 10:46:00 +00:00
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
2023-12-18 22:29:13 +00:00
|
|
|
Deno.test("retry() checks backoff function timings", async (t) => {
|
2023-05-20 12:14:18 +00:00
|
|
|
const originalMathRandom = Math.random;
|
|
|
|
|
2024-04-11 21:23:54 +00:00
|
|
|
await t.step("wait fixed times without jitter", async () => {
|
2023-12-14 20:47:50 +00:00
|
|
|
using time = new FakeTime();
|
2023-06-07 10:46:00 +00:00
|
|
|
let resolved = false;
|
|
|
|
const checkResolved = async () => {
|
|
|
|
try {
|
|
|
|
await retry(() => {
|
|
|
|
throw new Error("Failure");
|
|
|
|
}, { jitter: 0 });
|
|
|
|
} catch {
|
|
|
|
resolved = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-12-14 20:47:50 +00:00
|
|
|
const promise = checkResolved();
|
|
|
|
const startTime = time.now;
|
2023-06-07 10:46:00 +00:00
|
|
|
|
2023-12-14 20:47:50 +00:00
|
|
|
await time.nextAsync();
|
|
|
|
assertEquals(time.now - startTime, 1000);
|
2023-06-07 10:46:00 +00:00
|
|
|
|
2023-12-14 20:47:50 +00:00
|
|
|
await time.nextAsync();
|
|
|
|
assertEquals(time.now - startTime, 3000);
|
2023-06-07 10:46:00 +00:00
|
|
|
|
2023-12-14 20:47:50 +00:00
|
|
|
await time.nextAsync();
|
|
|
|
assertEquals(time.now - startTime, 7000);
|
2023-06-07 10:46:00 +00:00
|
|
|
|
2023-12-14 20:47:50 +00:00
|
|
|
await time.nextAsync();
|
|
|
|
assertEquals(time.now - startTime, 15000);
|
|
|
|
assertEquals(resolved, false);
|
2023-06-07 10:46:00 +00:00
|
|
|
|
2023-12-14 20:47:50 +00:00
|
|
|
await time.runMicrotasks();
|
|
|
|
assertEquals(time.now - startTime, 15000);
|
|
|
|
assertEquals(resolved, true);
|
|
|
|
|
|
|
|
await time.runAllAsync();
|
|
|
|
assertEquals(time.now - startTime, 15000);
|
|
|
|
await promise;
|
2023-06-07 10:46:00 +00:00
|
|
|
});
|
|
|
|
|
2023-05-20 12:14:18 +00:00
|
|
|
Math.random = originalMathRandom;
|
2022-11-30 18:45:25 +00:00
|
|
|
});
|