11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst common = require('../common');
41cb0ef41Sopenharmony_ciconst { EventEmitterAsyncResource } = require('events');
51cb0ef41Sopenharmony_ciconst {
61cb0ef41Sopenharmony_ci  createHook,
71cb0ef41Sopenharmony_ci  executionAsyncId,
81cb0ef41Sopenharmony_ci} = require('async_hooks');
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ciconst {
111cb0ef41Sopenharmony_ci  deepStrictEqual,
121cb0ef41Sopenharmony_ci  strictEqual,
131cb0ef41Sopenharmony_ci  throws,
141cb0ef41Sopenharmony_ci} = require('assert');
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ciconst {
171cb0ef41Sopenharmony_ci  setImmediate: tick,
181cb0ef41Sopenharmony_ci} = require('timers/promises');
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_cifunction makeHook(trackedTypes) {
211cb0ef41Sopenharmony_ci  const eventMap = new Map();
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ci  function log(asyncId, name) {
241cb0ef41Sopenharmony_ci    const entry = eventMap.get(asyncId);
251cb0ef41Sopenharmony_ci    if (entry !== undefined) entry.push({ name });
261cb0ef41Sopenharmony_ci  }
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci  const hook = createHook({
291cb0ef41Sopenharmony_ci    init(asyncId, type, triggerAsyncId, resource) {
301cb0ef41Sopenharmony_ci      if (trackedTypes.includes(type)) {
311cb0ef41Sopenharmony_ci        eventMap.set(asyncId, [
321cb0ef41Sopenharmony_ci          {
331cb0ef41Sopenharmony_ci            name: 'init',
341cb0ef41Sopenharmony_ci            type,
351cb0ef41Sopenharmony_ci            triggerAsyncId,
361cb0ef41Sopenharmony_ci            resource,
371cb0ef41Sopenharmony_ci          },
381cb0ef41Sopenharmony_ci        ]);
391cb0ef41Sopenharmony_ci      }
401cb0ef41Sopenharmony_ci    },
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci    before(asyncId) { log(asyncId, 'before'); },
431cb0ef41Sopenharmony_ci    after(asyncId) { log(asyncId, 'after'); },
441cb0ef41Sopenharmony_ci    destroy(asyncId) { log(asyncId, 'destroy'); },
451cb0ef41Sopenharmony_ci  }).enable();
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ci  return {
481cb0ef41Sopenharmony_ci    done() {
491cb0ef41Sopenharmony_ci      hook.disable();
501cb0ef41Sopenharmony_ci      return new Set(eventMap.values());
511cb0ef41Sopenharmony_ci    },
521cb0ef41Sopenharmony_ci    ids() {
531cb0ef41Sopenharmony_ci      return new Set(eventMap.keys());
541cb0ef41Sopenharmony_ci    },
551cb0ef41Sopenharmony_ci  };
561cb0ef41Sopenharmony_ci}
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci// Tracks emit() calls correctly using async_hooks
591cb0ef41Sopenharmony_ci(async () => {
601cb0ef41Sopenharmony_ci  const tracer = makeHook(['Foo']);
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci  class Foo extends EventEmitterAsyncResource {}
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci  const origExecutionAsyncId = executionAsyncId();
651cb0ef41Sopenharmony_ci  const foo = new Foo();
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci  foo.on('someEvent', common.mustCall());
681cb0ef41Sopenharmony_ci  foo.emit('someEvent');
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci  deepStrictEqual([foo.asyncId], [...tracer.ids()]);
711cb0ef41Sopenharmony_ci  strictEqual(foo.triggerAsyncId, origExecutionAsyncId);
721cb0ef41Sopenharmony_ci  strictEqual(foo.asyncResource.eventEmitter, foo);
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_ci  foo.emitDestroy();
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci  await tick();
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci  deepStrictEqual(tracer.done(), new Set([
791cb0ef41Sopenharmony_ci    [
801cb0ef41Sopenharmony_ci      {
811cb0ef41Sopenharmony_ci        name: 'init',
821cb0ef41Sopenharmony_ci        type: 'Foo',
831cb0ef41Sopenharmony_ci        triggerAsyncId: origExecutionAsyncId,
841cb0ef41Sopenharmony_ci        resource: foo.asyncResource,
851cb0ef41Sopenharmony_ci      },
861cb0ef41Sopenharmony_ci      { name: 'before' },
871cb0ef41Sopenharmony_ci      { name: 'after' },
881cb0ef41Sopenharmony_ci      { name: 'destroy' },
891cb0ef41Sopenharmony_ci    ],
901cb0ef41Sopenharmony_ci  ]));
911cb0ef41Sopenharmony_ci})().then(common.mustCall());
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci// Can explicitly specify name as positional arg
941cb0ef41Sopenharmony_ci(async () => {
951cb0ef41Sopenharmony_ci  const tracer = makeHook(['ResourceName']);
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci  const origExecutionAsyncId = executionAsyncId();
981cb0ef41Sopenharmony_ci  class Foo extends EventEmitterAsyncResource {}
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci  const foo = new Foo('ResourceName');
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci  deepStrictEqual(tracer.done(), new Set([
1031cb0ef41Sopenharmony_ci    [
1041cb0ef41Sopenharmony_ci      {
1051cb0ef41Sopenharmony_ci        name: 'init',
1061cb0ef41Sopenharmony_ci        type: 'ResourceName',
1071cb0ef41Sopenharmony_ci        triggerAsyncId: origExecutionAsyncId,
1081cb0ef41Sopenharmony_ci        resource: foo.asyncResource,
1091cb0ef41Sopenharmony_ci      },
1101cb0ef41Sopenharmony_ci    ],
1111cb0ef41Sopenharmony_ci  ]));
1121cb0ef41Sopenharmony_ci})().then(common.mustCall());
1131cb0ef41Sopenharmony_ci
1141cb0ef41Sopenharmony_ci// Can explicitly specify name as option
1151cb0ef41Sopenharmony_ci(async () => {
1161cb0ef41Sopenharmony_ci  const tracer = makeHook(['ResourceName']);
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci  const origExecutionAsyncId = executionAsyncId();
1191cb0ef41Sopenharmony_ci  class Foo extends EventEmitterAsyncResource {}
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci  const foo = new Foo({ name: 'ResourceName' });
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  deepStrictEqual(tracer.done(), new Set([
1241cb0ef41Sopenharmony_ci    [
1251cb0ef41Sopenharmony_ci      {
1261cb0ef41Sopenharmony_ci        name: 'init',
1271cb0ef41Sopenharmony_ci        type: 'ResourceName',
1281cb0ef41Sopenharmony_ci        triggerAsyncId: origExecutionAsyncId,
1291cb0ef41Sopenharmony_ci        resource: foo.asyncResource,
1301cb0ef41Sopenharmony_ci      },
1311cb0ef41Sopenharmony_ci    ],
1321cb0ef41Sopenharmony_ci  ]));
1331cb0ef41Sopenharmony_ci})().then(common.mustCall());
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci// Member methods ERR_INVALID_THIS
1361cb0ef41Sopenharmony_cithrows(
1371cb0ef41Sopenharmony_ci  () => EventEmitterAsyncResource.prototype.emit(),
1381cb0ef41Sopenharmony_ci  { code: 'ERR_INVALID_THIS' }
1391cb0ef41Sopenharmony_ci);
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_cithrows(
1421cb0ef41Sopenharmony_ci  () => EventEmitterAsyncResource.prototype.emitDestroy(),
1431cb0ef41Sopenharmony_ci  { code: 'ERR_INVALID_THIS' }
1441cb0ef41Sopenharmony_ci);
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci['asyncId', 'triggerAsyncId', 'asyncResource'].forEach((getter) => {
1471cb0ef41Sopenharmony_ci  throws(
1481cb0ef41Sopenharmony_ci    () => Reflect.get(EventEmitterAsyncResource.prototype, getter, {}),
1491cb0ef41Sopenharmony_ci    {
1501cb0ef41Sopenharmony_ci      code: 'ERR_INVALID_THIS',
1511cb0ef41Sopenharmony_ci      name: /TypeError/,
1521cb0ef41Sopenharmony_ci      message: 'Value of "this" must be of type EventEmitterAsyncResource',
1531cb0ef41Sopenharmony_ci      stack: new RegExp(`at get ${getter}`),
1541cb0ef41Sopenharmony_ci    }
1551cb0ef41Sopenharmony_ci  );
1561cb0ef41Sopenharmony_ci});
157