API to suspend/resume tasks with timeout

This commit is contained in:
Fedor Indutny
2021-09-27 11:22:46 -07:00
committed by GitHub
parent cf4c81b11c
commit af387095be
4 changed files with 205 additions and 104 deletions

View File

@@ -2,14 +2,28 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { assert } from 'chai';
import * as sinon from 'sinon';
import { sleep } from '../util/sleep';
import createTaskWithTimeout from '../textsecure/TaskWithTimeout';
import createTaskWithTimeout, {
suspendTasksWithTimeout,
resumeTasksWithTimeout,
} from '../textsecure/TaskWithTimeout';
describe('createTaskWithTimeout', () => {
let sandbox: sinon.SinonSandbox;
beforeEach(() => {
sandbox = sinon.createSandbox();
});
afterEach(() => {
sandbox.restore();
});
it('resolves when promise resolves', async () => {
const task = () => Promise.resolve('hi!');
const taskWithTimeout = createTaskWithTimeout(task, 'test');
const taskWithTimeout = createTaskWithTimeout(task, 'resolving-task');
const result = await taskWithTimeout();
assert.strictEqual(result, 'hi!');
@@ -18,38 +32,105 @@ describe('createTaskWithTimeout', () => {
it('flows error from promise back', async () => {
const error = new Error('original');
const task = () => Promise.reject(error);
const taskWithTimeout = createTaskWithTimeout(task, 'test');
const taskWithTimeout = createTaskWithTimeout(task, 'rejecting-task');
await assert.isRejected(taskWithTimeout(), 'original');
});
it('rejects if promise takes too long (this one logs error to console)', async () => {
const task = async () => {
await sleep(3000);
};
const taskWithTimeout = createTaskWithTimeout(task, 'test', {
timeout: 10,
});
const clock = sandbox.useFakeTimers();
await assert.isRejected(taskWithTimeout());
const task = async () => {
await sleep(3000000);
};
const taskWithTimeout = createTaskWithTimeout(task, 'slow-task');
const promise = assert.isRejected(taskWithTimeout());
await clock.nextAsync();
await clock.nextAsync();
await promise;
});
it('rejects if task throws (and does not log about taking too long)', async () => {
const clock = sandbox.useFakeTimers();
const error = new Error('Task is throwing!');
const task = () => {
throw error;
};
const taskWithTimeout = createTaskWithTimeout(task, 'test', {
timeout: 10,
});
const taskWithTimeout = createTaskWithTimeout(task, 'throwing-task');
await clock.nextAsync();
await assert.isRejected(taskWithTimeout(), 'Task is throwing!');
});
it('passes arguments to the underlying function', async () => {
const task = (arg: string) => Promise.resolve(arg);
const taskWithTimeout = createTaskWithTimeout(task, 'test');
const taskWithTimeout = createTaskWithTimeout(task, 'arguments-task');
const result = await taskWithTimeout('hi!');
assert.strictEqual(result, 'hi!');
});
it('suspends and resumes tasks', async () => {
const clock = sandbox.useFakeTimers();
let state = 0;
const task = async () => {
state = 1;
await sleep(900);
state = 2;
await sleep(900);
state = 3;
};
const taskWithTimeout = createTaskWithTimeout(task, 'suspend-task', {
timeout: 1000,
});
const promise = taskWithTimeout();
assert.strictEqual(state, 1);
suspendTasksWithTimeout();
await clock.nextAsync();
assert.strictEqual(state, 2);
resumeTasksWithTimeout();
await clock.nextAsync();
assert.strictEqual(state, 3);
await promise;
});
it('suspends and resumes timing out task', async () => {
const clock = sandbox.useFakeTimers();
let state = 0;
const task = async () => {
state = 1;
await sleep(3000000);
state = 2;
await sleep(3000000);
state = 3;
};
const taskWithTimeout = createTaskWithTimeout(task, 'suspend-slow-task');
const promise = assert.isRejected(taskWithTimeout());
assert.strictEqual(state, 1);
suspendTasksWithTimeout();
await clock.nextAsync();
assert.strictEqual(state, 2);
resumeTasksWithTimeout();
await clock.nextAsync();
assert.strictEqual(state, 2);
await promise;
});
});