node/test/parallel/test-eventemitter-asyncresource.js
Yagiz Nizipli d5c29ba12d
events: set EventEmitterAsyncResource fields private
PR-URL: https://github.com/nodejs/node/pull/54889
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
2024-09-17 03:55:21 +00:00

155 lines
3.4 KiB
JavaScript

'use strict';
const common = require('../common');
const { EventEmitterAsyncResource } = require('events');
const {
createHook,
executionAsyncId,
} = require('async_hooks');
const {
deepStrictEqual,
strictEqual,
throws,
} = require('assert');
const {
setImmediate: tick,
} = require('timers/promises');
function makeHook(trackedTypes) {
const eventMap = new Map();
function log(asyncId, name) {
const entry = eventMap.get(asyncId);
if (entry !== undefined) entry.push({ name });
}
const hook = createHook({
init(asyncId, type, triggerAsyncId, resource) {
if (trackedTypes.includes(type)) {
eventMap.set(asyncId, [
{
name: 'init',
type,
triggerAsyncId,
resource,
},
]);
}
},
before(asyncId) { log(asyncId, 'before'); },
after(asyncId) { log(asyncId, 'after'); },
destroy(asyncId) { log(asyncId, 'destroy'); },
}).enable();
return {
done() {
hook.disable();
return new Set(eventMap.values());
},
ids() {
return new Set(eventMap.keys());
},
};
}
// Tracks emit() calls correctly using async_hooks
(async () => {
const tracer = makeHook(['Foo']);
class Foo extends EventEmitterAsyncResource {}
const origExecutionAsyncId = executionAsyncId();
const foo = new Foo();
foo.on('someEvent', common.mustCall());
foo.emit('someEvent');
deepStrictEqual([foo.asyncId], [...tracer.ids()]);
strictEqual(foo.triggerAsyncId, origExecutionAsyncId);
strictEqual(foo.asyncResource.eventEmitter, foo);
foo.emitDestroy();
await tick();
deepStrictEqual(tracer.done(), new Set([
[
{
name: 'init',
type: 'Foo',
triggerAsyncId: origExecutionAsyncId,
resource: foo.asyncResource,
},
{ name: 'before' },
{ name: 'after' },
{ name: 'destroy' },
],
]));
})().then(common.mustCall());
// Can explicitly specify name as positional arg
(async () => {
const tracer = makeHook(['ResourceName']);
const origExecutionAsyncId = executionAsyncId();
class Foo extends EventEmitterAsyncResource {}
const foo = new Foo('ResourceName');
deepStrictEqual(tracer.done(), new Set([
[
{
name: 'init',
type: 'ResourceName',
triggerAsyncId: origExecutionAsyncId,
resource: foo.asyncResource,
},
],
]));
})().then(common.mustCall());
// Can explicitly specify name as option
(async () => {
const tracer = makeHook(['ResourceName']);
const origExecutionAsyncId = executionAsyncId();
class Foo extends EventEmitterAsyncResource {}
const foo = new Foo({ name: 'ResourceName' });
deepStrictEqual(tracer.done(), new Set([
[
{
name: 'init',
type: 'ResourceName',
triggerAsyncId: origExecutionAsyncId,
resource: foo.asyncResource,
},
],
]));
})().then(common.mustCall());
throws(
() => EventEmitterAsyncResource.prototype.emit(),
{ name: 'TypeError', message: /Cannot read private member/ }
);
throws(
() => EventEmitterAsyncResource.prototype.emitDestroy(),
{ name: 'TypeError', message: /Cannot read private member/ }
);
['asyncId', 'triggerAsyncId', 'asyncResource'].forEach((getter) => {
throws(
() => Reflect.get(EventEmitterAsyncResource.prototype, getter, {}),
{
name: 'TypeError',
message: /Cannot read private member/,
stack: new RegExp(`at get ${getter}`),
}
);
});