Skip to content

Commit f32db91

Browse files
authored
Add test coverage for async contexts (#1164)
1 parent 24455f8 commit f32db91

File tree

2 files changed

+84
-33
lines changed

2 files changed

+84
-33
lines changed

test/async_context.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,25 @@ static void MakeCallback(const CallbackInfo& info) {
1212
Object::New(info.Env()), std::initializer_list<napi_value>{}, context);
1313
}
1414

15+
static void MakeCallbackNoResource(const CallbackInfo& info) {
16+
Function callback = info[0].As<Function>();
17+
AsyncContext context(info.Env(), "async_context_no_res_test");
18+
callback.MakeCallback(
19+
Object::New(info.Env()), std::initializer_list<napi_value>{}, context);
20+
}
21+
22+
static Boolean AssertAsyncContextReturnCorrectEnv(const CallbackInfo& info) {
23+
AsyncContext context(info.Env(), "empty_context_test");
24+
return Boolean::New(info.Env(), context.Env() == info.Env());
25+
}
1526
} // end anonymous namespace
1627

1728
Object InitAsyncContext(Env env) {
1829
Object exports = Object::New(env);
1930
exports["makeCallback"] = Function::New(env, MakeCallback);
31+
exports["makeCallbackNoResource"] =
32+
Function::New(env, MakeCallbackNoResource);
33+
exports["asyncCxtReturnCorrectEnv"] =
34+
Function::New(env, AssertAsyncContextReturnCorrectEnv);
2035
return exports;
2136
}

test/async_context.js

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ const common = require('./common');
55

66
// we only check async hooks on 8.x an higher were
77
// they are closer to working properly
8-
const nodeVersion = process.versions.node.split('.')[0]
9-
let async_hooks = undefined;
10-
function checkAsyncHooks() {
8+
const nodeVersion = process.versions.node.split('.')[0];
9+
let asyncHooks;
10+
function checkAsyncHooks () {
1111
if (nodeVersion >= 8) {
12-
if (async_hooks == undefined) {
13-
async_hooks = require('async_hooks');
12+
if (asyncHooks === undefined) {
13+
asyncHooks = require('async_hooks');
1414
}
1515
return true;
1616
}
@@ -19,68 +19,104 @@ function checkAsyncHooks() {
1919

2020
module.exports = common.runTest(test);
2121

22-
function installAsyncHooksForTest() {
22+
function installAsyncHooksForTest (resName) {
2323
return new Promise((resolve, reject) => {
2424
let id;
2525
const events = [];
2626
/**
2727
* TODO(legendecas): investigate why resolving & disabling hooks in
2828
* destroy callback causing crash with case 'callbackscope.js'.
2929
*/
30-
let hook;
3130
let destroyed = false;
32-
const interval = setInterval(() => {
33-
if (destroyed) {
34-
hook.disable();
35-
clearInterval(interval);
36-
resolve(events);
37-
}
38-
}, 10);
39-
40-
hook = async_hooks.createHook({
41-
init(asyncId, type, triggerAsyncId, resource) {
42-
if (id === undefined && type === 'async_context_test') {
31+
const hook = asyncHooks.createHook({
32+
init (asyncId, type, triggerAsyncId, resource) {
33+
if (id === undefined && type === resName) {
4334
id = asyncId;
4435
events.push({ eventName: 'init', type, triggerAsyncId, resource });
4536
}
4637
},
47-
before(asyncId) {
38+
before (asyncId) {
4839
if (asyncId === id) {
4940
events.push({ eventName: 'before' });
5041
}
5142
},
52-
after(asyncId) {
43+
after (asyncId) {
5344
if (asyncId === id) {
5445
events.push({ eventName: 'after' });
5546
}
5647
},
57-
destroy(asyncId) {
48+
destroy (asyncId) {
5849
if (asyncId === id) {
5950
events.push({ eventName: 'destroy' });
6051
destroyed = true;
6152
}
6253
}
6354
}).enable();
55+
56+
const interval = setInterval(() => {
57+
if (destroyed) {
58+
hook.disable();
59+
clearInterval(interval);
60+
resolve(events);
61+
}
62+
}, 10);
6463
});
6564
}
6665

67-
function test(binding) {
68-
if (!checkAsyncHooks()) {
69-
return;
70-
}
71-
72-
const hooks = installAsyncHooksForTest();
73-
const triggerAsyncId = async_hooks.executionAsyncId();
74-
binding.asynccontext.makeCallback(common.mustCall(), { foo: 'foo' });
75-
return hooks.then(actual => {
66+
async function makeCallbackWithResource (binding) {
67+
const hooks = installAsyncHooksForTest('async_context_test');
68+
const triggerAsyncId = asyncHooks.executionAsyncId();
69+
await new Promise((resolve, reject) => {
70+
binding.asynccontext.makeCallback(common.mustCall(), { foo: 'foo' });
71+
hooks.then(actual => {
7672
assert.deepStrictEqual(actual, [
77-
{ eventName: 'init',
73+
{
74+
eventName: 'init',
7875
type: 'async_context_test',
7976
triggerAsyncId: triggerAsyncId,
80-
resource: { foo: 'foo' } },
77+
resource: { foo: 'foo' }
78+
},
79+
{ eventName: 'before' },
80+
{ eventName: 'after' },
81+
{ eventName: 'destroy' }
82+
]);
83+
}).catch(common.mustNotCall());
84+
resolve();
85+
});
86+
}
87+
88+
async function makeCallbackWithoutResource (binding) {
89+
const hooks = installAsyncHooksForTest('async_context_no_res_test');
90+
const triggerAsyncId = asyncHooks.executionAsyncId();
91+
await new Promise((resolve, reject) => {
92+
binding.asynccontext.makeCallbackNoResource(common.mustCall());
93+
hooks.then(actual => {
94+
assert.deepStrictEqual(actual, [
95+
{
96+
eventName: 'init',
97+
type: 'async_context_no_res_test',
98+
triggerAsyncId: triggerAsyncId,
99+
resource: { }
100+
},
81101
{ eventName: 'before' },
82102
{ eventName: 'after' },
83103
{ eventName: 'destroy' }
84104
]);
85-
}).catch(common.mustNotCall());
105+
}).catch(common.mustNotCall());
106+
resolve();
107+
});
108+
}
109+
110+
function assertAsyncContextReturnsCorrectEnv (binding) {
111+
assert.strictEqual(binding.asynccontext.asyncCxtReturnCorrectEnv(), true);
112+
}
113+
114+
async function test (binding) {
115+
if (!checkAsyncHooks()) {
116+
return;
117+
}
118+
119+
await makeCallbackWithResource(binding);
120+
await makeCallbackWithoutResource(binding);
121+
assertAsyncContextReturnsCorrectEnv(binding);
86122
}

0 commit comments

Comments
 (0)