From 87dcf579b9cb4bf81e564303bd3e6d607a7b0a21 Mon Sep 17 00:00:00 2001 From: JckXia Date: Sat, 16 Apr 2022 16:27:42 -0400 Subject: [PATCH] Add test coverage for async contexts --- test/async_context.cc | 15 +++++++ test/async_context.js | 102 ++++++++++++++++++++++++++++-------------- 2 files changed, 84 insertions(+), 33 deletions(-) diff --git a/test/async_context.cc b/test/async_context.cc index ed98db938..be2e1d917 100644 --- a/test/async_context.cc +++ b/test/async_context.cc @@ -12,10 +12,25 @@ static void MakeCallback(const CallbackInfo& info) { Object::New(info.Env()), std::initializer_list{}, context); } +static void MakeCallbackNoResource(const CallbackInfo& info) { + Function callback = info[0].As(); + AsyncContext context(info.Env(), "async_context_no_res_test"); + callback.MakeCallback( + Object::New(info.Env()), std::initializer_list{}, context); +} + +static Boolean AssertAsyncContextReturnCorrectEnv(const CallbackInfo& info) { + AsyncContext context(info.Env(), "empty_context_test"); + return Boolean::New(info.Env(), context.Env() == info.Env()); +} } // end anonymous namespace Object InitAsyncContext(Env env) { Object exports = Object::New(env); exports["makeCallback"] = Function::New(env, MakeCallback); + exports["makeCallbackNoResource"] = + Function::New(env, MakeCallbackNoResource); + exports["asyncCxtReturnCorrectEnv"] = + Function::New(env, AssertAsyncContextReturnCorrectEnv); return exports; } diff --git a/test/async_context.js b/test/async_context.js index d6a3fc5aa..6a4bef662 100644 --- a/test/async_context.js +++ b/test/async_context.js @@ -5,12 +5,12 @@ const common = require('./common'); // we only check async hooks on 8.x an higher were // they are closer to working properly -const nodeVersion = process.versions.node.split('.')[0] -let async_hooks = undefined; -function checkAsyncHooks() { +const nodeVersion = process.versions.node.split('.')[0]; +let asyncHooks; +function checkAsyncHooks () { if (nodeVersion >= 8) { - if (async_hooks == undefined) { - async_hooks = require('async_hooks'); + if (asyncHooks === undefined) { + asyncHooks = require('async_hooks'); } return true; } @@ -19,7 +19,7 @@ function checkAsyncHooks() { module.exports = common.runTest(test); -function installAsyncHooksForTest() { +function installAsyncHooksForTest (resName) { return new Promise((resolve, reject) => { let id; const events = []; @@ -27,60 +27,96 @@ function installAsyncHooksForTest() { * TODO(legendecas): investigate why resolving & disabling hooks in * destroy callback causing crash with case 'callbackscope.js'. */ - let hook; let destroyed = false; - const interval = setInterval(() => { - if (destroyed) { - hook.disable(); - clearInterval(interval); - resolve(events); - } - }, 10); - - hook = async_hooks.createHook({ - init(asyncId, type, triggerAsyncId, resource) { - if (id === undefined && type === 'async_context_test') { + const hook = asyncHooks.createHook({ + init (asyncId, type, triggerAsyncId, resource) { + if (id === undefined && type === resName) { id = asyncId; events.push({ eventName: 'init', type, triggerAsyncId, resource }); } }, - before(asyncId) { + before (asyncId) { if (asyncId === id) { events.push({ eventName: 'before' }); } }, - after(asyncId) { + after (asyncId) { if (asyncId === id) { events.push({ eventName: 'after' }); } }, - destroy(asyncId) { + destroy (asyncId) { if (asyncId === id) { events.push({ eventName: 'destroy' }); destroyed = true; } } }).enable(); + + const interval = setInterval(() => { + if (destroyed) { + hook.disable(); + clearInterval(interval); + resolve(events); + } + }, 10); }); } -function test(binding) { - if (!checkAsyncHooks()) { - return; - } - - const hooks = installAsyncHooksForTest(); - const triggerAsyncId = async_hooks.executionAsyncId(); - binding.asynccontext.makeCallback(common.mustCall(), { foo: 'foo' }); - return hooks.then(actual => { +async function makeCallbackWithResource (binding) { + const hooks = installAsyncHooksForTest('async_context_test'); + const triggerAsyncId = asyncHooks.executionAsyncId(); + await new Promise((resolve, reject) => { + binding.asynccontext.makeCallback(common.mustCall(), { foo: 'foo' }); + hooks.then(actual => { assert.deepStrictEqual(actual, [ - { eventName: 'init', + { + eventName: 'init', type: 'async_context_test', triggerAsyncId: triggerAsyncId, - resource: { foo: 'foo' } }, + resource: { foo: 'foo' } + }, + { eventName: 'before' }, + { eventName: 'after' }, + { eventName: 'destroy' } + ]); + }).catch(common.mustNotCall()); + resolve(); + }); +} + +async function makeCallbackWithoutResource (binding) { + const hooks = installAsyncHooksForTest('async_context_no_res_test'); + const triggerAsyncId = asyncHooks.executionAsyncId(); + await new Promise((resolve, reject) => { + binding.asynccontext.makeCallbackNoResource(common.mustCall()); + hooks.then(actual => { + assert.deepStrictEqual(actual, [ + { + eventName: 'init', + type: 'async_context_no_res_test', + triggerAsyncId: triggerAsyncId, + resource: { } + }, { eventName: 'before' }, { eventName: 'after' }, { eventName: 'destroy' } ]); - }).catch(common.mustNotCall()); + }).catch(common.mustNotCall()); + resolve(); + }); +} + +function assertAsyncContextReturnsCorrectEnv (binding) { + assert.strictEqual(binding.asynccontext.asyncCxtReturnCorrectEnv(), true); +} + +async function test (binding) { + if (!checkAsyncHooks()) { + return; + } + + await makeCallbackWithResource(binding); + await makeCallbackWithoutResource(binding); + assertAsyncContextReturnsCorrectEnv(binding); }