mirror of https://github.com/lukechilds/node.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
8.9 KiB
275 lines
8.9 KiB
8 years ago
|
/*
|
||
|
* Test Steps Explained
|
||
|
* ====================
|
||
|
*
|
||
|
* Initializing hooks:
|
||
|
*
|
||
|
* We initialize 3 hooks. For hook2 and hook3 we register a callback for the
|
||
|
* "before" and in case of hook3 also for the "after" invocations.
|
||
|
*
|
||
|
* Enabling hooks initially:
|
||
|
*
|
||
|
* We only enable hook1 and hook3 initially.
|
||
|
*
|
||
|
* Enabling hook2:
|
||
|
*
|
||
|
* When hook3's "before" invocation occurs we enable hook2. Since this
|
||
|
* happens right before calling `onfirstImmediate` hook2 will miss all hook
|
||
|
* invocations until then, including the "init" and "before" of the first
|
||
|
* Immediate.
|
||
|
* However afterwards it collects all invocations that follow on the first
|
||
|
* Immediate as well as all invocations on the second Immediate.
|
||
|
*
|
||
|
* This shows that a hook can enable another hook inside a life time event
|
||
|
* callback.
|
||
|
*
|
||
|
*
|
||
|
* Disabling hook1
|
||
|
*
|
||
|
* Since we registered the "before" callback for hook2 it will execute it
|
||
|
* right before `onsecondImmediate` is called.
|
||
|
* At that point we disable hook1 which is why it will miss all invocations
|
||
|
* afterwards and thus won't include the second "after" as well as the
|
||
|
* "destroy" invocations
|
||
|
*
|
||
|
* This shows that a hook can disable another hook inside a life time event
|
||
|
* callback.
|
||
|
*
|
||
|
* Disabling hook3
|
||
|
*
|
||
|
* When the second "after" invocation occurs (after onsecondImmediate), hook3
|
||
|
* disables itself.
|
||
|
* As a result it will not receive the "destroy" invocation.
|
||
|
*
|
||
|
* This shows that a hook can disable itself inside a life time event callback.
|
||
|
*
|
||
|
* Sample Test Log
|
||
|
* ===============
|
||
|
*
|
||
|
* - setting up first Immediate
|
||
|
* hook1.init.uid-5
|
||
|
* hook3.init.uid-5
|
||
|
* - finished setting first Immediate
|
||
|
|
||
|
* hook1.before.uid-5
|
||
|
* hook3.before.uid-5
|
||
|
* - enabled hook2
|
||
|
* - entering onfirstImmediate
|
||
|
|
||
|
* - setting up second Immediate
|
||
|
* hook1.init.uid-6
|
||
|
* hook3.init.uid-6
|
||
|
* hook2.init.uid-6
|
||
|
* - finished setting second Immediate
|
||
|
|
||
|
* - exiting onfirstImmediate
|
||
|
* hook1.after.uid-5
|
||
|
* hook3.after.uid-5
|
||
|
* hook2.after.uid-5
|
||
|
* hook1.destroy.uid-5
|
||
|
* hook3.destroy.uid-5
|
||
|
* hook2.destroy.uid-5
|
||
|
* hook1.before.uid-6
|
||
|
* hook3.before.uid-6
|
||
|
* hook2.before.uid-6
|
||
|
* - disabled hook1
|
||
|
* - entering onsecondImmediate
|
||
|
* - exiting onsecondImmediate
|
||
|
* hook3.after.uid-6
|
||
|
* - disabled hook3
|
||
|
* hook2.after.uid-6
|
||
|
* hook2.destroy.uid-6
|
||
|
*/
|
||
|
|
||
|
'use strict';
|
||
|
|
||
|
const common = require('../common');
|
||
|
const assert = require('assert');
|
||
|
const tick = require('./tick');
|
||
|
const initHooks = require('./init-hooks');
|
||
|
const { checkInvocations } = require('./hook-checks');
|
||
|
// Include "Unknown"s because hook2 will not be able to identify
|
||
|
// the type of the first Immediate since it will miss its `init` invocation.
|
||
|
const types = [ 'Immediate', 'Unknown' ];
|
||
|
|
||
|
//
|
||
|
// Initializing hooks
|
||
|
//
|
||
|
const hook1 = initHooks();
|
||
|
const hook2 = initHooks({ onbefore: onhook2Before, allowNoInit: true });
|
||
|
const hook3 = initHooks({ onbefore: onhook3Before, onafter: onhook3After });
|
||
|
|
||
|
//
|
||
|
// Enabling hook1 and hook3 only, hook2 is still disabled
|
||
|
//
|
||
|
hook1.enable();
|
||
|
hook3.enable();
|
||
|
|
||
|
//
|
||
|
// Enabling hook2
|
||
|
//
|
||
|
let enabledHook2 = false;
|
||
|
function onhook3Before() {
|
||
|
if (enabledHook2) return;
|
||
|
hook2.enable();
|
||
|
enabledHook2 = true;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Disabling hook1
|
||
|
//
|
||
|
let disabledHook3 = false;
|
||
|
function onhook2Before() {
|
||
|
if (disabledHook3) return;
|
||
|
hook1.disable();
|
||
|
disabledHook3 = true;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Disabling hook3 during the second "after" invocations it sees
|
||
|
//
|
||
|
let count = 2;
|
||
|
function onhook3After() {
|
||
|
if (!--count) {
|
||
|
hook3.disable();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
setImmediate(common.mustCall(onfirstImmediate));
|
||
|
|
||
|
//
|
||
|
// onfirstImmediate is called after all "init" and "before" callbacks of the
|
||
|
// active hooks were invoked
|
||
|
//
|
||
|
function onfirstImmediate() {
|
||
|
const as1 = hook1.activitiesOfTypes(types);
|
||
|
const as2 = hook2.activitiesOfTypes(types);
|
||
|
const as3 = hook3.activitiesOfTypes(types);
|
||
|
assert.strictEqual(as1.length, 1,
|
||
|
'hook1 captured one immediate on first callback');
|
||
|
// hook2 was not enabled yet .. it is enabled after hook3's "before" completed
|
||
|
assert.strictEqual(as2.length, 0,
|
||
|
'hook2 captured no immediate on first callback');
|
||
|
assert.strictEqual(as3.length, 1,
|
||
|
'hook3 captured one immediate on first callback');
|
||
|
|
||
|
// Check that hook1 and hook3 captured the same Immediate and that it is valid
|
||
|
const firstImmediate = as1[0];
|
||
|
assert.strictEqual(as3[0].uid, as1[0].uid,
|
||
|
'hook1 and hook3 captured same first immediate');
|
||
|
assert.strictEqual(firstImmediate.type, 'Immediate', 'immediate');
|
||
|
assert.strictEqual(typeof firstImmediate.uid, 'number', 'uid is a number');
|
||
|
assert.strictEqual(typeof firstImmediate.triggerId,
|
||
|
'number', 'triggerId is a number');
|
||
|
checkInvocations(as1[0], { init: 1, before: 1 },
|
||
|
'hook1[0]: on first immediate');
|
||
|
checkInvocations(as3[0], { init: 1, before: 1 },
|
||
|
'hook3[0]: on first immediate');
|
||
|
|
||
|
// Setup the second Immediate, note that now hook2 is enabled and thus
|
||
|
// will capture all lifetime events of this Immediate
|
||
|
setImmediate(common.mustCall(onsecondImmediate));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Once we exit onfirstImmediate the "after" callbacks of the active hooks are
|
||
|
// invoked
|
||
|
//
|
||
|
|
||
|
let hook1First, hook2First, hook3First;
|
||
|
let hook1Second, hook2Second, hook3Second;
|
||
|
|
||
|
//
|
||
|
// onsecondImmediate is called after all "before" callbacks of the active hooks
|
||
|
// are invoked again
|
||
|
//
|
||
|
function onsecondImmediate() {
|
||
|
const as1 = hook1.activitiesOfTypes(types);
|
||
|
const as2 = hook2.activitiesOfTypes(types);
|
||
|
const as3 = hook3.activitiesOfTypes(types);
|
||
|
assert.strictEqual(
|
||
|
as1.length, 2,
|
||
|
'hook1 captured first and second immediate on second callback');
|
||
|
assert.strictEqual(
|
||
|
as2.length, 2,
|
||
|
'hook2 captured first and second immediate on second callback');
|
||
|
assert.strictEqual(
|
||
|
as3.length, 2,
|
||
|
'hook3 captured first and second immediate on second callback');
|
||
|
|
||
|
// Assign the info collected by each hook for each immediate for easier
|
||
|
// reference.
|
||
|
// hook2 saw the "init" of the second immediate before the
|
||
|
// "after" of the first which is why they are ordered the opposite way
|
||
|
hook1First = as1[0];
|
||
|
hook1Second = as1[1];
|
||
|
hook2First = as2[1];
|
||
|
hook2Second = as2[0];
|
||
|
hook3First = as3[0];
|
||
|
hook3Second = as3[1];
|
||
|
|
||
|
// Check that all hooks captured the same Immediate and that it is valid
|
||
|
const secondImmediate = hook1Second;
|
||
|
assert.strictEqual(hook2Second.uid, hook3Second.uid,
|
||
|
'hook2 and hook3 captured same second immediate');
|
||
|
assert.strictEqual(hook1Second.uid, hook3Second.uid,
|
||
|
'hook1 and hook3 captured same second immediate');
|
||
|
assert.strictEqual(secondImmediate.type, 'Immediate', 'immediate');
|
||
|
assert.strictEqual(typeof secondImmediate.uid, 'number', 'uid is a number');
|
||
|
assert.strictEqual(typeof secondImmediate.triggerId, 'number',
|
||
|
'triggerId is a number');
|
||
|
|
||
|
checkInvocations(hook1First, { init: 1, before: 1, after: 1, destroy: 1 },
|
||
|
'hook1First: on second immediate');
|
||
|
checkInvocations(hook1Second, { init: 1, before: 1 },
|
||
|
'hook1Second: on second immediate');
|
||
|
// hook2 missed the "init" and "before" since it was enabled after they
|
||
|
// occurred
|
||
|
checkInvocations(hook2First, { after: 1, destroy: 1 },
|
||
|
'hook2First: on second immediate');
|
||
|
checkInvocations(hook2Second, { init: 1, before: 1 },
|
||
|
'hook2Second: on second immediate');
|
||
|
checkInvocations(hook3First, { init: 1, before: 1, after: 1, destroy: 1 },
|
||
|
'hook3First: on second immediate');
|
||
|
checkInvocations(hook3Second, { init: 1, before: 1 },
|
||
|
'hook3Second: on second immediate');
|
||
|
tick(1);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Once we exit onsecondImmediate the "after" callbacks of the active hooks are
|
||
|
// invoked again.
|
||
|
// During this second "after" invocation hook3 disables itself
|
||
|
// (see onhook3After).
|
||
|
//
|
||
|
|
||
|
process.on('exit', onexit);
|
||
|
|
||
|
function onexit() {
|
||
|
hook1.disable();
|
||
|
hook2.disable();
|
||
|
hook3.disable();
|
||
|
hook1.sanityCheck();
|
||
|
hook2.sanityCheck();
|
||
|
hook3.sanityCheck();
|
||
|
|
||
|
checkInvocations(hook1First, { init: 1, before: 1, after: 1, destroy: 1 },
|
||
|
'hook1First: when process exits');
|
||
|
// hook1 was disabled during hook2's "before" of the second immediate
|
||
|
// and thus did not see "after" and "destroy"
|
||
|
checkInvocations(hook1Second, { init: 1, before: 1 },
|
||
|
'hook1Second: when process exits');
|
||
|
// hook2 missed the "init" and "before" since it was enabled after they
|
||
|
// occurred
|
||
|
checkInvocations(hook2First, { after: 1, destroy: 1 },
|
||
|
'hook2First: when process exits');
|
||
|
checkInvocations(hook2Second, { init: 1, before: 1, after: 1, destroy: 1 },
|
||
|
'hook2Second: when process exits');
|
||
|
checkInvocations(hook3First, { init: 1, before: 1, after: 1, destroy: 1 },
|
||
|
'hook3First: when process exits');
|
||
|
// we don't see a "destroy" invocation here since hook3 disabled itself
|
||
|
// during its "after" invocation
|
||
|
checkInvocations(hook3Second, { init: 1, before: 1, after: 1 },
|
||
|
'hook3Second: when process exits');
|
||
|
}
|