From 69098bbc27abebf4b6590512b30990849512987e Mon Sep 17 00:00:00 2001 From: David Cai Date: Mon, 5 Jun 2017 15:35:06 +0800 Subject: [PATCH] test: increase coverage of async_hooks --- lib/async_hooks.js | 8 +-- test/async-hooks/test-callback-error.js | 56 +++++++++++++++++++ ....api.async-resource.after-on-destroyed.js} | 0 ...api.async-resource.before-on-destroyed.js} | 0 ...dder.api.async-resource.improper-order.js} | 0 ...der.api.async-resource.improper-unwind.js} | 0 ...js => test-embedder.api.async-resource.js} | 12 ++++ test/async-hooks/test-emit-before-after.js | 46 +++++++++++++++ test/async-hooks/test-emit-init.js | 49 ++++++++++++++++ test/async-hooks/test-enable-disable.js | 4 ++ .../test-async-hooks-run-in-async-id-scope.js | 13 +++++ 11 files changed, 184 insertions(+), 4 deletions(-) create mode 100644 test/async-hooks/test-callback-error.js rename test/async-hooks/{test-embedder.api.async-event.after-on-destroyed.js => test-embedder.api.async-resource.after-on-destroyed.js} (100%) rename test/async-hooks/{test-embedder.api.async-event.before-on-destroyed.js => test-embedder.api.async-resource.before-on-destroyed.js} (100%) rename test/async-hooks/{test-embedder.api.async-event.improper-order.js => test-embedder.api.async-resource.improper-order.js} (100%) rename test/async-hooks/{test-embedder.api.async-event.improper-unwind.js => test-embedder.api.async-resource.improper-unwind.js} (100%) rename test/async-hooks/{test-embedder.api.async-event.js => test-embedder.api.async-resource.js} (85%) create mode 100644 test/async-hooks/test-emit-before-after.js create mode 100644 test/async-hooks/test-emit-init.js create mode 100644 test/parallel/test-async-hooks-run-in-async-id-scope.js diff --git a/lib/async_hooks.js b/lib/async_hooks.js index d5d5407b1de19b..aec73ed770f069 100644 --- a/lib/async_hooks.js +++ b/lib/async_hooks.js @@ -205,15 +205,15 @@ class AsyncResource { } this[trigger_id_symbol] = triggerId; - // Return immediately if there's nothing to do. - if (async_hook_fields[kInit] === 0) - return; - if (typeof type !== 'string' || type.length <= 0) throw new TypeError('type must be a string with length > 0'); if (!Number.isSafeInteger(triggerId) || triggerId < 0) throw new RangeError('triggerId must be an unsigned integer'); + // Return immediately if there's nothing to do. + if (async_hook_fields[kInit] === 0) + return; + processing_hook = true; for (var i = 0; i < active_hooks_array.length; i++) { if (typeof active_hooks_array[i][init_symbol] === 'function') { diff --git a/test/async-hooks/test-callback-error.js b/test/async-hooks/test-callback-error.js new file mode 100644 index 00000000000000..8fe0177449e4ff --- /dev/null +++ b/test/async-hooks/test-callback-error.js @@ -0,0 +1,56 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const spawnSync = require('child_process').spawnSync; +const async_hooks = require('async_hooks'); +const initHooks = require('./init-hooks'); + +switch (process.argv[2]) { + case 'test_init_callback': + initHooks({ + oninit: common.mustCall(() => { throw new Error('test_init_callback'); }) + }).enable(); + + async_hooks.emitInit(async_hooks.currentId(), 'test_init_callback_type', + async_hooks.triggerId()); + break; + case 'test_callback': + initHooks({ + onbefore: common.mustCall(() => { throw new Error('test_callback'); }) + }).enable(); + + async_hooks.emitInit(async_hooks.currentId(), 'test_callback_type', + async_hooks.triggerId()); + async_hooks.emitBefore(async_hooks.currentId()); + break; +} + +if (process.execArgv.includes('--abort-on-uncaught-exception')) { + initHooks({ + oninit: common.mustCall(() => { throw new Error('test_callback_abort'); }) + }).enable(); + + async_hooks.emitInit(async_hooks.currentId(), 'test_callback_abort', + async_hooks.triggerId()); +} + +const c1 = spawnSync(`${process.execPath}`, [__filename, 'test_init_callback']); +assert.strictEqual(c1.stderr.toString().split('\n')[0], + 'Error: test_init_callback'); +assert.strictEqual(c1.status, 1); + +const c2 = spawnSync(`${process.execPath}`, [__filename, 'test_callback']); +assert.strictEqual(c2.stderr.toString().split('\n')[0], 'Error: test_callback'); +assert.strictEqual(c2.status, 1); + +const c3 = spawnSync(`${process.execPath}`, ['--abort-on-uncaught-exception', + __filename, + 'test_callback_abort']); +assert.strictEqual(c3.stdout.toString(), ''); + +const stderrOutput = c3.stderr.toString() + .trim() + .split('\n') + .map((s) => s.trim()); +assert.strictEqual(stderrOutput[0], 'Error: test_callback_abort'); diff --git a/test/async-hooks/test-embedder.api.async-event.after-on-destroyed.js b/test/async-hooks/test-embedder.api.async-resource.after-on-destroyed.js similarity index 100% rename from test/async-hooks/test-embedder.api.async-event.after-on-destroyed.js rename to test/async-hooks/test-embedder.api.async-resource.after-on-destroyed.js diff --git a/test/async-hooks/test-embedder.api.async-event.before-on-destroyed.js b/test/async-hooks/test-embedder.api.async-resource.before-on-destroyed.js similarity index 100% rename from test/async-hooks/test-embedder.api.async-event.before-on-destroyed.js rename to test/async-hooks/test-embedder.api.async-resource.before-on-destroyed.js diff --git a/test/async-hooks/test-embedder.api.async-event.improper-order.js b/test/async-hooks/test-embedder.api.async-resource.improper-order.js similarity index 100% rename from test/async-hooks/test-embedder.api.async-event.improper-order.js rename to test/async-hooks/test-embedder.api.async-resource.improper-order.js diff --git a/test/async-hooks/test-embedder.api.async-event.improper-unwind.js b/test/async-hooks/test-embedder.api.async-resource.improper-unwind.js similarity index 100% rename from test/async-hooks/test-embedder.api.async-event.improper-unwind.js rename to test/async-hooks/test-embedder.api.async-resource.improper-unwind.js diff --git a/test/async-hooks/test-embedder.api.async-event.js b/test/async-hooks/test-embedder.api.async-resource.js similarity index 85% rename from test/async-hooks/test-embedder.api.async-event.js rename to test/async-hooks/test-embedder.api.async-resource.js index a5ffd863e6b0b3..ec3d265e58cb0f 100644 --- a/test/async-hooks/test-embedder.api.async-event.js +++ b/test/async-hooks/test-embedder.api.async-resource.js @@ -12,6 +12,14 @@ const { checkInvocations } = require('./hook-checks'); const hooks = initHooks(); hooks.enable(); +assert.throws(() => new AsyncResource(), + /^TypeError: type must be a string with length > 0$/); +assert.throws(() => new AsyncResource('invalid_trigger_id', null), + /^RangeError: triggerId must be an unsigned integer$/); + +assert.strictEqual(typeof new AsyncResource('default_trigger_id').triggerId(), + 'number'); + // create first custom event 'alcazares' with triggerId derived // from async_hooks currentId const alcaTriggerId = async_hooks.currentId(); @@ -26,6 +34,10 @@ assert.strictEqual(typeof alcazares.uid, 'number'); assert.strictEqual(alcazares.triggerId, alcaTriggerId); checkInvocations(alcazares, { init: 1 }, 'alcazares constructed'); +assert.strictEqual(typeof alcaEvent.asyncId(), 'number'); +assert.notStrictEqual(alcaEvent.asyncId(), alcaTriggerId); +assert.strictEqual(alcaEvent.triggerId(), alcaTriggerId); + alcaEvent.emitBefore(); checkInvocations(alcazares, { init: 1, before: 1 }, 'alcazares emitted before'); diff --git a/test/async-hooks/test-emit-before-after.js b/test/async-hooks/test-emit-before-after.js new file mode 100644 index 00000000000000..fb16bda22aff92 --- /dev/null +++ b/test/async-hooks/test-emit-before-after.js @@ -0,0 +1,46 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const spawnSync = require('child_process').spawnSync; +const async_hooks = require('async_hooks'); +const initHooks = require('./init-hooks'); + +switch (process.argv[2]) { + case 'test_invalid_async_id': + async_hooks.emitBefore(-1); + break; + case 'test_invalid_trigger_id': + async_hooks.emitBefore(1, -1); + break; +} + +const c1 = spawnSync(process.execPath, [__filename, 'test_invalid_async_id']); +assert.strictEqual(c1.stderr.toString().split('\n')[0], + 'Error: before(): asyncId or triggerId is less than zero ' + + '(asyncId: -1, triggerId: -1)'); +assert.strictEqual(c1.status, 1); + +const c2 = spawnSync(process.execPath, [__filename, 'test_invalid_trigger_id']); +assert.strictEqual(c2.stderr.toString().split('\n')[0], + 'Error: before(): asyncId or triggerId is less than zero ' + + '(asyncId: 1, triggerId: -1)'); +assert.strictEqual(c2.status, 1); + +const expectedId = async_hooks.newUid(); +const expectedTriggerId = async_hooks.newUid(); +const expectedType = 'test_emit_before_after_type'; + +// Verify that if there is no registered hook, then nothing will happen. +async_hooks.emitBefore(expectedId); +async_hooks.emitAfter(expectedId); + +initHooks({ + onbefore: common.mustCall((id) => assert.strictEqual(id, expectedId)), + onafter: common.mustCall((id) => assert.strictEqual(id, expectedId)), + allowNoInit: true +}).enable(); + +async_hooks.emitInit(expectedId, expectedType, expectedTriggerId); +async_hooks.emitBefore(expectedId); +async_hooks.emitAfter(expectedId); diff --git a/test/async-hooks/test-emit-init.js b/test/async-hooks/test-emit-init.js new file mode 100644 index 00000000000000..59476f2d44e7c5 --- /dev/null +++ b/test/async-hooks/test-emit-init.js @@ -0,0 +1,49 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const async_hooks = require('async_hooks'); +const initHooks = require('./init-hooks'); + +// Verify that if there is no registered hook, then those invalid parameters +// won't be checked. +assert.doesNotThrow(() => async_hooks.emitInit()); + +const expectedId = async_hooks.newUid(); +const expectedTriggerId = async_hooks.newUid(); +const expectedType = 'test_emit_init_type'; +const expectedResource = { key: 'test_emit_init_resource' }; + +const hooks1 = initHooks({ + oninit: common.mustCall((id, type, triggerId, resource) => { + assert.strictEqual(id, expectedId); + assert.strictEqual(type, expectedType); + assert.strictEqual(triggerId, expectedTriggerId); + assert.strictEqual(resource.key, expectedResource.key); + }) +}); + +hooks1.enable(); + +assert.throws(() => async_hooks.emitInit(), + /^RangeError: asyncId must be an unsigned integer$/); +assert.throws(() => async_hooks.emitInit(expectedId), + /^TypeError: type must be a string with length > 0$/); +assert.throws(() => async_hooks.emitInit(expectedId, expectedType, -1), + /^RangeError: triggerId must be an unsigned integer$/); + +async_hooks.emitInit(expectedId, expectedType, expectedTriggerId, + expectedResource); + +hooks1.disable(); + +initHooks({ + oninit: common.mustCall((id, type, triggerId, resource) => { + assert.strictEqual(id, expectedId); + assert.strictEqual(type, expectedType); + assert.notStrictEqual(triggerId, expectedTriggerId); + assert.strictEqual(resource.key, expectedResource.key); + }) +}).enable(); + +async_hooks.emitInit(expectedId, expectedType, expectedResource); diff --git a/test/async-hooks/test-enable-disable.js b/test/async-hooks/test-enable-disable.js index cc93750c883389..6cd584878a7e0f 100644 --- a/test/async-hooks/test-enable-disable.js +++ b/test/async-hooks/test-enable-disable.js @@ -103,6 +103,8 @@ const hook3 = initHooks({ onbefore: onhook3Before, onafter: onhook3After }); // Enabling hook1 and hook3 only, hook2 is still disabled // hook1.enable(); +// Verify that the hook is enabled even if .enable() is called twice. +hook1.enable(); hook3.enable(); // @@ -122,6 +124,8 @@ let disabledHook3 = false; function onhook2Before() { if (disabledHook3) return; hook1.disable(); + // Verify that the hook is disabled even if .disable() is called twice. + hook1.disable(); disabledHook3 = true; } diff --git a/test/parallel/test-async-hooks-run-in-async-id-scope.js b/test/parallel/test-async-hooks-run-in-async-id-scope.js new file mode 100644 index 00000000000000..a283e9c30924be --- /dev/null +++ b/test/parallel/test-async-hooks-run-in-async-id-scope.js @@ -0,0 +1,13 @@ +'use strict'; + +const common = require('../common'); +const assert = require('assert'); +const async_hooks = require('async_hooks'); + +const asyncId = async_hooks.newUid(); + +assert.notStrictEqual(async_hooks.currentId(), asyncId); + +async_hooks.runInAsyncIdScope(asyncId, common.mustCall(() => { + assert.strictEqual(async_hooks.currentId(), asyncId); +}));