deps: upgrade v8 to 4.2.77.13
[platform/upstream/nodejs.git] / test / common.js
1 var path = require('path');
2 var fs = require('fs');
3 var assert = require('assert');
4 var os = require('os');
5 var child_process = require('child_process');
6
7 exports.testDir = path.dirname(__filename);
8 exports.fixturesDir = path.join(exports.testDir, 'fixtures');
9 exports.libDir = path.join(exports.testDir, '../lib');
10 exports.tmpDirName = 'tmp';
11 exports.PORT = +process.env.NODE_COMMON_PORT || 12346;
12
13 if (process.env.TEST_THREAD_ID) {
14   // Distribute ports in parallel tests
15   if (!process.env.NODE_COMMON_PORT)
16     exports.PORT += +process.env.TEST_THREAD_ID * 100;
17
18   exports.tmpDirName += '.' + process.env.TEST_THREAD_ID;
19 }
20 exports.tmpDir = path.join(exports.testDir, exports.tmpDirName);
21
22 var opensslCli = null;
23 var inFreeBSDJail = null;
24 var localhostIPv4 = null;
25
26 Object.defineProperty(exports, 'inFreeBSDJail', {
27   get: function() {
28     if (inFreeBSDJail !== null) return inFreeBSDJail;
29
30     if (process.platform === 'freebsd' &&
31       child_process.execSync('sysctl -n security.jail.jailed').toString() ===
32       '1\n') {
33       inFreeBSDJail = true;
34     } else {
35       inFreeBSDJail = false;
36     }
37     return inFreeBSDJail;
38   }
39 });
40
41 Object.defineProperty(exports, 'localhostIPv4', {
42   get: function() {
43     if (localhostIPv4 !== null) return localhostIPv4;
44
45     if (exports.inFreeBSDJail) {
46       // Jailed network interfaces are a bit special - since we need to jump
47       // through loops, as well as this being an exception case, assume the
48       // user will provide this instead.
49       if (process.env.LOCALHOST) {
50         localhostIPv4 = process.env.LOCALHOST;
51       } else {
52         console.error('Looks like we\'re in a FreeBSD Jail. ' +
53                       'Please provide your default interface address ' +
54                       'as LOCALHOST or expect some tests to fail.');
55       }
56     }
57
58     if (localhostIPv4 === null) localhostIPv4 = '127.0.0.1';
59
60     return localhostIPv4;
61   }
62 });
63
64 // opensslCli defined lazily to reduce overhead of spawnSync
65 Object.defineProperty(exports, 'opensslCli', {get: function() {
66   if (opensslCli !== null) return opensslCli;
67
68   if (process.config.variables.node_shared_openssl) {
69     // use external command
70     opensslCli = 'openssl';
71   } else {
72     // use command built from sources included in io.js repository
73     opensslCli = path.join(path.dirname(process.execPath), 'openssl-cli');
74   }
75
76   if (process.platform === 'win32') opensslCli += '.exe';
77
78   var openssl_cmd = child_process.spawnSync(opensslCli, ['version']);
79   if (openssl_cmd.status !== 0 || openssl_cmd.error !== undefined) {
80     // openssl command cannot be executed
81     opensslCli = false;
82   }
83   return opensslCli;
84 }, enumerable: true });
85
86 Object.defineProperty(exports, 'hasCrypto', {get: function() {
87   return process.versions.openssl ? true : false;
88 }});
89
90 if (process.platform === 'win32') {
91   exports.PIPE = '\\\\.\\pipe\\libuv-test';
92 } else {
93   exports.PIPE = exports.tmpDir + '/test.sock';
94 }
95
96 if (process.env.NODE_COMMON_PIPE) {
97   exports.PIPE = process.env.NODE_COMMON_PIPE;
98   // Remove manually, the test runner won't do it
99   // for us like it does for files in test/tmp.
100   try {
101     fs.unlinkSync(exports.PIPE);
102   } catch (e) {
103     // Ignore.
104   }
105 }
106
107 if (process.platform === 'win32') {
108   exports.faketimeCli = false;
109 } else {
110   exports.faketimeCli = path.join(__dirname, "..", "tools", "faketime", "src",
111     "faketime");
112 }
113
114 var ifaces = os.networkInterfaces();
115 exports.hasIPv6 = Object.keys(ifaces).some(function(name) {
116   return /lo/.test(name) && ifaces[name].some(function(info) {
117     return info.family === 'IPv6';
118   });
119 });
120
121 var util = require('util');
122 for (var i in util) exports[i] = util[i];
123 //for (var i in exports) global[i] = exports[i];
124
125 function protoCtrChain(o) {
126   var result = [];
127   for (; o; o = o.__proto__) { result.push(o.constructor); }
128   return result.join();
129 }
130
131 exports.indirectInstanceOf = function(obj, cls) {
132   if (obj instanceof cls) { return true; }
133   var clsChain = protoCtrChain(cls.prototype);
134   var objChain = protoCtrChain(obj);
135   return objChain.slice(-clsChain.length) === clsChain;
136 };
137
138
139 exports.ddCommand = function(filename, kilobytes) {
140   if (process.platform === 'win32') {
141     var p = path.resolve(exports.fixturesDir, 'create-file.js');
142     return '"' + process.argv[0] + '" "' + p + '" "' +
143            filename + '" ' + (kilobytes * 1024);
144   } else {
145     return 'dd if=/dev/zero of="' + filename + '" bs=1024 count=' + kilobytes;
146   }
147 };
148
149
150 exports.spawnCat = function(options) {
151   var spawn = require('child_process').spawn;
152
153   if (process.platform === 'win32') {
154     return spawn('more', [], options);
155   } else {
156     return spawn('cat', [], options);
157   }
158 };
159
160
161 exports.spawnSyncCat = function(options) {
162   var spawnSync = require('child_process').spawnSync;
163
164   if (process.platform === 'win32') {
165     return spawnSync('more', [], options);
166   } else {
167     return spawnSync('cat', [], options);
168   }
169 };
170
171
172 exports.spawnPwd = function(options) {
173   var spawn = require('child_process').spawn;
174
175   if (process.platform === 'win32') {
176     return spawn('cmd.exe', ['/c', 'cd'], options);
177   } else {
178     return spawn('pwd', [], options);
179   }
180 };
181
182 exports.platformTimeout = function(ms) {
183   if (process.arch !== 'arm')
184     return ms;
185
186   if (process.config.variables.arm_version === '6')
187     return 6 * ms;  // ARMv6
188
189   return 2 * ms;  // ARMv7 and up.
190 };
191
192 var knownGlobals = [setTimeout,
193                     setInterval,
194                     setImmediate,
195                     clearTimeout,
196                     clearInterval,
197                     clearImmediate,
198                     console,
199                     constructor, // Enumerable in V8 3.21.
200                     Buffer,
201                     process,
202                     global];
203
204 if (global.gc) {
205   knownGlobals.push(gc);
206 }
207
208 if (global.DTRACE_HTTP_SERVER_RESPONSE) {
209   knownGlobals.push(DTRACE_HTTP_SERVER_RESPONSE);
210   knownGlobals.push(DTRACE_HTTP_SERVER_REQUEST);
211   knownGlobals.push(DTRACE_HTTP_CLIENT_RESPONSE);
212   knownGlobals.push(DTRACE_HTTP_CLIENT_REQUEST);
213   knownGlobals.push(DTRACE_NET_STREAM_END);
214   knownGlobals.push(DTRACE_NET_SERVER_CONNECTION);
215 }
216
217 if (global.COUNTER_NET_SERVER_CONNECTION) {
218   knownGlobals.push(COUNTER_NET_SERVER_CONNECTION);
219   knownGlobals.push(COUNTER_NET_SERVER_CONNECTION_CLOSE);
220   knownGlobals.push(COUNTER_HTTP_SERVER_REQUEST);
221   knownGlobals.push(COUNTER_HTTP_SERVER_RESPONSE);
222   knownGlobals.push(COUNTER_HTTP_CLIENT_REQUEST);
223   knownGlobals.push(COUNTER_HTTP_CLIENT_RESPONSE);
224 }
225
226 if (global.LTTNG_HTTP_SERVER_RESPONSE) {
227   knownGlobals.push(LTTNG_HTTP_SERVER_RESPONSE);
228   knownGlobals.push(LTTNG_HTTP_SERVER_REQUEST);
229   knownGlobals.push(LTTNG_HTTP_CLIENT_RESPONSE);
230   knownGlobals.push(LTTNG_HTTP_CLIENT_REQUEST);
231   knownGlobals.push(LTTNG_NET_STREAM_END);
232   knownGlobals.push(LTTNG_NET_SERVER_CONNECTION);
233 }
234
235 if (global.ArrayBuffer) {
236   knownGlobals.push(ArrayBuffer);
237   knownGlobals.push(Int8Array);
238   knownGlobals.push(Uint8Array);
239   knownGlobals.push(Uint8ClampedArray);
240   knownGlobals.push(Int16Array);
241   knownGlobals.push(Uint16Array);
242   knownGlobals.push(Int32Array);
243   knownGlobals.push(Uint32Array);
244   knownGlobals.push(Float32Array);
245   knownGlobals.push(Float64Array);
246   knownGlobals.push(DataView);
247 }
248
249 // Harmony features.
250 if (global.Proxy) {
251   knownGlobals.push(Proxy);
252 }
253
254 if (global.Symbol) {
255   knownGlobals.push(Symbol);
256 }
257
258 function leakedGlobals() {
259   var leaked = [];
260
261   for (var val in global)
262     if (-1 === knownGlobals.indexOf(global[val]))
263       leaked.push(val);
264
265   return leaked;
266 };
267 exports.leakedGlobals = leakedGlobals;
268
269 // Turn this off if the test should not check for global leaks.
270 exports.globalCheck = true;
271
272 process.on('exit', function() {
273   if (!exports.globalCheck) return;
274   var leaked = leakedGlobals();
275   if (leaked.length > 0) {
276     console.error('Unknown globals: %s', leaked);
277     assert.ok(false, 'Unknown global found');
278   }
279 });
280
281
282 var mustCallChecks = [];
283
284
285 function runCallChecks(exitCode) {
286   if (exitCode !== 0) return;
287
288   var failed = mustCallChecks.filter(function(context) {
289     return context.actual !== context.expected;
290   });
291
292   failed.forEach(function(context) {
293     console.log('Mismatched %s function calls. Expected %d, actual %d.',
294                 context.name,
295                 context.expected,
296                 context.actual);
297     console.log(context.stack.split('\n').slice(2).join('\n'));
298   });
299
300   if (failed.length) process.exit(1);
301 }
302
303
304 exports.mustCall = function(fn, expected) {
305   if (typeof expected !== 'number') expected = 1;
306
307   var context = {
308     expected: expected,
309     actual: 0,
310     stack: (new Error).stack,
311     name: fn.name || '<anonymous>'
312   };
313
314   // add the exit listener only once to avoid listener leak warnings
315   if (mustCallChecks.length === 0) process.on('exit', runCallChecks);
316
317   mustCallChecks.push(context);
318
319   return function() {
320     context.actual++;
321     return fn.apply(this, arguments);
322   };
323 };
324
325 exports.checkSpawnSyncRet = function(ret) {
326   assert.strictEqual(ret.status, 0);
327   assert.strictEqual(ret.error, undefined);
328 };
329
330 var etcServicesFileName = path.join('/etc', 'services');
331 if (process.platform === 'win32') {
332   etcServicesFileName = path.join(process.env.SystemRoot, 'System32', 'drivers',
333     'etc', 'services');
334 }
335
336 /*
337  * Returns a string that represents the service name associated
338  * to the service bound to port "port" and using protocol "protocol".
339  *
340  * If the service is not defined in the services file, it returns
341  * the port number as a string.
342  *
343  * Returns undefined if /etc/services (or its equivalent on non-UNIX
344  * platforms) can't be read.
345  */
346 exports.getServiceName = function getServiceName(port, protocol) {
347   if (port == null) {
348     throw new Error("Missing port number");
349   }
350
351   if (typeof protocol !== 'string') {
352     throw new Error("Protocol must be a string");
353   }
354
355   /*
356    * By default, if a service can't be found in /etc/services,
357    * its name is considered to be its port number.
358    */
359   var serviceName = port.toString();
360
361   try {
362     /*
363      * I'm not a big fan of readFileSync, but reading /etc/services asynchronously
364      * here would require implementing a simple line parser, which seems overkill
365      * for a simple utility function that is not running concurrently with any
366      * other one.
367      */
368     var servicesContent = fs.readFileSync(etcServicesFileName,
369       { encoding: 'utf8'});
370     var regexp = util.format('^(\\w+)\\s+\\s%d/%s\\s', port, protocol);
371     var re = new RegExp(regexp, 'm');
372
373     var matches = re.exec(servicesContent);
374     if (matches && matches.length > 1) {
375       serviceName = matches[1];
376     }
377   } catch(e) {
378     console.error('Cannot read file: ', etcServicesFileName);
379     return undefined;
380   }
381
382   return serviceName;
383 }
384
385 exports.hasMultiLocalhost = function hasMultiLocalhost() {
386   var TCP = process.binding('tcp_wrap').TCP;
387   var t = new TCP();
388   var ret = t.bind('127.0.0.2', exports.PORT);
389   t.close();
390   return ret === 0;
391 };
392
393 exports.isValidHostname = function(str) {
394   // See http://stackoverflow.com/a/3824105
395   var re = new RegExp(
396     '^([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])' +
397     '(\\.([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9]))*$');
398
399   return !!str.match(re) && str.length <= 255;
400 }
401
402 exports.fileExists = function(pathname) {
403   try {
404     fs.accessSync(pathname);
405     return true;
406   } catch (err) {
407     return false;
408   }
409 };