Skip to content

Commit c56d604

Browse files
addaleaxjasnell
authored andcommitted
test: add AsyncResource addon test
PR-URL: #13142 Reviewed-By: Matthew Loring <[email protected]> Reviewed-By: Andreas Madsen <[email protected]>
1 parent 60a2fe7 commit c56d604

File tree

3 files changed

+201
-0
lines changed

3 files changed

+201
-0
lines changed

test/addons/async-resource/binding.cc

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#include "node.h"
2+
3+
#include <assert.h>
4+
#include <vector>
5+
6+
namespace {
7+
8+
using node::AsyncResource;
9+
using v8::External;
10+
using v8::Function;
11+
using v8::FunctionCallbackInfo;
12+
using v8::Integer;
13+
using v8::Isolate;
14+
using v8::Local;
15+
using v8::MaybeLocal;
16+
using v8::Object;
17+
using v8::String;
18+
using v8::Value;
19+
20+
void CreateAsyncResource(const FunctionCallbackInfo<Value>& args) {
21+
Isolate* isolate = args.GetIsolate();
22+
assert(args[0]->IsObject());
23+
AsyncResource* r;
24+
if (args[1]->IsInt32()) {
25+
r = new AsyncResource(isolate, args[0].As<Object>(), "foobär",
26+
args[1].As<Integer>()->Value());
27+
} else {
28+
r = new AsyncResource(isolate, args[0].As<Object>(), "foobär");
29+
}
30+
31+
args.GetReturnValue().Set(
32+
External::New(isolate, static_cast<void*>(r)));
33+
}
34+
35+
void DestroyAsyncResource(const FunctionCallbackInfo<Value>& args) {
36+
assert(args[0]->IsExternal());
37+
auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value());
38+
delete r;
39+
}
40+
41+
void CallViaFunction(const FunctionCallbackInfo<Value>& args) {
42+
Isolate* isolate = args.GetIsolate();
43+
assert(args[0]->IsExternal());
44+
auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value());
45+
46+
Local<String> name =
47+
String::NewFromUtf8(isolate, "methöd", v8::NewStringType::kNormal)
48+
.ToLocalChecked();
49+
Local<Value> fn =
50+
r->get_resource()->Get(isolate->GetCurrentContext(), name)
51+
.ToLocalChecked();
52+
assert(fn->IsFunction());
53+
54+
Local<Value> arg = Integer::New(isolate, 42);
55+
MaybeLocal<Value> ret = r->MakeCallback(fn.As<Function>(), 1, &arg);
56+
args.GetReturnValue().Set(ret.FromMaybe(Local<Value>()));
57+
}
58+
59+
void CallViaString(const FunctionCallbackInfo<Value>& args) {
60+
Isolate* isolate = args.GetIsolate();
61+
assert(args[0]->IsExternal());
62+
auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value());
63+
64+
Local<String> name =
65+
String::NewFromUtf8(isolate, "methöd", v8::NewStringType::kNormal)
66+
.ToLocalChecked();
67+
68+
Local<Value> arg = Integer::New(isolate, 42);
69+
MaybeLocal<Value> ret = r->MakeCallback(name, 1, &arg);
70+
args.GetReturnValue().Set(ret.FromMaybe(Local<Value>()));
71+
}
72+
73+
void CallViaUtf8Name(const FunctionCallbackInfo<Value>& args) {
74+
Isolate* isolate = args.GetIsolate();
75+
assert(args[0]->IsExternal());
76+
auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value());
77+
78+
Local<Value> arg = Integer::New(isolate, 42);
79+
MaybeLocal<Value> ret = r->MakeCallback("methöd", 1, &arg);
80+
args.GetReturnValue().Set(ret.FromMaybe(Local<Value>()));
81+
}
82+
83+
void GetUid(const FunctionCallbackInfo<Value>& args) {
84+
assert(args[0]->IsExternal());
85+
auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value());
86+
args.GetReturnValue().Set(r->get_uid());
87+
}
88+
89+
void GetResource(const FunctionCallbackInfo<Value>& args) {
90+
assert(args[0]->IsExternal());
91+
auto r = static_cast<AsyncResource*>(args[0].As<External>()->Value());
92+
args.GetReturnValue().Set(r->get_resource());
93+
}
94+
95+
void GetCurrentId(const FunctionCallbackInfo<Value>& args) {
96+
args.GetReturnValue().Set(node::AsyncHooksGetCurrentId(args.GetIsolate()));
97+
}
98+
99+
void Initialize(Local<Object> exports) {
100+
NODE_SET_METHOD(exports, "createAsyncResource", CreateAsyncResource);
101+
NODE_SET_METHOD(exports, "destroyAsyncResource", DestroyAsyncResource);
102+
NODE_SET_METHOD(exports, "callViaFunction", CallViaFunction);
103+
NODE_SET_METHOD(exports, "callViaString", CallViaString);
104+
NODE_SET_METHOD(exports, "callViaUtf8Name", CallViaUtf8Name);
105+
NODE_SET_METHOD(exports, "getUid", GetUid);
106+
NODE_SET_METHOD(exports, "getResource", GetResource);
107+
NODE_SET_METHOD(exports, "getCurrentId", GetCurrentId);
108+
}
109+
110+
} // namespace
111+
112+
NODE_MODULE(binding, Initialize)
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
'targets': [
3+
{
4+
'target_name': 'binding',
5+
'defines': [ 'V8_DEPRECATION_WARNINGS=1' ],
6+
'sources': [ 'binding.cc' ]
7+
}
8+
]
9+
}

