summaryrefslogtreecommitdiffstats
path: root/polygerrit-ui/app/services/scheduler/retry-scheduler_test.ts
diff options
context:
space:
mode:
Diffstat (limited to 'polygerrit-ui/app/services/scheduler/retry-scheduler_test.ts')
-rw-r--r--polygerrit-ui/app/services/scheduler/retry-scheduler_test.ts122
1 files changed, 122 insertions, 0 deletions
diff --git a/polygerrit-ui/app/services/scheduler/retry-scheduler_test.ts b/polygerrit-ui/app/services/scheduler/retry-scheduler_test.ts
new file mode 100644
index 0000000000..988b167071
--- /dev/null
+++ b/polygerrit-ui/app/services/scheduler/retry-scheduler_test.ts
@@ -0,0 +1,122 @@
+/**
+ * @license
+ * Copyright 2022 Google LLC
+ * SPDX-License-Identifier: Apache-2.0
+ */
+import '../../test/common-test-setup-karma.js';
+import {assertFails} from '../../test/test-utils.js';
+import {Scheduler} from './scheduler';
+import {RetryScheduler, RetryError} from './retry-scheduler';
+import {FakeScheduler} from './fake-scheduler';
+import {SinonFakeTimers} from 'sinon';
+
+suite('retry scheduler', () => {
+ let clock: SinonFakeTimers;
+ let fakeScheduler: FakeScheduler<number>;
+ let scheduler: Scheduler<number>;
+ setup(() => {
+ clock = sinon.useFakeTimers();
+ fakeScheduler = new FakeScheduler<number>();
+ scheduler = new RetryScheduler<number>(fakeScheduler, 3, 50, 1);
+ });
+
+ async function waitForRetry(ms: number) {
+ // Flush the promise so that we can reach untilTimeout
+ await flush();
+ // Advance the clock.
+ clock.tick(ms);
+ // Flush the promise that waits for the clock.
+ await flush();
+ }
+
+ test('executes tasks', async () => {
+ const promise = scheduler.schedule(async () => 1);
+ assert.equal(fakeScheduler.scheduled.length, 1);
+ fakeScheduler.resolve();
+ assert.equal(fakeScheduler.scheduled.length, 0);
+ const val = await promise;
+ assert.equal(val, 1);
+ });
+
+ test('propagates task errors', async () => {
+ const error = new Error('This is an error');
+ const promise = scheduler.schedule(async () => {
+ throw error;
+ });
+ assert.equal(fakeScheduler.scheduled.length, 1);
+ assertFails(promise, error);
+ fakeScheduler.resolve();
+ assert.equal(fakeScheduler.scheduled.length, 0);
+ await promise.catch((reason: Error) => {
+ assert.equal(reason, error);
+ });
+ });
+
+ test('propagates subscheduler errors', async () => {
+ const error = new Error('This is an error');
+ const promise = scheduler.schedule(async () => 1);
+ assert.equal(fakeScheduler.scheduled.length, 1);
+ assertFails(promise, error);
+ fakeScheduler.reject(error);
+ assert.equal(fakeScheduler.scheduled.length, 0);
+ await promise.catch((reason: Error) => {
+ assert.equal(reason, error);
+ });
+ });
+
+ test('retries on retryable error', async () => {
+ let retries = 1;
+ const promise = scheduler.schedule(async () => {
+ if (retries-- > 0) throw new RetryError('Retrying');
+ return 1;
+ });
+ assert.equal(fakeScheduler.scheduled.length, 1);
+ fakeScheduler.resolve();
+ assert.equal(fakeScheduler.scheduled.length, 0);
+ await waitForRetry(50);
+ assert.equal(fakeScheduler.scheduled.length, 1);
+ fakeScheduler.resolve();
+ const val = await promise;
+ assert.equal(val, 1);
+ });
+
+ test('retries up to 3 times', async () => {
+ let retries = 3;
+ const promise = scheduler.schedule(async () => {
+ if (retries-- > 0) throw new RetryError('Retrying');
+ return 1;
+ });
+ assert.equal(fakeScheduler.scheduled.length, 1);
+ for (let i = 0; i < 3; i++) {
+ fakeScheduler.resolve();
+ assert.equal(fakeScheduler.scheduled.length, 0);
+ await waitForRetry(50);
+ assert.equal(fakeScheduler.scheduled.length, 1);
+ }
+ fakeScheduler.resolve();
+ const val = await promise;
+ assert.equal(val, 1);
+ });
+
+ test('fails after more than 3 times', async () => {
+ let retries = 4;
+ const promise = scheduler.schedule(async () => {
+ if (retries-- > 0) throw new RetryError(retries, `Retrying ${retries}`);
+ return 1;
+ });
+ assert.equal(fakeScheduler.scheduled.length, 1);
+ for (let i = 0; i < 3; i++) {
+ fakeScheduler.resolve();
+ assert.equal(fakeScheduler.scheduled.length, 0);
+ await waitForRetry(50);
+ assert.equal(fakeScheduler.scheduled.length, 1);
+ }
+ fakeScheduler.resolve();
+ assertFails(promise);
+ // The error we get back should be the last error.
+ await promise.catch((reason: RetryError<number>) => {
+ assert.equal(reason.payload, 0);
+ assert.equal(reason.message, 'Retrying 0');
+ });
+ });
+});