2 var path = require('path');
3 var fs = require('fs');
4 var assert = require('assert');
5 var os = require('os');
6 var child_process = require('child_process');
8 exports.testDir = path.dirname(__filename);
9 exports.fixturesDir = path.join(exports.testDir, 'fixtures');
10 exports.libDir = path.join(exports.testDir, '../lib');
11 exports.tmpDirName = 'tmp';
12 exports.PORT = +process.env.NODE_COMMON_PORT || 12346;
14 if (process.env.TEST_THREAD_ID) {
15 // Distribute ports in parallel tests
16 if (!process.env.NODE_COMMON_PORT)
17 exports.PORT += +process.env.TEST_THREAD_ID * 100;
19 exports.tmpDirName += '.' + process.env.TEST_THREAD_ID;
21 exports.tmpDir = path.join(exports.testDir, exports.tmpDirName);
23 var opensslCli = null;
24 var inFreeBSDJail = null;
25 var localhostIPv4 = null;
27 Object.defineProperty(exports, 'inFreeBSDJail', {
29 if (inFreeBSDJail !== null) return inFreeBSDJail;
31 if (process.platform === 'freebsd' &&
32 child_process.execSync('sysctl -n security.jail.jailed').toString() ===
36 inFreeBSDJail = false;
42 Object.defineProperty(exports, 'localhostIPv4', {
44 if (localhostIPv4 !== null) return localhostIPv4;
46 if (exports.inFreeBSDJail) {
47 // Jailed network interfaces are a bit special - since we need to jump
48 // through loops, as well as this being an exception case, assume the
49 // user will provide this instead.
50 if (process.env.LOCALHOST) {
51 localhostIPv4 = process.env.LOCALHOST;
53 console.error('Looks like we\'re in a FreeBSD Jail. ' +
54 'Please provide your default interface address ' +
55 'as LOCALHOST or expect some tests to fail.');
59 if (localhostIPv4 === null) localhostIPv4 = '127.0.0.1';
65 // opensslCli defined lazily to reduce overhead of spawnSync
66 Object.defineProperty(exports, 'opensslCli', {get: function() {
67 if (opensslCli !== null) return opensslCli;
69 if (process.config.variables.node_shared_openssl) {
70 // use external command
71 opensslCli = 'openssl';
73 // use command built from sources included in io.js repository
74 opensslCli = path.join(path.dirname(process.execPath), 'openssl-cli');
77 if (process.platform === 'win32') opensslCli += '.exe';
79 var openssl_cmd = child_process.spawnSync(opensslCli, ['version']);
80 if (openssl_cmd.status !== 0 || openssl_cmd.error !== undefined) {
81 // openssl command cannot be executed
85 }, enumerable: true });
87 Object.defineProperty(exports, 'hasCrypto', {get: function() {
88 return process.versions.openssl ? true : false;
91 if (process.platform === 'win32') {
92 exports.PIPE = '\\\\.\\pipe\\libuv-test';
94 exports.PIPE = exports.tmpDir + '/test.sock';
97 if (process.env.NODE_COMMON_PIPE) {
98 exports.PIPE = process.env.NODE_COMMON_PIPE;
99 // Remove manually, the test runner won't do it
100 // for us like it does for files in test/tmp.
102 fs.unlinkSync(exports.PIPE);
108 if (process.platform === 'win32') {
109 exports.faketimeCli = false;
111 exports.faketimeCli = path.join(__dirname, '..', 'tools', 'faketime', 'src',
115 var ifaces = os.networkInterfaces();
116 exports.hasIPv6 = Object.keys(ifaces).some(function(name) {
117 return /lo/.test(name) && ifaces[name].some(function(info) {
118 return info.family === 'IPv6';
122 var util = require('util');
123 for (var i in util) exports[i] = util[i];
124 //for (var i in exports) global[i] = exports[i];
126 function protoCtrChain(o) {
128 for (; o; o = o.__proto__) { result.push(o.constructor); }
129 return result.join();
132 exports.indirectInstanceOf = function(obj, cls) {
133 if (obj instanceof cls) { return true; }
134 var clsChain = protoCtrChain(cls.prototype);
135 var objChain = protoCtrChain(obj);
136 return objChain.slice(-clsChain.length) === clsChain;
140 exports.ddCommand = function(filename, kilobytes) {
141 if (process.platform === 'win32') {
142 var p = path.resolve(exports.fixturesDir, 'create-file.js');
143 return '"' + process.argv[0] + '" "' + p + '" "' +
144 filename + '" ' + (kilobytes * 1024);
146 return 'dd if=/dev/zero of="' + filename + '" bs=1024 count=' + kilobytes;
151 exports.spawnCat = function(options) {
152 var spawn = require('child_process').spawn;
154 if (process.platform === 'win32') {
155 return spawn('more', [], options);
157 return spawn('cat', [], options);
162 exports.spawnSyncCat = function(options) {
163 var spawnSync = require('child_process').spawnSync;
165 if (process.platform === 'win32') {
166 return spawnSync('more', [], options);
168 return spawnSync('cat', [], options);
173 exports.spawnPwd = function(options) {
174 var spawn = require('child_process').spawn;
176 if (process.platform === 'win32') {
177 return spawn('cmd.exe', ['/c', 'cd'], options);
179 return spawn('pwd', [], options);
183 exports.platformTimeout = function(ms) {
184 if (process.arch !== 'arm')
187 if (process.config.variables.arm_version === '6')
188 return 7 * ms; // ARMv6
190 return 2 * ms; // ARMv7 and up.
193 var knownGlobals = [setTimeout,
200 constructor, // Enumerable in V8 3.21.
206 knownGlobals.push(gc);
209 if (global.DTRACE_HTTP_SERVER_RESPONSE) {
210 knownGlobals.push(DTRACE_HTTP_SERVER_RESPONSE);
211 knownGlobals.push(DTRACE_HTTP_SERVER_REQUEST);
212 knownGlobals.push(DTRACE_HTTP_CLIENT_RESPONSE);
213 knownGlobals.push(DTRACE_HTTP_CLIENT_REQUEST);
214 knownGlobals.push(DTRACE_NET_STREAM_END);
215 knownGlobals.push(DTRACE_NET_SERVER_CONNECTION);
218 if (global.COUNTER_NET_SERVER_CONNECTION) {
219 knownGlobals.push(COUNTER_NET_SERVER_CONNECTION);
220 knownGlobals.push(COUNTER_NET_SERVER_CONNECTION_CLOSE);
221 knownGlobals.push(COUNTER_HTTP_SERVER_REQUEST);
222 knownGlobals.push(COUNTER_HTTP_SERVER_RESPONSE);
223 knownGlobals.push(COUNTER_HTTP_CLIENT_REQUEST);
224 knownGlobals.push(COUNTER_HTTP_CLIENT_RESPONSE);
227 if (global.LTTNG_HTTP_SERVER_RESPONSE) {
228 knownGlobals.push(LTTNG_HTTP_SERVER_RESPONSE);
229 knownGlobals.push(LTTNG_HTTP_SERVER_REQUEST);
230 knownGlobals.push(LTTNG_HTTP_CLIENT_RESPONSE);
231 knownGlobals.push(LTTNG_HTTP_CLIENT_REQUEST);
232 knownGlobals.push(LTTNG_NET_STREAM_END);
233 knownGlobals.push(LTTNG_NET_SERVER_CONNECTION);
236 if (global.ArrayBuffer) {
237 knownGlobals.push(ArrayBuffer);
238 knownGlobals.push(Int8Array);
239 knownGlobals.push(Uint8Array);
240 knownGlobals.push(Uint8ClampedArray);
241 knownGlobals.push(Int16Array);
242 knownGlobals.push(Uint16Array);
243 knownGlobals.push(Int32Array);
244 knownGlobals.push(Uint32Array);
245 knownGlobals.push(Float32Array);
246 knownGlobals.push(Float64Array);
247 knownGlobals.push(DataView);
252 knownGlobals.push(Proxy);
256 knownGlobals.push(Symbol);
259 function leakedGlobals() {
262 for (var val in global)
263 if (-1 === knownGlobals.indexOf(global[val]))
268 exports.leakedGlobals = leakedGlobals;
270 // Turn this off if the test should not check for global leaks.
271 exports.globalCheck = true;
273 process.on('exit', function() {
274 if (!exports.globalCheck) return;
275 var leaked = leakedGlobals();
276 if (leaked.length > 0) {
277 console.error('Unknown globals: %s', leaked);
278 assert.ok(false, 'Unknown global found');
283 var mustCallChecks = [];
286 function runCallChecks(exitCode) {
287 if (exitCode !== 0) return;
289 var failed = mustCallChecks.filter(function(context) {
290 return context.actual !== context.expected;
293 failed.forEach(function(context) {
294 console.log('Mismatched %s function calls. Expected %d, actual %d.',
298 console.log(context.stack.split('\n').slice(2).join('\n'));
301 if (failed.length) process.exit(1);
305 exports.mustCall = function(fn, expected) {
306 if (typeof expected !== 'number') expected = 1;
311 stack: (new Error()).stack,
312 name: fn.name || '<anonymous>'
315 // add the exit listener only once to avoid listener leak warnings
316 if (mustCallChecks.length === 0) process.on('exit', runCallChecks);
318 mustCallChecks.push(context);
322 return fn.apply(this, arguments);
326 exports.checkSpawnSyncRet = function(ret) {
327 assert.strictEqual(ret.status, 0);
328 assert.strictEqual(ret.error, undefined);
331 var etcServicesFileName = path.join('/etc', 'services');
332 if (process.platform === 'win32') {
333 etcServicesFileName = path.join(process.env.SystemRoot, 'System32', 'drivers',
338 * Returns a string that represents the service name associated
339 * to the service bound to port "port" and using protocol "protocol".
341 * If the service is not defined in the services file, it returns
342 * the port number as a string.
344 * Returns undefined if /etc/services (or its equivalent on non-UNIX
345 * platforms) can't be read.
347 exports.getServiceName = function getServiceName(port, protocol) {
349 throw new Error('Missing port number');
352 if (typeof protocol !== 'string') {
353 throw new Error('Protocol must be a string');
357 * By default, if a service can't be found in /etc/services,
358 * its name is considered to be its port number.
360 var serviceName = port.toString();
364 * I'm not a big fan of readFileSync, but reading /etc/services
365 * asynchronously here would require implementing a simple line parser,
366 * which seems overkill for a simple utility function that is not running
367 * concurrently with any other one.
369 var servicesContent = fs.readFileSync(etcServicesFileName,
370 { encoding: 'utf8'});
371 var regexp = util.format('^(\\w+)\\s+\\s%d/%s\\s', port, protocol);
372 var re = new RegExp(regexp, 'm');
374 var matches = re.exec(servicesContent);
375 if (matches && matches.length > 1) {
376 serviceName = matches[1];
379 console.error('Cannot read file: ', etcServicesFileName);
386 exports.hasMultiLocalhost = function hasMultiLocalhost() {
387 var TCP = process.binding('tcp_wrap').TCP;
389 var ret = t.bind('127.0.0.2', exports.PORT);
394 exports.isValidHostname = function(str) {
395 // See http://stackoverflow.com/a/3824105
397 '^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])' +
398 '(\\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]))*$');
400 return !!str.match(re) && str.length <= 255;
403 exports.fileExists = function(pathname) {
405 fs.accessSync(pathname);