| 'use strict'; |
| const common = require('../common'); |
| if (process.config.variables.node_without_node_options) |
| common.skip('missing NODE_OPTIONS support'); |
| |
| // Test options specified by env variable. |
| |
| const assert = require('assert'); |
| const exec = require('child_process').execFile; |
| const { Worker } = require('worker_threads'); |
| |
| const tmpdir = require('../common/tmpdir'); |
| tmpdir.refresh(); |
| |
| const printA = require.resolve('../fixtures/printA.js'); |
| const printSpaceA = require.resolve('../fixtures/print A.js'); |
| |
| expectNoWorker(` -r ${printA} `, 'A\nB\n'); |
| expectNoWorker(`-r ${printA}`, 'A\nB\n'); |
| expectNoWorker(`-r ${JSON.stringify(printA)}`, 'A\nB\n'); |
| expectNoWorker(`-r ${JSON.stringify(printSpaceA)}`, 'A\nB\n'); |
| expectNoWorker(`-r ${printA} -r ${printA}`, 'A\nB\n'); |
| expectNoWorker(` -r ${printA} -r ${printA}`, 'A\nB\n'); |
| expectNoWorker(` --require ${printA} --require ${printA}`, 'A\nB\n'); |
| expect('--no-deprecation', 'B\n'); |
| expect('--no-warnings', 'B\n'); |
| expect('--no_warnings', 'B\n'); |
| expect('--trace-warnings', 'B\n'); |
| expect('--no-extra-info-on-fatal-exception', 'B\n'); |
| expect('--redirect-warnings=_', 'B\n'); |
| expect('--trace-deprecation', 'B\n'); |
| expect('--trace-sync-io', 'B\n'); |
| expectNoWorker('--trace-events-enabled', 'B\n'); |
| expect('--track-heap-objects', 'B\n'); |
| expect('--throw-deprecation', |
| /.*DeprecationWarning: Buffer\(\) is deprecated due to security and usability issues.*/, |
| 'new Buffer(42)', |
| true); |
| expectNoWorker('--zero-fill-buffers', 'B\n'); |
| expectNoWorker('--v8-pool-size=10', 'B\n'); |
| expectNoWorker('--trace-event-categories node', 'B\n'); |
| expectNoWorker( |
| // eslint-disable-next-line no-template-curly-in-string |
| '--trace-event-file-pattern {pid}-${rotation}.trace_events', |
| 'B\n' |
| ); |
| // eslint-disable-next-line no-template-curly-in-string |
| expectNoWorker('--trace-event-file-pattern {pid}-${rotation}.trace_events ' + |
| '--trace-event-categories node.async_hooks', 'B\n'); |
| expect('--unhandled-rejections=none', 'B\n'); |
| |
| if (common.isLinux) { |
| expect('--perf-basic-prof', 'B\n'); |
| expect('--perf-basic-prof-only-functions', 'B\n'); |
| |
| if (['arm', 'x64'].includes(process.arch)) { |
| expect('--perf-prof', 'B\n'); |
| expect('--perf-prof-unwinding-info', 'B\n'); |
| } |
| } |
| |
| if (common.hasCrypto) { |
| expectNoWorker('--use-openssl-ca', 'B\n'); |
| expectNoWorker('--use-bundled-ca', 'B\n'); |
| if (!common.hasOpenSSL3) |
| expectNoWorker('--openssl-config=_ossl_cfg', 'B\n'); |
| } |
| |
| // V8 options |
| expect('--abort_on-uncaught_exception', 'B\n'); |
| expect('--disallow-code-generation-from-strings', 'B\n'); |
| expect('--huge-max-old-generation-size', 'B\n'); |
| expect('--jitless', 'B\n'); |
| expect('--max-old-space-size=0', 'B\n'); |
| expect('--stack-trace-limit=100', |
| /(\s*at f \(\[(eval|worker eval)\]:1:\d*\)\r?\n)/, |
| '(function f() { f(); })();', |
| true); |
| // Unsupported on arm. See https://crbug.com/v8/8713. |
| if (!['arm', 'arm64'].includes(process.arch)) |
| expect('--interpreted-frames-native-stack', 'B\n'); |
| |
| // Workers can't eval as ES Modules. https://github.com/nodejs/node/issues/30682 |
| expectNoWorker('--input-type=module', |
| 'B\n', 'console.log(await "B")'); |
| |
| function expectNoWorker(opt, want, command, wantsError) { |
| expect(opt, want, command, wantsError, false); |
| } |
| |
| function expect( |
| opt, want, command = 'console.log("B")', wantsError = false, testWorker = true |
| ) { |
| const argv = ['-e', command]; |
| const opts = { |
| cwd: tmpdir.path, |
| env: Object.assign({}, process.env, { NODE_OPTIONS: opt }), |
| maxBuffer: 1e6, |
| }; |
| if (typeof want === 'string') |
| want = new RegExp(want); |
| |
| const test = (type) => common.mustCall((err, stdout) => { |
| const o = JSON.stringify(opt); |
| if (wantsError) { |
| assert.ok(err, `${type}: expected error for ${o}`); |
| stdout = err.stack; |
| } else { |
| assert.ifError(err, `${type}: failed for ${o}`); |
| } |
| if (want.test(stdout)) return; |
| |
| assert.fail( |
| `${type}: for ${o}, failed to find ${want} in: <\n${stdout}\n>` |
| ); |
| }); |
| |
| exec(process.execPath, argv, opts, test('child process')); |
| if (testWorker) |
| workerTest(opts, command, wantsError, test('worker')); |
| } |
| |
| async function collectStream(readable) { |
| readable.setEncoding('utf8'); |
| let data = ''; |
| for await (const chunk of readable) { |
| data += chunk; |
| } |
| return data; |
| } |
| |
| function workerTest(opts, command, wantsError, test) { |
| let workerError = null; |
| const worker = new Worker(command, { |
| ...opts, |
| execArgv: [], |
| eval: true, |
| stdout: true, |
| stderr: true |
| }); |
| worker.on('error', (err) => { |
| workerError = err; |
| }); |
| worker.on('exit', common.mustCall((code) => { |
| assert.strictEqual(code, wantsError ? 1 : 0); |
| collectStream(worker.stdout).then((stdout) => { |
| test(workerError, stdout); |
| }); |
| })); |
| } |