Path: blob/main/src/vs/base/test/common/cancellation.test.ts
5259 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/4import assert from 'assert';5import { CancellationToken, CancellationTokenSource, CancellationTokenPool } from '../../common/cancellation.js';6import { ensureNoDisposablesAreLeakedInTestSuite } from './utils.js';78suite('CancellationToken', function () {910const store = ensureNoDisposablesAreLeakedInTestSuite();1112test('None', () => {13assert.strictEqual(CancellationToken.None.isCancellationRequested, false);14assert.strictEqual(typeof CancellationToken.None.onCancellationRequested, 'function');15});1617test('cancel before token', function () {1819const source = new CancellationTokenSource();20assert.strictEqual(source.token.isCancellationRequested, false);21source.cancel();2223assert.strictEqual(source.token.isCancellationRequested, true);2425return new Promise<void>(resolve => {26source.token.onCancellationRequested(() => resolve());27});28});2930test('cancel happens only once', function () {3132const source = new CancellationTokenSource();33assert.strictEqual(source.token.isCancellationRequested, false);3435let cancelCount = 0;36function onCancel() {37cancelCount += 1;38}3940store.add(source.token.onCancellationRequested(onCancel));4142source.cancel();43source.cancel();4445assert.strictEqual(cancelCount, 1);46});4748test('cancel calls all listeners', function () {4950let count = 0;5152const source = new CancellationTokenSource();53store.add(source.token.onCancellationRequested(() => count++));54store.add(source.token.onCancellationRequested(() => count++));55store.add(source.token.onCancellationRequested(() => count++));5657source.cancel();58assert.strictEqual(count, 3);59});6061test('token stays the same', function () {6263let source = new CancellationTokenSource();64let token = source.token;65assert.ok(token === source.token); // doesn't change on get6667source.cancel();68assert.ok(token === source.token); // doesn't change after cancel6970source.cancel();71assert.ok(token === source.token); // doesn't change after 2nd cancel7273source = new CancellationTokenSource();74source.cancel();75token = source.token;76assert.ok(token === source.token); // doesn't change on get77});7879test('dispose calls no listeners', function () {8081let count = 0;8283const source = new CancellationTokenSource();84store.add(source.token.onCancellationRequested(() => count++));8586source.dispose();87source.cancel();88assert.strictEqual(count, 0);89});9091test('dispose calls no listeners (unless told to cancel)', function () {9293let count = 0;9495const source = new CancellationTokenSource();96store.add(source.token.onCancellationRequested(() => count++));9798source.dispose(true);99// source.cancel();100assert.strictEqual(count, 1);101});102103test('dispose does not cancel', function () {104const source = new CancellationTokenSource();105source.dispose();106assert.strictEqual(source.token.isCancellationRequested, false);107});108109test('parent cancels child', function () {110111const parent = new CancellationTokenSource();112const child = new CancellationTokenSource(parent.token);113114let count = 0;115store.add(child.token.onCancellationRequested(() => count++));116117parent.cancel();118119assert.strictEqual(count, 1);120assert.strictEqual(child.token.isCancellationRequested, true);121assert.strictEqual(parent.token.isCancellationRequested, true);122123child.dispose();124parent.dispose();125});126});127128suite('CancellationTokenPool', function () {129130const store = ensureNoDisposablesAreLeakedInTestSuite();131132test('empty pool token is not cancelled', function () {133const pool = new CancellationTokenPool();134store.add(pool);135136assert.strictEqual(pool.token.isCancellationRequested, false);137});138139test('pool token cancels when all tokens are cancelled', function () {140const pool = new CancellationTokenPool();141store.add(pool);142143const source1 = new CancellationTokenSource();144const source2 = new CancellationTokenSource();145const source3 = new CancellationTokenSource();146147pool.add(source1.token);148pool.add(source2.token);149pool.add(source3.token);150151assert.strictEqual(pool.token.isCancellationRequested, false);152153source1.cancel();154assert.strictEqual(pool.token.isCancellationRequested, false);155156source2.cancel();157assert.strictEqual(pool.token.isCancellationRequested, false);158159source3.cancel();160assert.strictEqual(pool.token.isCancellationRequested, true);161162source1.dispose();163source2.dispose();164source3.dispose();165});166167test('pool token fires cancellation event when all tokens are cancelled', function () {168return new Promise<void>(resolve => {169const pool = new CancellationTokenPool();170store.add(pool);171172const source1 = new CancellationTokenSource();173const source2 = new CancellationTokenSource();174175pool.add(source1.token);176pool.add(source2.token);177178store.add(pool.token.onCancellationRequested(() => resolve()));179180source1.cancel();181source2.cancel();182183source1.dispose();184source2.dispose();185});186});187188test('adding already cancelled token counts immediately', function () {189const pool = new CancellationTokenPool();190store.add(pool);191192const source1 = new CancellationTokenSource();193const source2 = new CancellationTokenSource();194195source1.cancel(); // Cancel before adding to pool196197pool.add(source1.token);198assert.strictEqual(pool.token.isCancellationRequested, true); // 1 of 1 cancelled, so pool is cancelled199200pool.add(source2.token); // Adding after pool is done should have no effect201assert.strictEqual(pool.token.isCancellationRequested, true);202203source2.cancel(); // This should have no effect since pool is already done204assert.strictEqual(pool.token.isCancellationRequested, true);205206source1.dispose();207source2.dispose();208});209210test('adding single already cancelled token cancels pool immediately', function () {211const pool = new CancellationTokenPool();212store.add(pool);213214const source = new CancellationTokenSource();215source.cancel();216217pool.add(source.token);218assert.strictEqual(pool.token.isCancellationRequested, true); // 1 of 1 cancelled219220source.dispose();221});222223test('adding token after pool is done has no effect', function () {224const pool = new CancellationTokenPool();225store.add(pool);226227const source1 = new CancellationTokenSource();228const source2 = new CancellationTokenSource();229230pool.add(source1.token);231source1.cancel(); // Pool should be done now232233assert.strictEqual(pool.token.isCancellationRequested, true);234235// Adding another token should have no effect236pool.add(source2.token);237source2.cancel();238239assert.strictEqual(pool.token.isCancellationRequested, true);240241source1.dispose();242source2.dispose();243});244245test('single token pool behaviour', function () {246const pool = new CancellationTokenPool();247store.add(pool);248249const source = new CancellationTokenSource();250pool.add(source.token);251252assert.strictEqual(pool.token.isCancellationRequested, false);253254source.cancel();255assert.strictEqual(pool.token.isCancellationRequested, true);256257source.dispose();258});259260test('pool with only cancelled tokens', function () {261const pool = new CancellationTokenPool();262store.add(pool);263264const source1 = new CancellationTokenSource();265const source2 = new CancellationTokenSource();266267source1.cancel();268source2.cancel();269270pool.add(source1.token);271pool.add(source2.token);272273assert.strictEqual(pool.token.isCancellationRequested, true);274275source1.dispose();276source2.dispose();277});278});279280281