• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright Joyent, Inc. and other Node contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a
4// copy of this software and associated documentation files (the
5// "Software"), to deal in the Software without restriction, including
6// without limitation the rights to use, copy, modify, merge, publish,
7// distribute, sublicense, and/or sell copies of the Software, and to permit
8// persons to whom the Software is furnished to do so, subject to the
9// following conditions:
10//
11// The above copyright notice and this permission notice shall be included
12// in all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22/* eslint-disable node-core/crypto-check */
23'use strict';
24const process = global.process;  // Some tests tamper with the process global.
25
26const assert = require('assert');
27const { exec, execSync, spawnSync } = require('child_process');
28const fs = require('fs');
29// Do not require 'os' until needed so that test-os-checked-function can
30// monkey patch it. If 'os' is required here, that test will fail.
31const path = require('path');
32const util = require('util');
33const { isMainThread } = require('worker_threads');
34
35const tmpdir = require('./tmpdir');
36const bits = ['arm64', 'mips', 'mipsel', 'ppc64', 's390x', 'x64']
37  .includes(process.arch) ? 64 : 32;
38const hasIntl = !!process.config.variables.v8_enable_i18n_support;
39
40// Some tests assume a umask of 0o022 so set that up front. Tests that need a
41// different umask will set it themselves.
42//
43// Workers can read, but not set the umask, so check that this is the main
44// thread.
45if (isMainThread)
46  process.umask(0o022);
47
48const noop = () => {};
49
50const hasCrypto = Boolean(process.versions.openssl) &&
51                  !process.env.NODE_SKIP_CRYPTO;
52
53const hasOpenSSL3 = hasCrypto &&
54    require('crypto').constants.OPENSSL_VERSION_NUMBER >= 805306368;
55
56const hasQuic = hasCrypto && !!process.config.variables.openssl_quic;
57
58// Check for flags. Skip this for workers (both, the `cluster` module and
59// `worker_threads`) and child processes.
60// If the binary was built without-ssl then the crypto flags are
61// invalid (bad option). The test itself should handle this case.
62if (process.argv.length === 2 &&
63    !process.env.NODE_SKIP_FLAG_CHECK &&
64    isMainThread &&
65    hasCrypto &&
66    require.main &&
67    require('cluster').isMaster) {
68  // The copyright notice is relatively big and the flags could come afterwards.
69  const bytesToRead = 1500;
70  const buffer = Buffer.allocUnsafe(bytesToRead);
71  const fd = fs.openSync(require.main.filename, 'r');
72  const bytesRead = fs.readSync(fd, buffer, 0, bytesToRead);
73  fs.closeSync(fd);
74  const source = buffer.toString('utf8', 0, bytesRead);
75
76  const flagStart = source.indexOf('// Flags: --') + 10;
77  if (flagStart !== 9) {
78    let flagEnd = source.indexOf('\n', flagStart);
79    // Normalize different EOL.
80    if (source[flagEnd - 1] === '\r') {
81      flagEnd--;
82    }
83    const flags = source
84      .substring(flagStart, flagEnd)
85      .replace(/_/g, '-')
86      .split(' ');
87    const args = process.execArgv.map((arg) => arg.replace(/_/g, '-'));
88    for (const flag of flags) {
89      if (!args.includes(flag) &&
90          // If the binary is build without `intl` the inspect option is
91          // invalid. The test itself should handle this case.
92          (process.features.inspector || !flag.startsWith('--inspect'))) {
93        console.log(
94          'NOTE: The test started as a child_process using these flags:',
95          util.inspect(flags),
96          'Use NODE_SKIP_FLAG_CHECK to run the test with the original flags.'
97        );
98        const args = [...flags, ...process.execArgv, ...process.argv.slice(1)];
99        const options = { encoding: 'utf8', stdio: 'inherit' };
100        const result = spawnSync(process.execPath, args, options);
101        if (result.signal) {
102          process.kill(0, result.signal);
103        } else {
104          process.exit(result.status);
105        }
106      }
107    }
108  }
109}
110
111const isWindows = process.platform === 'win32';
112const isAIX = process.platform === 'aix';
113const isSunOS = process.platform === 'sunos';
114const isFreeBSD = process.platform === 'freebsd';
115const isOpenBSD = process.platform === 'openbsd';
116const isLinux = process.platform === 'linux';
117const isOSX = process.platform === 'darwin';
118
119const isDumbTerminal = process.env.TERM === 'dumb';
120
121const buildType = process.config.target_defaults ?
122  process.config.target_defaults.default_configuration :
123  'Release';
124
125// If env var is set then enable async_hook hooks for all tests.
126if (process.env.NODE_TEST_WITH_ASYNC_HOOKS) {
127  const destroydIdsList = {};
128  const destroyListList = {};
129  const initHandles = {};
130  const { internalBinding } = require('internal/test/binding');
131  const async_wrap = internalBinding('async_wrap');
132
133  process.on('exit', () => {
134    // Iterate through handles to make sure nothing crashes
135    for (const k in initHandles)
136      util.inspect(initHandles[k]);
137  });
138
139  const _queueDestroyAsyncId = async_wrap.queueDestroyAsyncId;
140  async_wrap.queueDestroyAsyncId = function queueDestroyAsyncId(id) {
141    if (destroyListList[id] !== undefined) {
142      process._rawDebug(destroyListList[id]);
143      process._rawDebug();
144      throw new Error(`same id added to destroy list twice (${id})`);
145    }
146    destroyListList[id] = util.inspect(new Error());
147    _queueDestroyAsyncId(id);
148  };
149
150  require('async_hooks').createHook({
151    init(id, ty, tr, resource) {
152      if (initHandles[id]) {
153        process._rawDebug(
154          `Is same resource: ${resource === initHandles[id].resource}`);
155        process._rawDebug(`Previous stack:\n${initHandles[id].stack}\n`);
156        throw new Error(`init called twice for same id (${id})`);
157      }
158      initHandles[id] = {
159        resource,
160        stack: util.inspect(new Error()).substr(6)
161      };
162    },
163    before() { },
164    after() { },
165    destroy(id) {
166      if (destroydIdsList[id] !== undefined) {
167        process._rawDebug(destroydIdsList[id]);
168        process._rawDebug();
169        throw new Error(`destroy called for same id (${id})`);
170      }
171      destroydIdsList[id] = util.inspect(new Error());
172    },
173  }).enable();
174}
175
176let opensslCli = null;
177let inFreeBSDJail = null;
178let localhostIPv4 = null;
179
180const localIPv6Hosts =
181  isLinux ? [
182    // Debian/Ubuntu
183    'ip6-localhost',
184    'ip6-loopback',
185
186    // SUSE
187    'ipv6-localhost',
188    'ipv6-loopback',
189
190    // Typically universal
191    'localhost',
192  ] : [ 'localhost' ];
193
194const PIPE = (() => {
195  const localRelative = path.relative(process.cwd(), `${tmpdir.path}/`);
196  const pipePrefix = isWindows ? '\\\\.\\pipe\\' : localRelative;
197  const pipeName = `node-test.${process.pid}.sock`;
198  return path.join(pipePrefix, pipeName);
199})();
200
201// Check that when running a test with
202// `$node --abort-on-uncaught-exception $file child`
203// the process aborts.
204function childShouldThrowAndAbort() {
205  let testCmd = '';
206  if (!isWindows) {
207    // Do not create core files, as it can take a lot of disk space on
208    // continuous testing and developers' machines
209    testCmd += 'ulimit -c 0 && ';
210  }
211  testCmd += `"${process.argv[0]}" --abort-on-uncaught-exception `;
212  testCmd += `"${process.argv[1]}" child`;
213  const child = exec(testCmd);
214  child.on('exit', function onExit(exitCode, signal) {
215    const errMsg = 'Test should have aborted ' +
216                   `but instead exited with exit code ${exitCode}` +
217                   ` and signal ${signal}`;
218    assert(nodeProcessAborted(exitCode, signal), errMsg);
219  });
220}
221
222function createZeroFilledFile(filename) {
223  const fd = fs.openSync(filename, 'w');
224  fs.ftruncateSync(fd, 10 * 1024 * 1024);
225  fs.closeSync(fd);
226}
227
228
229const pwdCommand = isWindows ?
230  ['cmd.exe', ['/d', '/c', 'cd']] :
231  ['pwd', []];
232
233
234function platformTimeout(ms) {
235  const multipliers = typeof ms === 'bigint' ?
236    { two: 2n, four: 4n, seven: 7n } : { two: 2, four: 4, seven: 7 };
237
238  if (process.features.debug)
239    ms = multipliers.two * ms;
240
241  if (isAIX)
242    return multipliers.two * ms; // Default localhost speed is slower on AIX
243
244  if (process.arch !== 'arm')
245    return ms;
246
247  const armv = process.config.variables.arm_version;
248
249  if (armv === '6')
250    return multipliers.seven * ms;  // ARMv6
251
252  if (armv === '7')
253    return multipliers.two * ms;  // ARMv7
254
255  return ms; // ARMv8+
256}
257
258let knownGlobals = [
259  clearImmediate,
260  clearInterval,
261  clearTimeout,
262  global,
263  setImmediate,
264  setInterval,
265  setTimeout,
266  queueMicrotask,
267];
268
269// TODO(@jasnell): This check can be temporary. AbortController is
270// not currently supported in either Node.js 12 or 10, making it
271// difficult to run tests comparitively on those versions. Once
272// all supported versions have AbortController as a global, this
273// check can be removed and AbortController can be added to the
274// knownGlobals list above.
275if (global.AbortController)
276  knownGlobals.push(global.AbortController);
277
278if (global.gc) {
279  knownGlobals.push(global.gc);
280}
281
282function allowGlobals(...allowlist) {
283  knownGlobals = knownGlobals.concat(allowlist);
284}
285
286if (process.env.NODE_TEST_KNOWN_GLOBALS !== '0') {
287  if (process.env.NODE_TEST_KNOWN_GLOBALS) {
288    const knownFromEnv = process.env.NODE_TEST_KNOWN_GLOBALS.split(',');
289    allowGlobals(...knownFromEnv);
290  }
291
292  function leakedGlobals() {
293    const leaked = [];
294
295    for (const val in global) {
296      if (!knownGlobals.includes(global[val])) {
297        leaked.push(val);
298      }
299    }
300
301    return leaked;
302  }
303
304  process.on('exit', function() {
305    const leaked = leakedGlobals();
306    if (leaked.length > 0) {
307      assert.fail(`Unexpected global(s) found: ${leaked.join(', ')}`);
308    }
309  });
310}
311
312const mustCallChecks = [];
313
314function runCallChecks(exitCode) {
315  if (exitCode !== 0) return;
316
317  const failed = mustCallChecks.filter(function(context) {
318    if ('minimum' in context) {
319      context.messageSegment = `at least ${context.minimum}`;
320      return context.actual < context.minimum;
321    }
322    context.messageSegment = `exactly ${context.exact}`;
323    return context.actual !== context.exact;
324  });
325
326  failed.forEach(function(context) {
327    console.log('Mismatched %s function calls. Expected %s, actual %d.',
328                context.name,
329                context.messageSegment,
330                context.actual);
331    console.log(context.stack.split('\n').slice(2).join('\n'));
332  });
333
334  if (failed.length) process.exit(1);
335}
336
337function mustCall(fn, exact) {
338  return _mustCallInner(fn, exact, 'exact');
339}
340
341function mustSucceed(fn, exact) {
342  return mustCall(function(err, ...args) {
343    assert.ifError(err);
344    if (typeof fn === 'function')
345      return fn.apply(this, args);
346  }, exact);
347}
348
349function mustCallAtLeast(fn, minimum) {
350  return _mustCallInner(fn, minimum, 'minimum');
351}
352
353function _mustCallInner(fn, criteria = 1, field) {
354  if (process._exiting)
355    throw new Error('Cannot use common.mustCall*() in process exit handler');
356  if (typeof fn === 'number') {
357    criteria = fn;
358    fn = noop;
359  } else if (fn === undefined) {
360    fn = noop;
361  }
362
363  if (typeof criteria !== 'number')
364    throw new TypeError(`Invalid ${field} value: ${criteria}`);
365
366  const context = {
367    [field]: criteria,
368    actual: 0,
369    stack: util.inspect(new Error()),
370    name: fn.name || '<anonymous>'
371  };
372
373  // Add the exit listener only once to avoid listener leak warnings
374  if (mustCallChecks.length === 0) process.on('exit', runCallChecks);
375
376  mustCallChecks.push(context);
377
378  const _return = function() { // eslint-disable-line func-style
379    context.actual++;
380    return fn.apply(this, arguments);
381  };
382  // Function instances have own properties that may be relevant.
383  // Let's replicate those properties to the returned function.
384  // Refs: https://tc39.es/ecma262/#sec-function-instances
385  Object.defineProperties(_return, {
386    name: {
387      value: fn.name,
388      writable: false,
389      enumerable: false,
390      configurable: true,
391    },
392    length: {
393      value: fn.length,
394      writable: false,
395      enumerable: false,
396      configurable: true,
397    },
398  });
399  return _return;
400}
401
402function hasMultiLocalhost() {
403  const { internalBinding } = require('internal/test/binding');
404  const { TCP, constants: TCPConstants } = internalBinding('tcp_wrap');
405  const t = new TCP(TCPConstants.SOCKET);
406  const ret = t.bind('127.0.0.2', 0);
407  t.close();
408  return ret === 0;
409}
410
411function skipIfEslintMissing() {
412  if (!fs.existsSync(
413    path.join(__dirname, '..', '..', 'tools', 'node_modules', 'eslint')
414  )) {
415    skip('missing ESLint');
416  }
417}
418
419function canCreateSymLink() {
420  // On Windows, creating symlinks requires admin privileges.
421  // We'll only try to run symlink test if we have enough privileges.
422  // On other platforms, creating symlinks shouldn't need admin privileges
423  if (isWindows) {
424    // whoami.exe needs to be the one from System32
425    // If unix tools are in the path, they can shadow the one we want,
426    // so use the full path while executing whoami
427    const whoamiPath = path.join(process.env.SystemRoot,
428                                 'System32', 'whoami.exe');
429
430    try {
431      const output = execSync(`${whoamiPath} /priv`, { timeout: 1000 });
432      return output.includes('SeCreateSymbolicLinkPrivilege');
433    } catch {
434      return false;
435    }
436  }
437  // On non-Windows platforms, this always returns `true`
438  return true;
439}
440
441function getCallSite(top) {
442  const originalStackFormatter = Error.prepareStackTrace;
443  Error.prepareStackTrace = (err, stack) =>
444    `${stack[0].getFileName()}:${stack[0].getLineNumber()}`;
445  const err = new Error();
446  Error.captureStackTrace(err, top);
447  // With the V8 Error API, the stack is not formatted until it is accessed
448  err.stack; // eslint-disable-line no-unused-expressions
449  Error.prepareStackTrace = originalStackFormatter;
450  return err.stack;
451}
452
453function mustNotCall(msg) {
454  const callSite = getCallSite(mustNotCall);
455  return function mustNotCall(...args) {
456    const argsInfo = args.length > 0 ?
457      `\ncalled with arguments: ${args.map(util.inspect).join(', ')}` : '';
458    assert.fail(
459      `${msg || 'function should not have been called'} at ${callSite}` +
460      argsInfo);
461  };
462}
463
464function printSkipMessage(msg) {
465  console.log(`1..0 # Skipped: ${msg}`);
466}
467
468function skip(msg) {
469  printSkipMessage(msg);
470  process.exit(0);
471}
472
473// Returns true if the exit code "exitCode" and/or signal name "signal"
474// represent the exit code and/or signal name of a node process that aborted,
475// false otherwise.
476function nodeProcessAborted(exitCode, signal) {
477  // Depending on the compiler used, node will exit with either
478  // exit code 132 (SIGILL), 133 (SIGTRAP) or 134 (SIGABRT).
479  let expectedExitCodes = [132, 133, 134];
480
481  // On platforms using KSH as the default shell (like SmartOS),
482  // when a process aborts, KSH exits with an exit code that is
483  // greater than 256, and thus the exit code emitted with the 'exit'
484  // event is null and the signal is set to either SIGILL, SIGTRAP,
485  // or SIGABRT (depending on the compiler).
486  const expectedSignals = ['SIGILL', 'SIGTRAP', 'SIGABRT'];
487
488  // On Windows, 'aborts' are of 2 types, depending on the context:
489  // (i) Forced access violation, if --abort-on-uncaught-exception is on
490  // which corresponds to exit code 3221225477 (0xC0000005)
491  // (ii) Otherwise, _exit(134) which is called in place of abort() due to
492  // raising SIGABRT exiting with ambiguous exit code '3' by default
493  if (isWindows)
494    expectedExitCodes = [0xC0000005, 134];
495
496  // When using --abort-on-uncaught-exception, V8 will use
497  // base::OS::Abort to terminate the process.
498  // Depending on the compiler used, the shell or other aspects of
499  // the platform used to build the node binary, this will actually
500  // make V8 exit by aborting or by raising a signal. In any case,
501  // one of them (exit code or signal) needs to be set to one of
502  // the expected exit codes or signals.
503  if (signal !== null) {
504    return expectedSignals.includes(signal);
505  }
506  return expectedExitCodes.includes(exitCode);
507}
508
509function isAlive(pid) {
510  try {
511    process.kill(pid, 'SIGCONT');
512    return true;
513  } catch {
514    return false;
515  }
516}
517
518function _expectWarning(name, expected, code) {
519  if (typeof expected === 'string') {
520    expected = [[expected, code]];
521  } else if (!Array.isArray(expected)) {
522    expected = Object.entries(expected).map(([a, b]) => [b, a]);
523  } else if (!(Array.isArray(expected[0]))) {
524    expected = [[expected[0], expected[1]]];
525  }
526  // Deprecation codes are mandatory, everything else is not.
527  if (name === 'DeprecationWarning') {
528    expected.forEach(([_, code]) => assert(code, expected));
529  }
530  return mustCall((warning) => {
531    const [ message, code ] = expected.shift();
532    assert.strictEqual(warning.name, name);
533    if (typeof message === 'string') {
534      assert.strictEqual(warning.message, message);
535    } else {
536      assert(message.test(warning.message));
537    }
538    assert.strictEqual(warning.code, code);
539  }, expected.length);
540}
541
542let catchWarning;
543
544// Accepts a warning name and description or array of descriptions or a map of
545// warning names to description(s) ensures a warning is generated for each
546// name/description pair.
547// The expected messages have to be unique per `expectWarning()` call.
548function expectWarning(nameOrMap, expected, code) {
549  if (catchWarning === undefined) {
550    catchWarning = {};
551    process.on('warning', (warning) => {
552      if (!catchWarning[warning.name]) {
553        throw new TypeError(
554          `"${warning.name}" was triggered without being expected.\n` +
555          util.inspect(warning)
556        );
557      }
558      catchWarning[warning.name](warning);
559    });
560  }
561  if (typeof nameOrMap === 'string') {
562    catchWarning[nameOrMap] = _expectWarning(nameOrMap, expected, code);
563  } else {
564    Object.keys(nameOrMap).forEach((name) => {
565      catchWarning[name] = _expectWarning(name, nameOrMap[name]);
566    });
567  }
568}
569
570// Useful for testing expected internal/error objects
571function expectsError(validator, exact) {
572  return mustCall((...args) => {
573    if (args.length !== 1) {
574      // Do not use `assert.strictEqual()` to prevent `inspect` from
575      // always being called.
576      assert.fail(`Expected one argument, got ${util.inspect(args)}`);
577    }
578    const error = args.pop();
579    const descriptor = Object.getOwnPropertyDescriptor(error, 'message');
580    // The error message should be non-enumerable
581    assert.strictEqual(descriptor.enumerable, false);
582
583    assert.throws(() => { throw error; }, validator);
584    return true;
585  }, exact);
586}
587
588function skipIfInspectorDisabled() {
589  if (!process.features.inspector) {
590    skip('V8 inspector is disabled');
591  }
592}
593
594function skipIf32Bits() {
595  if (bits < 64) {
596    skip('The tested feature is not available in 32bit builds');
597  }
598}
599
600function skipIfWorker() {
601  if (!isMainThread) {
602    skip('This test only works on a main thread');
603  }
604}
605
606function getArrayBufferViews(buf) {
607  const { buffer, byteOffset, byteLength } = buf;
608
609  const out = [];
610
611  const arrayBufferViews = [
612    Int8Array,
613    Uint8Array,
614    Uint8ClampedArray,
615    Int16Array,
616    Uint16Array,
617    Int32Array,
618    Uint32Array,
619    Float32Array,
620    Float64Array,
621    DataView,
622  ];
623
624  for (const type of arrayBufferViews) {
625    const { BYTES_PER_ELEMENT = 1 } = type;
626    if (byteLength % BYTES_PER_ELEMENT === 0) {
627      out.push(new type(buffer, byteOffset, byteLength / BYTES_PER_ELEMENT));
628    }
629  }
630  return out;
631}
632
633function getBufferSources(buf) {
634  return [...getArrayBufferViews(buf), new Uint8Array(buf).buffer];
635}
636
637// Crash the process on unhandled rejections.
638const crashOnUnhandledRejection = (err) => { throw err; };
639process.on('unhandledRejection', crashOnUnhandledRejection);
640function disableCrashOnUnhandledRejection() {
641  process.removeListener('unhandledRejection', crashOnUnhandledRejection);
642}
643
644function getTTYfd() {
645  // Do our best to grab a tty fd.
646  const tty = require('tty');
647  // Don't attempt fd 0 as it is not writable on Windows.
648  // Ref: ef2861961c3d9e9ed6972e1e84d969683b25cf95
649  const ttyFd = [1, 2, 4, 5].find(tty.isatty);
650  if (ttyFd === undefined) {
651    try {
652      return fs.openSync('/dev/tty');
653    } catch {
654      // There aren't any tty fd's available to use.
655      return -1;
656    }
657  }
658  return ttyFd;
659}
660
661function runWithInvalidFD(func) {
662  let fd = 1 << 30;
663  // Get first known bad file descriptor. 1 << 30 is usually unlikely to
664  // be an valid one.
665  try {
666    while (fs.fstatSync(fd--) && fd > 0);
667  } catch {
668    return func(fd);
669  }
670
671  printSkipMessage('Could not generate an invalid fd');
672}
673
674// A helper function to simplify checking for ERR_INVALID_ARG_TYPE output.
675function invalidArgTypeHelper(input) {
676  if (input == null) {
677    return ` Received ${input}`;
678  }
679  if (typeof input === 'function' && input.name) {
680    return ` Received function ${input.name}`;
681  }
682  if (typeof input === 'object') {
683    if (input.constructor && input.constructor.name) {
684      return ` Received an instance of ${input.constructor.name}`;
685    }
686    return ` Received ${util.inspect(input, { depth: -1 })}`;
687  }
688  let inspected = util.inspect(input, { colors: false });
689  if (inspected.length > 25)
690    inspected = `${inspected.slice(0, 25)}...`;
691  return ` Received type ${typeof input} (${inspected})`;
692}
693
694function skipIfDumbTerminal() {
695  if (isDumbTerminal) {
696    skip('skipping - dumb terminal');
697  }
698}
699
700function gcUntil(name, condition) {
701  if (typeof name === 'function') {
702    condition = name;
703    name = undefined;
704  }
705  return new Promise((resolve, reject) => {
706    let count = 0;
707    function gcAndCheck() {
708      setImmediate(() => {
709        count++;
710        global.gc();
711        if (condition()) {
712          resolve();
713        } else if (count < 10) {
714          gcAndCheck();
715        } else {
716          reject(name === undefined ? undefined : 'Test ' + name + ' failed');
717        }
718      });
719    }
720    gcAndCheck();
721  });
722}
723
724function requireNoPackageJSONAbove(dir = __dirname) {
725  let possiblePackage = path.join(dir, '..', 'package.json');
726  let lastPackage = null;
727  while (possiblePackage !== lastPackage) {
728    if (fs.existsSync(possiblePackage)) {
729      assert.fail(
730        'This test shouldn\'t load properties from a package.json above ' +
731        `its file location. Found package.json at ${possiblePackage}.`);
732    }
733    lastPackage = possiblePackage;
734    possiblePackage = path.join(possiblePackage, '..', '..', 'package.json');
735  }
736}
737
738const common = {
739  allowGlobals,
740  buildType,
741  canCreateSymLink,
742  childShouldThrowAndAbort,
743  createZeroFilledFile,
744  disableCrashOnUnhandledRejection,
745  expectsError,
746  expectWarning,
747  gcUntil,
748  getArrayBufferViews,
749  getBufferSources,
750  getCallSite,
751  getTTYfd,
752  hasIntl,
753  hasCrypto,
754  hasOpenSSL3,
755  hasQuic,
756  hasMultiLocalhost,
757  invalidArgTypeHelper,
758  isAIX,
759  isAlive,
760  isDumbTerminal,
761  isFreeBSD,
762  isLinux,
763  isMainThread,
764  isOpenBSD,
765  isOSX,
766  isSunOS,
767  isWindows,
768  localIPv6Hosts,
769  mustCall,
770  mustCallAtLeast,
771  mustNotCall,
772  mustSucceed,
773  nodeProcessAborted,
774  PIPE,
775  platformTimeout,
776  printSkipMessage,
777  pwdCommand,
778  requireNoPackageJSONAbove,
779  runWithInvalidFD,
780  skip,
781  skipIf32Bits,
782  skipIfDumbTerminal,
783  skipIfEslintMissing,
784  skipIfInspectorDisabled,
785  skipIfWorker,
786
787  get enoughTestCpu() {
788    const cpus = require('os').cpus();
789    return Array.isArray(cpus) && (cpus.length > 1 || cpus[0].speed > 999);
790  },
791
792  get enoughTestMem() {
793    return require('os').totalmem() > 0x70000000; /* 1.75 Gb */
794  },
795
796  get hasFipsCrypto() {
797    return hasCrypto && require('crypto').getFips();
798  },
799
800  get hasIPv6() {
801    const iFaces = require('os').networkInterfaces();
802    const re = isWindows ? /Loopback Pseudo-Interface/ : /lo/;
803    return Object.keys(iFaces).some((name) => {
804      return re.test(name) &&
805             iFaces[name].some(({ family }) => family === 'IPv6');
806    });
807  },
808
809  get inFreeBSDJail() {
810    if (inFreeBSDJail !== null) return inFreeBSDJail;
811
812    if (exports.isFreeBSD &&
813        execSync('sysctl -n security.jail.jailed').toString() === '1\n') {
814      inFreeBSDJail = true;
815    } else {
816      inFreeBSDJail = false;
817    }
818    return inFreeBSDJail;
819  },
820
821  // On IBMi, process.platform and os.platform() both return 'aix',
822  // It is not enough to differentiate between IBMi and real AIX system.
823  get isIBMi() {
824    return require('os').type() === 'OS400';
825  },
826
827  get isLinuxPPCBE() {
828    return (process.platform === 'linux') && (process.arch === 'ppc64') &&
829           (require('os').endianness() === 'BE');
830  },
831
832  get localhostIPv4() {
833    if (localhostIPv4 !== null) return localhostIPv4;
834
835    if (this.inFreeBSDJail) {
836      // Jailed network interfaces are a bit special - since we need to jump
837      // through loops, as well as this being an exception case, assume the
838      // user will provide this instead.
839      if (process.env.LOCALHOST) {
840        localhostIPv4 = process.env.LOCALHOST;
841      } else {
842        console.error('Looks like we\'re in a FreeBSD Jail. ' +
843                      'Please provide your default interface address ' +
844                      'as LOCALHOST or expect some tests to fail.');
845      }
846    }
847
848    if (localhostIPv4 === null) localhostIPv4 = '127.0.0.1';
849
850    return localhostIPv4;
851  },
852
853  // opensslCli defined lazily to reduce overhead of spawnSync
854  get opensslCli() {
855    if (opensslCli !== null) return opensslCli;
856
857    if (process.config.variables.node_shared_openssl) {
858      // Use external command
859      opensslCli = 'openssl';
860    } else {
861      // Use command built from sources included in Node.js repository
862      opensslCli = path.join(path.dirname(process.execPath), 'openssl-cli');
863    }
864
865    if (exports.isWindows) opensslCli += '.exe';
866
867    const opensslCmd = spawnSync(opensslCli, ['version']);
868    if (opensslCmd.status !== 0 || opensslCmd.error !== undefined) {
869      // OpenSSL command cannot be executed
870      opensslCli = false;
871    }
872    return opensslCli;
873  },
874
875  get PORT() {
876    if (+process.env.TEST_PARALLEL) {
877      throw new Error('common.PORT cannot be used in a parallelized test');
878    }
879    return +process.env.NODE_COMMON_PORT || 12346;
880  }
881
882};
883
884const validProperties = new Set(Object.keys(common));
885module.exports = new Proxy(common, {
886  get(obj, prop) {
887    if (!validProperties.has(prop))
888      throw new Error(`Using invalid common property: '${prop}'`);
889    return obj[prop];
890  }
891});
892