11cb0ef41Sopenharmony_ci// Flags: --no-warnings --expose-internals 21cb0ef41Sopenharmony_ci'use strict'; 31cb0ef41Sopenharmony_ciconst common = require('../common'); 41cb0ef41Sopenharmony_ciconst assert = require('assert'); 51cb0ef41Sopenharmony_ciconst timers = require('timers'); 61cb0ef41Sopenharmony_ciconst { promisify } = require('util'); 71cb0ef41Sopenharmony_ciconst child_process = require('child_process'); 81cb0ef41Sopenharmony_ci 91cb0ef41Sopenharmony_ciconst { getEventListeners } = require('events'); 101cb0ef41Sopenharmony_ciconst { NodeEventTarget } = require('internal/event_target'); 111cb0ef41Sopenharmony_ci 121cb0ef41Sopenharmony_ciconst timerPromises = require('timers/promises'); 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_ciconst setPromiseTimeout = promisify(timers.setTimeout); 151cb0ef41Sopenharmony_ciconst exec = promisify(child_process.exec); 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ciconst { setInterval } = timerPromises; 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ciprocess.on('multipleResolves', common.mustNotCall()); 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci{ 221cb0ef41Sopenharmony_ci const iterable = setInterval(1, undefined); 231cb0ef41Sopenharmony_ci const iterator = iterable[Symbol.asyncIterator](); 241cb0ef41Sopenharmony_ci const promise = iterator.next(); 251cb0ef41Sopenharmony_ci promise.then(common.mustCall((result) => { 261cb0ef41Sopenharmony_ci assert.ok(!result.done, 'iterator was wrongly marked as done'); 271cb0ef41Sopenharmony_ci assert.strictEqual(result.value, undefined); 281cb0ef41Sopenharmony_ci return iterator.return(); 291cb0ef41Sopenharmony_ci })).then(common.mustCall()); 301cb0ef41Sopenharmony_ci} 311cb0ef41Sopenharmony_ci 321cb0ef41Sopenharmony_ci{ 331cb0ef41Sopenharmony_ci const iterable = setInterval(1, 'foobar'); 341cb0ef41Sopenharmony_ci const iterator = iterable[Symbol.asyncIterator](); 351cb0ef41Sopenharmony_ci const promise = iterator.next(); 361cb0ef41Sopenharmony_ci promise.then(common.mustCall((result) => { 371cb0ef41Sopenharmony_ci assert.ok(!result.done, 'iterator was wronly marked as done'); 381cb0ef41Sopenharmony_ci assert.strictEqual(result.value, 'foobar'); 391cb0ef41Sopenharmony_ci return iterator.return(); 401cb0ef41Sopenharmony_ci })).then(common.mustCall()); 411cb0ef41Sopenharmony_ci} 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci{ 441cb0ef41Sopenharmony_ci const iterable = setInterval(1, 'foobar'); 451cb0ef41Sopenharmony_ci const iterator = iterable[Symbol.asyncIterator](); 461cb0ef41Sopenharmony_ci const promise = iterator.next(); 471cb0ef41Sopenharmony_ci promise 481cb0ef41Sopenharmony_ci .then(common.mustCall((result) => { 491cb0ef41Sopenharmony_ci assert.ok(!result.done, 'iterator was wronly marked as done'); 501cb0ef41Sopenharmony_ci assert.strictEqual(result.value, 'foobar'); 511cb0ef41Sopenharmony_ci return iterator.next(); 521cb0ef41Sopenharmony_ci })) 531cb0ef41Sopenharmony_ci .then(common.mustCall((result) => { 541cb0ef41Sopenharmony_ci assert.ok(!result.done, 'iterator was wrongly marked as done'); 551cb0ef41Sopenharmony_ci assert.strictEqual(result.value, 'foobar'); 561cb0ef41Sopenharmony_ci return iterator.return(); 571cb0ef41Sopenharmony_ci })) 581cb0ef41Sopenharmony_ci .then(common.mustCall()); 591cb0ef41Sopenharmony_ci} 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci{ 621cb0ef41Sopenharmony_ci const signal = AbortSignal.abort(); // Abort in advance 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ci const iterable = setInterval(1, undefined, { signal }); 651cb0ef41Sopenharmony_ci const iterator = iterable[Symbol.asyncIterator](); 661cb0ef41Sopenharmony_ci assert.rejects(iterator.next(), /AbortError/).then(common.mustCall()); 671cb0ef41Sopenharmony_ci} 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci{ 701cb0ef41Sopenharmony_ci const ac = new AbortController(); 711cb0ef41Sopenharmony_ci const { signal } = ac; 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci const iterable = setInterval(100, undefined, { signal }); 741cb0ef41Sopenharmony_ci const iterator = iterable[Symbol.asyncIterator](); 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci // This promise should take 100 seconds to resolve, so now aborting it should 771cb0ef41Sopenharmony_ci // mean we abort early 781cb0ef41Sopenharmony_ci const promise = iterator.next(); 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_ci ac.abort(); // Abort in after we have a next promise 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci assert.rejects(promise, /AbortError/).then(common.mustCall()); 831cb0ef41Sopenharmony_ci} 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci{ 861cb0ef41Sopenharmony_ci // Check aborting after getting a value. 871cb0ef41Sopenharmony_ci const ac = new AbortController(); 881cb0ef41Sopenharmony_ci const { signal } = ac; 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ci const iterable = setInterval(100, undefined, { signal }); 911cb0ef41Sopenharmony_ci const iterator = iterable[Symbol.asyncIterator](); 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_ci const promise = iterator.next(); 941cb0ef41Sopenharmony_ci const abortPromise = promise.then(common.mustCall(() => ac.abort())) 951cb0ef41Sopenharmony_ci .then(() => iterator.next()); 961cb0ef41Sopenharmony_ci assert.rejects(abortPromise, /AbortError/).then(common.mustCall()); 971cb0ef41Sopenharmony_ci} 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci{ 1001cb0ef41Sopenharmony_ci [1, '', Infinity, null, {}].forEach((ref) => { 1011cb0ef41Sopenharmony_ci const iterable = setInterval(10, undefined, { ref }); 1021cb0ef41Sopenharmony_ci assert.rejects(() => iterable[Symbol.asyncIterator]().next(), /ERR_INVALID_ARG_TYPE/) 1031cb0ef41Sopenharmony_ci .then(common.mustCall()); 1041cb0ef41Sopenharmony_ci }); 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci [1, '', Infinity, null, {}].forEach((signal) => { 1071cb0ef41Sopenharmony_ci const iterable = setInterval(10, undefined, { signal }); 1081cb0ef41Sopenharmony_ci assert.rejects(() => iterable[Symbol.asyncIterator]().next(), /ERR_INVALID_ARG_TYPE/) 1091cb0ef41Sopenharmony_ci .then(common.mustCall()); 1101cb0ef41Sopenharmony_ci }); 1111cb0ef41Sopenharmony_ci 1121cb0ef41Sopenharmony_ci [1, '', Infinity, null, true, false].forEach((options) => { 1131cb0ef41Sopenharmony_ci const iterable = setInterval(10, undefined, options); 1141cb0ef41Sopenharmony_ci assert.rejects(() => iterable[Symbol.asyncIterator]().next(), /ERR_INVALID_ARG_TYPE/) 1151cb0ef41Sopenharmony_ci .then(common.mustCall()); 1161cb0ef41Sopenharmony_ci }); 1171cb0ef41Sopenharmony_ci} 1181cb0ef41Sopenharmony_ci 1191cb0ef41Sopenharmony_ci{ 1201cb0ef41Sopenharmony_ci // Check that timer adding signals does not leak handlers 1211cb0ef41Sopenharmony_ci const signal = new NodeEventTarget(); 1221cb0ef41Sopenharmony_ci signal.aborted = false; 1231cb0ef41Sopenharmony_ci const iterator = setInterval(1, undefined, { signal }); 1241cb0ef41Sopenharmony_ci iterator.next().then(common.mustCall(() => { 1251cb0ef41Sopenharmony_ci assert.strictEqual(getEventListeners(signal, 'abort').length, 1); 1261cb0ef41Sopenharmony_ci iterator.return(); 1271cb0ef41Sopenharmony_ci })).finally(common.mustCall(() => { 1281cb0ef41Sopenharmony_ci assert.strictEqual(getEventListeners(signal, 'abort').length, 0); 1291cb0ef41Sopenharmony_ci })); 1301cb0ef41Sopenharmony_ci} 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ci{ 1331cb0ef41Sopenharmony_ci // Check that break removes the signal listener 1341cb0ef41Sopenharmony_ci const signal = new NodeEventTarget(); 1351cb0ef41Sopenharmony_ci signal.aborted = false; 1361cb0ef41Sopenharmony_ci async function tryBreak() { 1371cb0ef41Sopenharmony_ci const iterator = setInterval(10, undefined, { signal }); 1381cb0ef41Sopenharmony_ci let i = 0; 1391cb0ef41Sopenharmony_ci // eslint-disable-next-line no-unused-vars 1401cb0ef41Sopenharmony_ci for await (const _ of iterator) { 1411cb0ef41Sopenharmony_ci if (i === 0) { 1421cb0ef41Sopenharmony_ci assert.strictEqual(getEventListeners(signal, 'abort').length, 1); 1431cb0ef41Sopenharmony_ci } 1441cb0ef41Sopenharmony_ci i++; 1451cb0ef41Sopenharmony_ci if (i === 2) { 1461cb0ef41Sopenharmony_ci break; 1471cb0ef41Sopenharmony_ci } 1481cb0ef41Sopenharmony_ci } 1491cb0ef41Sopenharmony_ci assert.strictEqual(i, 2); 1501cb0ef41Sopenharmony_ci assert.strictEqual(getEventListeners(signal, 'abort').length, 0); 1511cb0ef41Sopenharmony_ci } 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ci tryBreak().then(common.mustCall()); 1541cb0ef41Sopenharmony_ci} 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci{ 1571cb0ef41Sopenharmony_ci exec(`${process.execPath} -pe "const assert = require('assert');` + 1581cb0ef41Sopenharmony_ci 'const interval = require(\'timers/promises\')' + 1591cb0ef41Sopenharmony_ci '.setInterval(1000, null, { ref: false });' + 1601cb0ef41Sopenharmony_ci 'interval[Symbol.asyncIterator]().next()' + 1611cb0ef41Sopenharmony_ci '.then(assert.fail)"').then(common.mustCall(({ stderr }) => { 1621cb0ef41Sopenharmony_ci assert.strictEqual(stderr, ''); 1631cb0ef41Sopenharmony_ci })); 1641cb0ef41Sopenharmony_ci} 1651cb0ef41Sopenharmony_ci 1661cb0ef41Sopenharmony_ci{ 1671cb0ef41Sopenharmony_ci async function runInterval(fn, intervalTime, signal) { 1681cb0ef41Sopenharmony_ci const input = 'foobar'; 1691cb0ef41Sopenharmony_ci const interval = setInterval(intervalTime, input, { signal }); 1701cb0ef41Sopenharmony_ci let iteration = 0; 1711cb0ef41Sopenharmony_ci for await (const value of interval) { 1721cb0ef41Sopenharmony_ci assert.strictEqual(value, input); 1731cb0ef41Sopenharmony_ci iteration++; 1741cb0ef41Sopenharmony_ci await fn(iteration); 1751cb0ef41Sopenharmony_ci } 1761cb0ef41Sopenharmony_ci } 1771cb0ef41Sopenharmony_ci 1781cb0ef41Sopenharmony_ci { 1791cb0ef41Sopenharmony_ci // Check that we call the correct amount of times. 1801cb0ef41Sopenharmony_ci const controller = new AbortController(); 1811cb0ef41Sopenharmony_ci const { signal } = controller; 1821cb0ef41Sopenharmony_ci 1831cb0ef41Sopenharmony_ci let loopCount = 0; 1841cb0ef41Sopenharmony_ci const delay = 20; 1851cb0ef41Sopenharmony_ci const timeoutLoop = runInterval(() => { 1861cb0ef41Sopenharmony_ci loopCount++; 1871cb0ef41Sopenharmony_ci if (loopCount === 5) controller.abort(); 1881cb0ef41Sopenharmony_ci if (loopCount > 5) throw new Error('ran too many times'); 1891cb0ef41Sopenharmony_ci }, delay, signal); 1901cb0ef41Sopenharmony_ci 1911cb0ef41Sopenharmony_ci assert.rejects(timeoutLoop, /AbortError/).then(common.mustCall(() => { 1921cb0ef41Sopenharmony_ci assert.strictEqual(loopCount, 5); 1931cb0ef41Sopenharmony_ci })); 1941cb0ef41Sopenharmony_ci } 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_ci { 1971cb0ef41Sopenharmony_ci // Check that if we abort when we have some unresolved callbacks, 1981cb0ef41Sopenharmony_ci // we actually call them. 1991cb0ef41Sopenharmony_ci const controller = new AbortController(); 2001cb0ef41Sopenharmony_ci const { signal } = controller; 2011cb0ef41Sopenharmony_ci const delay = 10; 2021cb0ef41Sopenharmony_ci let totalIterations = 0; 2031cb0ef41Sopenharmony_ci const timeoutLoop = runInterval(async (iterationNumber) => { 2041cb0ef41Sopenharmony_ci await setPromiseTimeout(delay * 4); 2051cb0ef41Sopenharmony_ci if (iterationNumber <= 2) { 2061cb0ef41Sopenharmony_ci assert.strictEqual(signal.aborted, false); 2071cb0ef41Sopenharmony_ci } 2081cb0ef41Sopenharmony_ci if (iterationNumber === 2) { 2091cb0ef41Sopenharmony_ci controller.abort(); 2101cb0ef41Sopenharmony_ci } 2111cb0ef41Sopenharmony_ci if (iterationNumber > 2) { 2121cb0ef41Sopenharmony_ci assert.strictEqual(signal.aborted, true); 2131cb0ef41Sopenharmony_ci } 2141cb0ef41Sopenharmony_ci if (iterationNumber > totalIterations) { 2151cb0ef41Sopenharmony_ci totalIterations = iterationNumber; 2161cb0ef41Sopenharmony_ci } 2171cb0ef41Sopenharmony_ci }, delay, signal); 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci timeoutLoop.catch(common.mustCall(() => { 2201cb0ef41Sopenharmony_ci assert.ok(totalIterations >= 3, `iterations was ${totalIterations} < 3`); 2211cb0ef41Sopenharmony_ci })); 2221cb0ef41Sopenharmony_ci } 2231cb0ef41Sopenharmony_ci} 2241cb0ef41Sopenharmony_ci 2251cb0ef41Sopenharmony_ci{ 2261cb0ef41Sopenharmony_ci // Check that the timing is correct 2271cb0ef41Sopenharmony_ci let pre = false; 2281cb0ef41Sopenharmony_ci let post = false; 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_ci const time_unit = 50; 2311cb0ef41Sopenharmony_ci Promise.all([ 2321cb0ef41Sopenharmony_ci setPromiseTimeout(1).then(() => pre = true), 2331cb0ef41Sopenharmony_ci new Promise((res) => { 2341cb0ef41Sopenharmony_ci const iterable = timerPromises.setInterval(time_unit * 2); 2351cb0ef41Sopenharmony_ci const iterator = iterable[Symbol.asyncIterator](); 2361cb0ef41Sopenharmony_ci 2371cb0ef41Sopenharmony_ci iterator.next().then(() => { 2381cb0ef41Sopenharmony_ci assert.ok(pre, 'interval ran too early'); 2391cb0ef41Sopenharmony_ci assert.ok(!post, 'interval ran too late'); 2401cb0ef41Sopenharmony_ci return iterator.next(); 2411cb0ef41Sopenharmony_ci }).then(() => { 2421cb0ef41Sopenharmony_ci assert.ok(post, 'second interval ran too early'); 2431cb0ef41Sopenharmony_ci return iterator.return(); 2441cb0ef41Sopenharmony_ci }).then(res); 2451cb0ef41Sopenharmony_ci }), 2461cb0ef41Sopenharmony_ci setPromiseTimeout(time_unit * 3).then(() => post = true), 2471cb0ef41Sopenharmony_ci ]).then(common.mustCall()); 2481cb0ef41Sopenharmony_ci} 2491cb0ef41Sopenharmony_ci 2501cb0ef41Sopenharmony_ci(async () => { 2511cb0ef41Sopenharmony_ci const signal = AbortSignal.abort('boom'); 2521cb0ef41Sopenharmony_ci try { 2531cb0ef41Sopenharmony_ci const iterable = timerPromises.setInterval(2, undefined, { signal }); 2541cb0ef41Sopenharmony_ci // eslint-disable-next-line no-unused-vars, no-empty 2551cb0ef41Sopenharmony_ci for await (const _ of iterable) { } 2561cb0ef41Sopenharmony_ci assert.fail('should have failed'); 2571cb0ef41Sopenharmony_ci } catch (err) { 2581cb0ef41Sopenharmony_ci assert.strictEqual(err.cause, 'boom'); 2591cb0ef41Sopenharmony_ci } 2601cb0ef41Sopenharmony_ci})().then(common.mustCall()); 261