aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorAnna Henningsen <anna@addaleax.net>2019-02-17 23:45:14 +0100
committerAnna Henningsen <anna@addaleax.net>2019-02-22 21:42:09 +0100
commit8ebd339031cf9826629ad780dd35fee130e95985 (patch)
tree6a8a1b59040f55404e3cb3e3cf2860bd4879bd40 /test
parent455b927be0111a6aa8f1e30ae5b21659afeba40d (diff)
downloadandroid-node-v8-8ebd339031cf9826629ad780dd35fee130e95985.tar.gz
android-node-v8-8ebd339031cf9826629ad780dd35fee130e95985.tar.bz2
android-node-v8-8ebd339031cf9826629ad780dd35fee130e95985.zip
worker: improve integration with native addons
Allow loading add-ons from multiple Node.js instances if they are declared context-aware; in particular, this applies to N-API addons. Also, plug a memory leak that occurred when registering N-API addons. Refs: https://github.com/nodejs/node/pull/23319 PR-URL: https://github.com/nodejs/node/pull/26175 Fixes: https://github.com/nodejs/node/issues/21481 Fixes: https://github.com/nodejs/node/issues/21783 Fixes: https://github.com/nodejs/node/issues/25662 Fixes: https://github.com/nodejs/node/issues/20239 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com> Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Diffstat (limited to 'test')
-rw-r--r--test/addons/dlopen-ping-pong/test-worker.js20
-rw-r--r--test/addons/worker-addon/binding.cc2
-rw-r--r--test/addons/worker-addon/test.js60
-rw-r--r--test/node-api/1_hello_world/test.js9
-rw-r--r--test/node-api/test_worker_terminate/test.js5
-rw-r--r--test/node-api/test_worker_terminate/test_worker_terminate.c2
6 files changed, 88 insertions, 10 deletions
diff --git a/test/addons/dlopen-ping-pong/test-worker.js b/test/addons/dlopen-ping-pong/test-worker.js
new file mode 100644
index 0000000000..feba6aa5eb
--- /dev/null
+++ b/test/addons/dlopen-ping-pong/test-worker.js
@@ -0,0 +1,20 @@
+'use strict';
+const common = require('../../common');
+
+if (common.isWindows)
+ common.skip('dlopen global symbol loading is not supported on this os.');
+
+const assert = require('assert');
+const { Worker } = require('worker_threads');
+
+// Check that modules that are not declared as context-aware cannot be re-loaded
+// from workers.
+
+const bindingPath = require.resolve(`./build/${common.buildType}/binding`);
+require(bindingPath);
+
+new Worker(`require(${JSON.stringify(bindingPath)})`, { eval: true })
+ .on('error', common.mustCall((err) => {
+ assert.strictEqual(err.constructor, Error);
+ assert.strictEqual(err.message, 'Module did not self-register.');
+ }));
diff --git a/test/addons/worker-addon/binding.cc b/test/addons/worker-addon/binding.cc
index faf3ba8647..01c857c43e 100644
--- a/test/addons/worker-addon/binding.cc
+++ b/test/addons/worker-addon/binding.cc
@@ -21,7 +21,7 @@ struct statically_allocated {
}
~statically_allocated() {
assert(count == 0);
- printf("dtor");
+ printf("dtor ");
}
} var;
diff --git a/test/addons/worker-addon/test.js b/test/addons/worker-addon/test.js
index 7fb7c1a87a..ef158e98b1 100644
--- a/test/addons/worker-addon/test.js
+++ b/test/addons/worker-addon/test.js
@@ -1,3 +1,4 @@
+// Flags: --experimental-report
'use strict';
const common = require('../../common');
const assert = require('assert');
@@ -6,21 +7,62 @@ const path = require('path');
const { Worker } = require('worker_threads');
const binding = path.resolve(__dirname, `./build/${common.buildType}/binding`);
-if (process.argv[2] === 'worker') {
- new Worker(`require(${JSON.stringify(binding)});`, { eval: true });
- return;
-} else if (process.argv[2] === 'main-thread') {
- process.env.addExtraItemToEventLoop = 'yes';
- require(binding);
- return;
+switch (process.argv[2]) {
+ case 'both':
+ require(binding);
+ // fallthrough
+ case 'worker-twice':
+ case 'worker':
+ const worker = new Worker(`require(${JSON.stringify(binding)});`, {
+ eval: true
+ });
+ if (process.argv[2] === 'worker-twice') {
+ worker.on('exit', common.mustCall(() => {
+ new Worker(`require(${JSON.stringify(binding)});`, {
+ eval: true
+ });
+ }));
+ }
+ return;
+ case 'main-thread':
+ process.env.addExtraItemToEventLoop = 'yes';
+ require(binding);
+ return;
}
-for (const test of ['worker', 'main-thread']) {
+// Use process.report to figure out if we might be running under musl libc.
+const glibc = JSON.parse(process.report.getReport()).header.glibcVersionRuntime;
+assert(typeof glibc === 'string' || glibc === undefined, glibc);
+
+const libcMayBeMusl = common.isLinux && glibc === undefined;
+
+for (const { test, expected } of [
+ { test: 'worker', expected: [ 'ctor cleanup dtor ' ] },
+ { test: 'main-thread', expected: [ 'ctor cleanup dtor ' ] },
+ // We always only have 1 instance of the shared object in memory, so
+ // 1 ctor and 1 dtor call. If we attach the module to 2 Environments,
+ // we expect 2 cleanup calls, otherwise one.
+ { test: 'both', expected: [ 'ctor cleanup cleanup dtor ' ] },
+ {
+ test: 'worker-twice',
+ // In this case, we load and unload an addon, then load and unload again.
+ // musl doesn't support unloading, so the output may be missing
+ // a dtor + ctor pair.
+ expected: [
+ 'ctor cleanup dtor ctor cleanup dtor '
+ ].concat(libcMayBeMusl ? [
+ 'ctor cleanup cleanup dtor ',
+ ] : [])
+ },
+]) {
+ console.log('spawning test', test);
const proc = child_process.spawnSync(process.execPath, [
__filename,
test
]);
+ process.stderr.write(proc.stderr.toString());
assert.strictEqual(proc.stderr.toString(), '');
- assert.strictEqual(proc.stdout.toString(), 'ctor cleanup dtor');
+ assert(expected.includes(proc.stdout.toString()),
+ `${proc.stdout.toString()} is not included in ${expected}`);
assert.strictEqual(proc.status, 0);
}
diff --git a/test/node-api/1_hello_world/test.js b/test/node-api/1_hello_world/test.js
index d1d67d34f6..dd28e26a56 100644
--- a/test/node-api/1_hello_world/test.js
+++ b/test/node-api/1_hello_world/test.js
@@ -1,6 +1,8 @@
'use strict';
const common = require('../../common');
const assert = require('assert');
+const { Worker } = require('worker_threads');
+
const bindingPath = require.resolve(`./build/${common.buildType}/binding`);
const binding = require(bindingPath);
assert.strictEqual(binding.hello(), 'world');
@@ -11,3 +13,10 @@ delete require.cache[bindingPath];
const rebinding = require(bindingPath);
assert.strictEqual(rebinding.hello(), 'world');
assert.notStrictEqual(binding.hello, rebinding.hello);
+
+// Test that workers can load addons declared using NAPI_MODULE_INIT().
+new Worker(`
+const { parentPort } = require('worker_threads');
+const msg = require(${JSON.stringify(bindingPath)}).hello();
+parentPort.postMessage(msg)`, { eval: true })
+ .on('message', common.mustCall((msg) => assert.strictEqual(msg, 'world')));
diff --git a/test/node-api/test_worker_terminate/test.js b/test/node-api/test_worker_terminate/test.js
index 2bfaab8e8e..7c7224c073 100644
--- a/test/node-api/test_worker_terminate/test.js
+++ b/test/node-api/test_worker_terminate/test.js
@@ -4,6 +4,11 @@ const assert = require('assert');
const { Worker, isMainThread, workerData } = require('worker_threads');
if (isMainThread) {
+ // Load the addon in the main thread first.
+ // This checks that N-API addons can be loaded from multiple contexts
+ // when they are not loaded through NAPI_MODULE().
+ require(`./build/${common.buildType}/test_worker_terminate`);
+
const counter = new Int32Array(new SharedArrayBuffer(4));
const worker = new Worker(__filename, { workerData: { counter } });
worker.on('exit', common.mustCall(() => {
diff --git a/test/node-api/test_worker_terminate/test_worker_terminate.c b/test/node-api/test_worker_terminate/test_worker_terminate.c
index a88d936293..517cae4203 100644
--- a/test/node-api/test_worker_terminate/test_worker_terminate.c
+++ b/test/node-api/test_worker_terminate/test_worker_terminate.c
@@ -36,4 +36,6 @@ napi_value Init(napi_env env, napi_value exports) {
return exports;
}
+// Do not start using NAPI_MODULE_INIT() here, so that we can test
+// compatibility of Workers with NAPI_MODULE().
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)