11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst common = require('../../common');
41cb0ef41Sopenharmony_ciconst assert = require('assert');
51cb0ef41Sopenharmony_ciconst domain = require('domain');
61cb0ef41Sopenharmony_ciconst binding = require(`./build/${common.buildType}/binding`);
71cb0ef41Sopenharmony_ciconst makeCallback = binding.makeCallback;
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci// Make sure this is run in the future.
101cb0ef41Sopenharmony_ciconst mustCallCheckDomains = common.mustCall(checkDomains);
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ci// Make sure that using MakeCallback allows the error to propagate.
141cb0ef41Sopenharmony_ciassert.throws(function() {
151cb0ef41Sopenharmony_ci  makeCallback({}, function() {
161cb0ef41Sopenharmony_ci    throw new Error('hi from domain error');
171cb0ef41Sopenharmony_ci  });
181cb0ef41Sopenharmony_ci}, /^Error: hi from domain error$/);
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ci
211cb0ef41Sopenharmony_ci// Check the execution order of the nextTickQueue and MicrotaskQueue in
221cb0ef41Sopenharmony_ci// relation to running multiple MakeCallback's from bootstrap,
231cb0ef41Sopenharmony_ci// node::MakeCallback() and node::AsyncWrap::MakeCallback().
241cb0ef41Sopenharmony_ci// TODO(trevnorris): Is there a way to verify this is being run during
251cb0ef41Sopenharmony_ci// bootstrap?
261cb0ef41Sopenharmony_ci(function verifyExecutionOrder(arg) {
271cb0ef41Sopenharmony_ci  const results = [];
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci  // Processing of the MicrotaskQueue is manually handled by node. They are not
301cb0ef41Sopenharmony_ci  // processed until after the nextTickQueue has been processed.
311cb0ef41Sopenharmony_ci  Promise.resolve(1).then(common.mustCall(function() {
321cb0ef41Sopenharmony_ci    results.push(7);
331cb0ef41Sopenharmony_ci  }));
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci  // The nextTick should run after all immediately invoked calls.
361cb0ef41Sopenharmony_ci  process.nextTick(common.mustCall(function() {
371cb0ef41Sopenharmony_ci    results.push(3);
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci    // Run same test again but while processing the nextTickQueue to make sure
401cb0ef41Sopenharmony_ci    // the following MakeCallback call breaks in the middle of processing the
411cb0ef41Sopenharmony_ci    // queue and allows the script to run normally.
421cb0ef41Sopenharmony_ci    process.nextTick(common.mustCall(function() {
431cb0ef41Sopenharmony_ci      results.push(6);
441cb0ef41Sopenharmony_ci    }));
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci    makeCallback({}, common.mustCall(function() {
471cb0ef41Sopenharmony_ci      results.push(4);
481cb0ef41Sopenharmony_ci    }));
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci    results.push(5);
511cb0ef41Sopenharmony_ci  }));
521cb0ef41Sopenharmony_ci
531cb0ef41Sopenharmony_ci  results.push(0);
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci  // MakeCallback is calling the function immediately, but should then detect
561cb0ef41Sopenharmony_ci  // that a script is already in the middle of execution and return before
571cb0ef41Sopenharmony_ci  // either the nextTickQueue or MicrotaskQueue are processed.
581cb0ef41Sopenharmony_ci  makeCallback({}, common.mustCall(function() {
591cb0ef41Sopenharmony_ci    results.push(1);
601cb0ef41Sopenharmony_ci  }));
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci  // This should run before either the nextTickQueue or MicrotaskQueue are
631cb0ef41Sopenharmony_ci  // processed. Previously MakeCallback would not detect this circumstance
641cb0ef41Sopenharmony_ci  // and process them immediately.
651cb0ef41Sopenharmony_ci  results.push(2);
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  setImmediate(common.mustCall(function() {
681cb0ef41Sopenharmony_ci    for (let i = 0; i < results.length; i++) {
691cb0ef41Sopenharmony_ci      assert.strictEqual(results[i], i,
701cb0ef41Sopenharmony_ci                         `verifyExecutionOrder(${arg}) results: ${results}`);
711cb0ef41Sopenharmony_ci    }
721cb0ef41Sopenharmony_ci    if (arg === 1) {
731cb0ef41Sopenharmony_ci      // The tests are first run on bootstrap during LoadEnvironment() in
741cb0ef41Sopenharmony_ci      // src/node.cc. Now run the tests through node::MakeCallback().
751cb0ef41Sopenharmony_ci      setImmediate(function() {
761cb0ef41Sopenharmony_ci        makeCallback({}, common.mustCall(function() {
771cb0ef41Sopenharmony_ci          verifyExecutionOrder(2);
781cb0ef41Sopenharmony_ci        }));
791cb0ef41Sopenharmony_ci      });
801cb0ef41Sopenharmony_ci    } else if (arg === 2) {
811cb0ef41Sopenharmony_ci      // Make sure there are no conflicts using node::MakeCallback()
821cb0ef41Sopenharmony_ci      // within timers.
831cb0ef41Sopenharmony_ci      setTimeout(common.mustCall(function() {
841cb0ef41Sopenharmony_ci        verifyExecutionOrder(3);
851cb0ef41Sopenharmony_ci      }), 10);
861cb0ef41Sopenharmony_ci    } else if (arg === 3) {
871cb0ef41Sopenharmony_ci      mustCallCheckDomains();
881cb0ef41Sopenharmony_ci    } else {
891cb0ef41Sopenharmony_ci      throw new Error('UNREACHABLE');
901cb0ef41Sopenharmony_ci    }
911cb0ef41Sopenharmony_ci  }));
921cb0ef41Sopenharmony_ci}(1));
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_cifunction checkDomains() {
961cb0ef41Sopenharmony_ci  // Check that domains are properly entered/exited when called in multiple
971cb0ef41Sopenharmony_ci  // levels from both node::MakeCallback() and AsyncWrap::MakeCallback
981cb0ef41Sopenharmony_ci  setImmediate(common.mustCall(function() {
991cb0ef41Sopenharmony_ci    const d1 = domain.create();
1001cb0ef41Sopenharmony_ci    const d2 = domain.create();
1011cb0ef41Sopenharmony_ci    const d3 = domain.create();
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci    makeCallback({ domain: d1 }, common.mustCall(function() {
1041cb0ef41Sopenharmony_ci      assert.strictEqual(d1, process.domain);
1051cb0ef41Sopenharmony_ci      makeCallback({ domain: d2 }, common.mustCall(function() {
1061cb0ef41Sopenharmony_ci        assert.strictEqual(d2, process.domain);
1071cb0ef41Sopenharmony_ci        makeCallback({ domain: d3 }, common.mustCall(function() {
1081cb0ef41Sopenharmony_ci          assert.strictEqual(d3, process.domain);
1091cb0ef41Sopenharmony_ci        }));
1101cb0ef41Sopenharmony_ci        assert.strictEqual(d2, process.domain);
1111cb0ef41Sopenharmony_ci      }));
1121cb0ef41Sopenharmony_ci      assert.strictEqual(d1, process.domain);
1131cb0ef41Sopenharmony_ci    }));
1141cb0ef41Sopenharmony_ci  }));
1151cb0ef41Sopenharmony_ci
1161cb0ef41Sopenharmony_ci  setTimeout(common.mustCall(function() {
1171cb0ef41Sopenharmony_ci    const d1 = domain.create();
1181cb0ef41Sopenharmony_ci    const d2 = domain.create();
1191cb0ef41Sopenharmony_ci    const d3 = domain.create();
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci    makeCallback({ domain: d1 }, common.mustCall(function() {
1221cb0ef41Sopenharmony_ci      assert.strictEqual(d1, process.domain);
1231cb0ef41Sopenharmony_ci      makeCallback({ domain: d2 }, common.mustCall(function() {
1241cb0ef41Sopenharmony_ci        assert.strictEqual(d2, process.domain);
1251cb0ef41Sopenharmony_ci        makeCallback({ domain: d3 }, common.mustCall(function() {
1261cb0ef41Sopenharmony_ci          assert.strictEqual(d3, process.domain);
1271cb0ef41Sopenharmony_ci        }));
1281cb0ef41Sopenharmony_ci        assert.strictEqual(d2, process.domain);
1291cb0ef41Sopenharmony_ci      }));
1301cb0ef41Sopenharmony_ci      assert.strictEqual(d1, process.domain);
1311cb0ef41Sopenharmony_ci    }));
1321cb0ef41Sopenharmony_ci  }), 1);
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci  function testTimer(id) {
1351cb0ef41Sopenharmony_ci    // Make sure nextTick, setImmediate and setTimeout can all recover properly
1361cb0ef41Sopenharmony_ci    // after a thrown makeCallback call.
1371cb0ef41Sopenharmony_ci    const d = domain.create();
1381cb0ef41Sopenharmony_ci    d.on('error', common.mustCall(function(e) {
1391cb0ef41Sopenharmony_ci      assert.strictEqual(e.message, `throw from domain ${id}`);
1401cb0ef41Sopenharmony_ci    }));
1411cb0ef41Sopenharmony_ci    makeCallback({ domain: d }, function() {
1421cb0ef41Sopenharmony_ci      throw new Error(`throw from domain ${id}`);
1431cb0ef41Sopenharmony_ci    });
1441cb0ef41Sopenharmony_ci    throw new Error('UNREACHABLE');
1451cb0ef41Sopenharmony_ci  }
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci  process.nextTick(common.mustCall(testTimer), 3);
1481cb0ef41Sopenharmony_ci  setImmediate(common.mustCall(testTimer), 2);
1491cb0ef41Sopenharmony_ci  setTimeout(common.mustCall(testTimer), 1, 1);
1501cb0ef41Sopenharmony_ci}
151