You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

209 lines
5.9 KiB

// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// Simple tests of most basic domain functionality.
var common = require('../common');
var assert = require('assert');
var domain = require('domain');
var events = require('events');
var caught = 0;
var expectCaught = 8;
var d = new domain.Domain();
var e = new events.EventEmitter();
d.on('error', function(er) {
console.error('caught', er);
switch (er.message) {
case 'emitted':
assert.equal(er.domain, d);
assert.equal(er.domain_emitter, e);
assert.equal(er.domain_thrown, false);
break;
case 'bound':
assert.ok(!er.domain_emitter);
assert.equal(er.domain, d);
assert.equal(er.domain_bound, fn);
assert.equal(er.domain_thrown, false);
break;
case 'thrown':
assert.ok(!er.domain_emitter);
assert.equal(er.domain, d);
assert.equal(er.domain_thrown, true);
break;
case "ENOENT, open 'this file does not exist'":
assert.equal(er.domain, d);
assert.equal(er.domain_thrown, false);
assert.equal(typeof er.domain_bound, 'function');
assert.ok(!er.domain_emitter);
assert.equal(er.code, 'ENOENT');
assert.equal(er.path, 'this file does not exist');
assert.equal(typeof er.errno, 'number');
break;
case "ENOENT, open 'stream for nonexistent file'":
assert.equal(typeof er.errno, 'number');
assert.equal(er.code, 'ENOENT');
assert.equal(er.path, 'stream for nonexistent file');
assert.equal(er.domain, d);
assert.equal(er.domain_emitter, fst);
assert.ok(!er.domain_bound);
assert.equal(er.domain_thrown, false);
break;
case 'implicit':
assert.equal(er.domain_emitter, implicit);
assert.equal(er.domain, d);
assert.equal(er.domain_thrown, false);
assert.ok(!er.domain_bound);
break;
case 'implicit timer':
assert.equal(er.domain, d);
assert.equal(er.domain_thrown, true);
assert.ok(!er.domain_emitter);
assert.ok(!er.domain_bound);
break;
case 'Cannot call method \'isDirectory\' of undefined':
assert.equal(er.domain, d);
assert.ok(!er.domain_emitter);
assert.ok(!er.domain_bound);
break;
default:
console.error('unexpected error, throwing %j', er.message);
throw er;
}
caught++;
});
process.on('exit', function() {
console.error('exit');
assert.equal(caught, expectCaught);
console.log('ok');
});
// Event emitters added to the domain have their errors routed.
d.add(e);
e.emit('error', new Error('emitted'));
// get rid of the `if (er) return cb(er)` malarky, by intercepting
// the cb functions to the domain, and using the intercepted function
// as a callback instead.
function fn(er) {
throw new Error('This function should never be called!');
process.exit(1);
}
var bound = d.intercept(fn);
bound(new Error('bound'));
// intercepted should never pass first argument to callback
function fn2(data) {
assert.equal(data, 'data', 'should not be null err argument')
}
var bound = d.intercept(fn2);
bound(null, 'data');
// throwing in a bound fn is also caught,
// even if it's asynchronous, by hitting the
// global uncaughtException handler. This doesn't
// require interception, since throws are always
// caught by the domain.
function thrower() {
throw new Error('thrown');
}
setTimeout(d.bind(thrower), 100);
// Pass an intercepted function to an fs operation that fails.
var fs = require('fs');
fs.open('this file does not exist', 'r', d.intercept(function(er) {
console.error('should not get here!', er);
throw new Error('should not get here!');
}, true));
// catch thrown errors no matter how many times we enter the event loop
// this only uses implicit binding, except for the first function
// passed to d.run(). The rest are implicitly bound by virtue of being
// set up while in the scope of the d domain.
d.run(function() {
process.nextTick(function() {
var i = setInterval(function () {
clearInterval(i);
setTimeout(function() {
fs.stat('this file does not exist', function(er, stat) {
// uh oh! stat isn't set!
// pretty common error.
console.log(stat.isDirectory());
});
});
});
});
});
// implicit addition by being created within a domain-bound context.
var implicit;
d.run(function() {
implicit = new events.EventEmitter;
});
setTimeout(function() {
// escape from the domain, but implicit is still bound to it.
implicit.emit('error', new Error('implicit'));
}, 10);
// implicit addition of a timer created within a domain-bound context.
d.run(function() {
setTimeout(function() {
throw new Error('implicit timer');
});
});
var result = d.run(function () {
return 'return value';
});
assert.equal(result, 'return value');
var fst = fs.createReadStream('stream for nonexistent file')
d.add(fst)