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