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