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