mirror of
https://github.com/nodejs/node.git
synced 2024-12-01 16:10:02 +01:00
5f3fb1c0a1
This test is already partially disabled for several platforms with the comment that the required info is not provided at the C++ level. I'm adding AIX as and PPC BE linux as they currently fall into the same category. We are working to see if we can change that in v8 but it will be non-trivial if is possible at all so I don't want to leave the CI with failing tests until that point. PR-URL: https://github.com/nodejs/node/pull/3491 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
445 lines
12 KiB
JavaScript
445 lines
12 KiB
JavaScript
/* eslint-disable required-modules */
|
|
'use strict';
|
|
var path = require('path');
|
|
var fs = require('fs');
|
|
var assert = require('assert');
|
|
var os = require('os');
|
|
var child_process = require('child_process');
|
|
|
|
|
|
exports.testDir = path.dirname(__filename);
|
|
exports.fixturesDir = path.join(exports.testDir, 'fixtures');
|
|
exports.libDir = path.join(exports.testDir, '../lib');
|
|
exports.tmpDirName = 'tmp';
|
|
exports.PORT = +process.env.NODE_COMMON_PORT || 12346;
|
|
exports.isWindows = process.platform === 'win32';
|
|
exports.isAix = process.platform === 'aix';
|
|
exports.isLinuxPPCBE = (process.platform === 'linux') &&
|
|
(process.arch === 'ppc64') &&
|
|
(os.endianness() === 'BE');
|
|
exports.isSunOS = process.platform === 'sunos';
|
|
exports.isFreeBSD = process.platform === 'freebsd';
|
|
|
|
function rimrafSync(p) {
|
|
try {
|
|
var st = fs.lstatSync(p);
|
|
} catch (e) {
|
|
if (e.code === 'ENOENT')
|
|
return;
|
|
}
|
|
|
|
try {
|
|
if (st && st.isDirectory())
|
|
rmdirSync(p, null);
|
|
else
|
|
fs.unlinkSync(p);
|
|
} catch (e) {
|
|
if (e.code === 'ENOENT')
|
|
return;
|
|
if (e.code === 'EPERM')
|
|
return rmdirSync(p, e);
|
|
if (e.code !== 'EISDIR')
|
|
throw e;
|
|
rmdirSync(p, e);
|
|
}
|
|
}
|
|
|
|
function rmdirSync(p, originalEr) {
|
|
try {
|
|
fs.rmdirSync(p);
|
|
} catch (e) {
|
|
if (e.code === 'ENOTDIR')
|
|
throw originalEr;
|
|
if (e.code === 'ENOTEMPTY' || e.code === 'EEXIST' || e.code === 'EPERM') {
|
|
fs.readdirSync(p).forEach(function(f) {
|
|
rimrafSync(path.join(p, f));
|
|
});
|
|
fs.rmdirSync(p);
|
|
}
|
|
}
|
|
}
|
|
|
|
exports.refreshTmpDir = function() {
|
|
rimrafSync(exports.tmpDir);
|
|
fs.mkdirSync(exports.tmpDir);
|
|
};
|
|
|
|
if (process.env.TEST_THREAD_ID) {
|
|
// Distribute ports in parallel tests
|
|
if (!process.env.NODE_COMMON_PORT)
|
|
exports.PORT += +process.env.TEST_THREAD_ID * 100;
|
|
|
|
exports.tmpDirName += '.' + process.env.TEST_THREAD_ID;
|
|
}
|
|
exports.tmpDir = path.join(exports.testDir, exports.tmpDirName);
|
|
|
|
var opensslCli = null;
|
|
var inFreeBSDJail = null;
|
|
var localhostIPv4 = null;
|
|
|
|
Object.defineProperty(exports, 'inFreeBSDJail', {
|
|
get: function() {
|
|
if (inFreeBSDJail !== null) return inFreeBSDJail;
|
|
|
|
if (process.platform === 'freebsd' &&
|
|
child_process.execSync('sysctl -n security.jail.jailed').toString() ===
|
|
'1\n') {
|
|
inFreeBSDJail = true;
|
|
} else {
|
|
inFreeBSDJail = false;
|
|
}
|
|
return inFreeBSDJail;
|
|
}
|
|
});
|
|
|
|
Object.defineProperty(exports, 'localhostIPv4', {
|
|
get: function() {
|
|
if (localhostIPv4 !== null) return localhostIPv4;
|
|
|
|
if (exports.inFreeBSDJail) {
|
|
// Jailed network interfaces are a bit special - since we need to jump
|
|
// through loops, as well as this being an exception case, assume the
|
|
// user will provide this instead.
|
|
if (process.env.LOCALHOST) {
|
|
localhostIPv4 = process.env.LOCALHOST;
|
|
} else {
|
|
console.error('Looks like we\'re in a FreeBSD Jail. ' +
|
|
'Please provide your default interface address ' +
|
|
'as LOCALHOST or expect some tests to fail.');
|
|
}
|
|
}
|
|
|
|
if (localhostIPv4 === null) localhostIPv4 = '127.0.0.1';
|
|
|
|
return localhostIPv4;
|
|
}
|
|
});
|
|
|
|
// opensslCli defined lazily to reduce overhead of spawnSync
|
|
Object.defineProperty(exports, 'opensslCli', {get: function() {
|
|
if (opensslCli !== null) return opensslCli;
|
|
|
|
if (process.config.variables.node_shared_openssl) {
|
|
// use external command
|
|
opensslCli = 'openssl';
|
|
} else {
|
|
// use command built from sources included in Node.js repository
|
|
opensslCli = path.join(path.dirname(process.execPath), 'openssl-cli');
|
|
}
|
|
|
|
if (exports.isWindows) opensslCli += '.exe';
|
|
|
|
var openssl_cmd = child_process.spawnSync(opensslCli, ['version']);
|
|
if (openssl_cmd.status !== 0 || openssl_cmd.error !== undefined) {
|
|
// openssl command cannot be executed
|
|
opensslCli = false;
|
|
}
|
|
return opensslCli;
|
|
}, enumerable: true });
|
|
|
|
Object.defineProperty(exports, 'hasCrypto', {get: function() {
|
|
return process.versions.openssl ? true : false;
|
|
}});
|
|
|
|
if (exports.isWindows) {
|
|
exports.PIPE = '\\\\.\\pipe\\libuv-test';
|
|
} else {
|
|
exports.PIPE = exports.tmpDir + '/test.sock';
|
|
}
|
|
|
|
if (process.env.NODE_COMMON_PIPE) {
|
|
exports.PIPE = process.env.NODE_COMMON_PIPE;
|
|
// Remove manually, the test runner won't do it
|
|
// for us like it does for files in test/tmp.
|
|
try {
|
|
fs.unlinkSync(exports.PIPE);
|
|
} catch (e) {
|
|
// Ignore.
|
|
}
|
|
}
|
|
|
|
if (exports.isWindows) {
|
|
exports.faketimeCli = false;
|
|
} else {
|
|
exports.faketimeCli = path.join(__dirname, '..', 'tools', 'faketime', 'src',
|
|
'faketime');
|
|
}
|
|
|
|
var ifaces = os.networkInterfaces();
|
|
exports.hasIPv6 = Object.keys(ifaces).some(function(name) {
|
|
return /lo/.test(name) && ifaces[name].some(function(info) {
|
|
return info.family === 'IPv6';
|
|
});
|
|
});
|
|
|
|
function protoCtrChain(o) {
|
|
var result = [];
|
|
for (; o; o = o.__proto__) { result.push(o.constructor); }
|
|
return result.join();
|
|
}
|
|
|
|
exports.indirectInstanceOf = function(obj, cls) {
|
|
if (obj instanceof cls) { return true; }
|
|
var clsChain = protoCtrChain(cls.prototype);
|
|
var objChain = protoCtrChain(obj);
|
|
return objChain.slice(-clsChain.length) === clsChain;
|
|
};
|
|
|
|
|
|
exports.ddCommand = function(filename, kilobytes) {
|
|
if (exports.isWindows) {
|
|
var p = path.resolve(exports.fixturesDir, 'create-file.js');
|
|
return '"' + process.argv[0] + '" "' + p + '" "' +
|
|
filename + '" ' + (kilobytes * 1024);
|
|
} else {
|
|
return 'dd if=/dev/zero of="' + filename + '" bs=1024 count=' + kilobytes;
|
|
}
|
|
};
|
|
|
|
|
|
exports.spawnCat = function(options) {
|
|
var spawn = require('child_process').spawn;
|
|
|
|
if (exports.isWindows) {
|
|
return spawn('more', [], options);
|
|
} else {
|
|
return spawn('cat', [], options);
|
|
}
|
|
};
|
|
|
|
|
|
exports.spawnSyncCat = function(options) {
|
|
var spawnSync = require('child_process').spawnSync;
|
|
|
|
if (exports.isWindows) {
|
|
return spawnSync('more', [], options);
|
|
} else {
|
|
return spawnSync('cat', [], options);
|
|
}
|
|
};
|
|
|
|
|
|
exports.spawnPwd = function(options) {
|
|
var spawn = require('child_process').spawn;
|
|
|
|
if (exports.isWindows) {
|
|
return spawn('cmd.exe', ['/c', 'cd'], options);
|
|
} else {
|
|
return spawn('pwd', [], options);
|
|
}
|
|
};
|
|
|
|
exports.platformTimeout = function(ms) {
|
|
if (process.arch !== 'arm')
|
|
return ms;
|
|
|
|
if (process.config.variables.arm_version === '6')
|
|
return 7 * ms; // ARMv6
|
|
|
|
return 2 * ms; // ARMv7 and up.
|
|
};
|
|
|
|
var knownGlobals = [setTimeout,
|
|
setInterval,
|
|
setImmediate,
|
|
clearTimeout,
|
|
clearInterval,
|
|
clearImmediate,
|
|
console,
|
|
constructor, // Enumerable in V8 3.21.
|
|
Buffer,
|
|
process,
|
|
global];
|
|
|
|
if (global.gc) {
|
|
knownGlobals.push(gc);
|
|
}
|
|
|
|
if (global.DTRACE_HTTP_SERVER_RESPONSE) {
|
|
knownGlobals.push(DTRACE_HTTP_SERVER_RESPONSE);
|
|
knownGlobals.push(DTRACE_HTTP_SERVER_REQUEST);
|
|
knownGlobals.push(DTRACE_HTTP_CLIENT_RESPONSE);
|
|
knownGlobals.push(DTRACE_HTTP_CLIENT_REQUEST);
|
|
knownGlobals.push(DTRACE_NET_STREAM_END);
|
|
knownGlobals.push(DTRACE_NET_SERVER_CONNECTION);
|
|
}
|
|
|
|
if (global.COUNTER_NET_SERVER_CONNECTION) {
|
|
knownGlobals.push(COUNTER_NET_SERVER_CONNECTION);
|
|
knownGlobals.push(COUNTER_NET_SERVER_CONNECTION_CLOSE);
|
|
knownGlobals.push(COUNTER_HTTP_SERVER_REQUEST);
|
|
knownGlobals.push(COUNTER_HTTP_SERVER_RESPONSE);
|
|
knownGlobals.push(COUNTER_HTTP_CLIENT_REQUEST);
|
|
knownGlobals.push(COUNTER_HTTP_CLIENT_RESPONSE);
|
|
}
|
|
|
|
if (global.LTTNG_HTTP_SERVER_RESPONSE) {
|
|
knownGlobals.push(LTTNG_HTTP_SERVER_RESPONSE);
|
|
knownGlobals.push(LTTNG_HTTP_SERVER_REQUEST);
|
|
knownGlobals.push(LTTNG_HTTP_CLIENT_RESPONSE);
|
|
knownGlobals.push(LTTNG_HTTP_CLIENT_REQUEST);
|
|
knownGlobals.push(LTTNG_NET_STREAM_END);
|
|
knownGlobals.push(LTTNG_NET_SERVER_CONNECTION);
|
|
}
|
|
|
|
if (global.ArrayBuffer) {
|
|
knownGlobals.push(ArrayBuffer);
|
|
knownGlobals.push(Int8Array);
|
|
knownGlobals.push(Uint8Array);
|
|
knownGlobals.push(Uint8ClampedArray);
|
|
knownGlobals.push(Int16Array);
|
|
knownGlobals.push(Uint16Array);
|
|
knownGlobals.push(Int32Array);
|
|
knownGlobals.push(Uint32Array);
|
|
knownGlobals.push(Float32Array);
|
|
knownGlobals.push(Float64Array);
|
|
knownGlobals.push(DataView);
|
|
}
|
|
|
|
// Harmony features.
|
|
if (global.Proxy) {
|
|
knownGlobals.push(Proxy);
|
|
}
|
|
|
|
if (global.Symbol) {
|
|
knownGlobals.push(Symbol);
|
|
}
|
|
|
|
function leakedGlobals() {
|
|
var leaked = [];
|
|
|
|
for (var val in global)
|
|
if (-1 === knownGlobals.indexOf(global[val]))
|
|
leaked.push(val);
|
|
|
|
return leaked;
|
|
};
|
|
exports.leakedGlobals = leakedGlobals;
|
|
|
|
// Turn this off if the test should not check for global leaks.
|
|
exports.globalCheck = true;
|
|
|
|
process.on('exit', function() {
|
|
if (!exports.globalCheck) return;
|
|
var leaked = leakedGlobals();
|
|
if (leaked.length > 0) {
|
|
console.error('Unknown globals: %s', leaked);
|
|
assert.ok(false, 'Unknown global found');
|
|
}
|
|
});
|
|
|
|
|
|
var mustCallChecks = [];
|
|
|
|
|
|
function runCallChecks(exitCode) {
|
|
if (exitCode !== 0) return;
|
|
|
|
var failed = mustCallChecks.filter(function(context) {
|
|
return context.actual !== context.expected;
|
|
});
|
|
|
|
failed.forEach(function(context) {
|
|
console.log('Mismatched %s function calls. Expected %d, actual %d.',
|
|
context.name,
|
|
context.expected,
|
|
context.actual);
|
|
console.log(context.stack.split('\n').slice(2).join('\n'));
|
|
});
|
|
|
|
if (failed.length) process.exit(1);
|
|
}
|
|
|
|
|
|
exports.mustCall = function(fn, expected) {
|
|
if (typeof expected !== 'number') expected = 1;
|
|
|
|
var context = {
|
|
expected: expected,
|
|
actual: 0,
|
|
stack: (new Error()).stack,
|
|
name: fn.name || '<anonymous>'
|
|
};
|
|
|
|
// add the exit listener only once to avoid listener leak warnings
|
|
if (mustCallChecks.length === 0) process.on('exit', runCallChecks);
|
|
|
|
mustCallChecks.push(context);
|
|
|
|
return function() {
|
|
context.actual++;
|
|
return fn.apply(this, arguments);
|
|
};
|
|
};
|
|
|
|
exports.checkSpawnSyncRet = function(ret) {
|
|
assert.strictEqual(ret.status, 0);
|
|
assert.strictEqual(ret.error, undefined);
|
|
};
|
|
|
|
var etcServicesFileName = path.join('/etc', 'services');
|
|
if (exports.isWindows) {
|
|
etcServicesFileName = path.join(process.env.SystemRoot, 'System32', 'drivers',
|
|
'etc', 'services');
|
|
}
|
|
|
|
/*
|
|
* Returns a string that represents the service name associated
|
|
* to the service bound to port "port" and using protocol "protocol".
|
|
*
|
|
* If the service is not defined in the services file, it returns
|
|
* the port number as a string.
|
|
*
|
|
* Returns undefined if /etc/services (or its equivalent on non-UNIX
|
|
* platforms) can't be read.
|
|
*/
|
|
exports.getServiceName = function getServiceName(port, protocol) {
|
|
if (port == null) {
|
|
throw new Error('Missing port number');
|
|
}
|
|
|
|
if (typeof protocol !== 'string') {
|
|
throw new Error('Protocol must be a string');
|
|
}
|
|
|
|
/*
|
|
* By default, if a service can't be found in /etc/services,
|
|
* its name is considered to be its port number.
|
|
*/
|
|
var serviceName = port.toString();
|
|
|
|
try {
|
|
var servicesContent = fs.readFileSync(etcServicesFileName,
|
|
{ encoding: 'utf8'});
|
|
var regexp = `^(\\w+)\\s+\\s${port}/${protocol}\\s`;
|
|
var re = new RegExp(regexp, 'm');
|
|
|
|
var matches = re.exec(servicesContent);
|
|
if (matches && matches.length > 1) {
|
|
serviceName = matches[1];
|
|
}
|
|
} catch(e) {
|
|
console.error('Cannot read file: ', etcServicesFileName);
|
|
return undefined;
|
|
}
|
|
|
|
return serviceName;
|
|
};
|
|
|
|
exports.hasMultiLocalhost = function hasMultiLocalhost() {
|
|
var TCP = process.binding('tcp_wrap').TCP;
|
|
var t = new TCP();
|
|
var ret = t.bind('127.0.0.2', exports.PORT);
|
|
t.close();
|
|
return ret === 0;
|
|
};
|
|
|
|
exports.fileExists = function(pathname) {
|
|
try {
|
|
fs.accessSync(pathname);
|
|
return true;
|
|
} catch (err) {
|
|
return false;
|
|
}
|
|
};
|