test/addons/async-resource/test.js

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
'use strict';
2+
3+
const common = require('../../common');
4+
const assert = require('assert');
5+
const binding = require(`./build/${common.buildType}/binding`);
6+
const async_hooks = require('async_hooks');
7+
8+
const kObjectTag = Symbol('kObjectTag');
9+
10+
const bindingUids = [];
11+
let expectedTriggerId;
12+
let before = 0;
13+
let after = 0;
14+
let destroy = 0;
15+
16+
async_hooks.createHook({
17+
init(id, type, triggerId, resource) {
18+
assert.strictEqual(typeof id, 'number');
19+
assert.strictEqual(typeof resource, 'object');
20+
assert(id > 1);
21+
if (type === 'foobär') {
22+
assert.strictEqual(resource.kObjectTag, kObjectTag);
23+
assert.strictEqual(triggerId, expectedTriggerId);
24+
bindingUids.push(id);
25+
}
26+
},
27+
28+
before(id) {
29+
if (bindingUids.includes(id)) before++;
30+
},
31+
32+
after(id) {
33+
if (bindingUids.includes(id)) after++;
34+
},
35+
36+
destroy(id) {
37+
if (bindingUids.includes(id)) destroy++;
38+
}
39+
}).enable();
40+
41+
assert.strictEqual(binding.getCurrentId(), 1);
42+
43+
for (const call of [binding.callViaFunction,
44+
binding.callViaString,
45+
binding.callViaUtf8Name]) {
46+
for (const passedTriggerId of [undefined, 12345]) {
47+
let uid;
48+
const object = {
49+
methöd(arg) {
50+
assert.strictEqual(this, object);
51+
assert.strictEqual(arg, 42);
52+
assert.strictEqual(binding.getCurrentId(), uid);
53+
return 'baz';
54+
},
55+
kObjectTag
56+
};
57+
58+
if (passedTriggerId === undefined)
59+
expectedTriggerId = 1;
60+
else
61+
expectedTriggerId = passedTriggerId;
62+
63+
const resource = binding.createAsyncResource(object, passedTriggerId);
64+
uid = bindingUids[bindingUids.length - 1];
65+
66+
const ret = call(resource);
67+
assert.strictEqual(ret, 'baz');
68+
assert.strictEqual(binding.getResource(resource), object);
69+
assert.strictEqual(binding.getUid(resource), uid);
70+
71+
binding.destroyAsyncResource(resource);
72+
}
73+
}
74+
75+
setImmediate(common.mustCall(() => {
76+
assert.strictEqual(bindingUids.length, 6);
77+
assert.strictEqual(before, bindingUids.length);
78+
assert.strictEqual(after, bindingUids.length);
79+
assert.strictEqual(destroy, bindingUids.length);
80+
}));

0 commit comments

Comments
 (0)