|
1 | 1 | 'use strict';
|
2 | 2 | const buildType = process.config.target_defaults.default_configuration;
|
3 | 3 | const assert = require('assert');
|
| 4 | +const { spawnSync } = require('child_process'); |
4 | 5 | const testUtil = require('./testUtil');
|
5 | 6 |
|
6 |
| -module.exports = test(require(`./build/${buildType}/binding.node`)) |
7 |
| - .then(() => test(require(`./build/${buildType}/binding_noexcept.node`))); |
| 7 | +if (process.argv.length === 3) { |
| 8 | + let interval; |
| 9 | + |
| 10 | + // Running as the child process, hook up an `uncaughtException` handler to |
| 11 | + // examine the error thrown by the finalizer. |
| 12 | + process.on('uncaughtException', (error) => { |
| 13 | + // TODO (gabrielschulhof): Use assert.matches() when we drop support for |
| 14 | + // Node.js v10.x. |
| 15 | + assert(!!error.message.match(/Finalizer exception/)); |
| 16 | + if (interval) { |
| 17 | + clearInterval(interval); |
| 18 | + } |
| 19 | + process.exit(0); |
| 20 | + }); |
| 21 | + |
| 22 | + // Create an external whose finalizer throws. |
| 23 | + (() => |
| 24 | + require(process.argv[2]).external.createExternalWithFinalizeException())(); |
| 25 | + |
| 26 | + // gc until the external's finalizer throws or until we give up. Since the |
| 27 | + // exception is thrown from a native `SetImmediate()` we cannot catch it |
| 28 | + // anywhere except in the process' `uncaughtException` handler. |
| 29 | + let maxGCTries = 10; |
| 30 | + (function gcInterval() { |
| 31 | + global.gc(); |
| 32 | + if (!interval) { |
| 33 | + interval = setInterval(gcInterval, 100); |
| 34 | + } else if (--maxGCTries === 0) { |
| 35 | + throw new Error('Timed out waiting for the gc to throw'); |
| 36 | + process.exit(1); |
| 37 | + } |
| 38 | + })(); |
| 39 | + |
| 40 | + return; |
| 41 | +} |
| 42 | + |
| 43 | +module.exports = test(require.resolve(`./build/${buildType}/binding.node`)) |
| 44 | + .then(() => |
| 45 | + test(require.resolve(`./build/${buildType}/binding_noexcept.node`))); |
| 46 | + |
| 47 | +function test(bindingPath) { |
| 48 | + const binding = require(bindingPath); |
| 49 | + |
| 50 | + const child = spawnSync(process.execPath, [ |
| 51 | + '--expose-gc', __filename, bindingPath |
| 52 | + ], { stdio: 'inherit' }); |
| 53 | + assert.strictEqual(child.status, 0); |
| 54 | + assert.strictEqual(child.signal, null); |
8 | 55 |
|
9 |
| -function test(binding) { |
10 | 56 | return testUtil.runGCTests([
|
11 | 57 | 'External without finalizer',
|
12 | 58 | () => {
|
|
0 commit comments