Skip to content

Commit

Permalink
fix #129 install process listeners safely
Browse files Browse the repository at this point in the history
fix #136 flaky tests for detachDescriptor option
  • Loading branch information
silkentrance committed Jul 6, 2017
1 parent f8db66b commit b838d3a
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 33 deletions.
75 changes: 59 additions & 16 deletions lib/tmp.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@
/*
* Module dependencies.
*/
const tmpdir = require('os-tmpdir');
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const osTmpDir = require('os-tmpdir');
const _c = process.binding('constants');


// we use this for determining which SIGINT handler we need to install
// TODO:is M$ so dim, win32 for win64 and future win128 platforms?
const isWindows = process.platform == 'win32';


/*
* The working inner variables.
*/
Expand All @@ -23,7 +29,7 @@ const
* The temporary directory.
* @type {string}
*/
tmpDir = osTmpDir(),
tmpDir = tmpdir(),

// the random characters to choose from
RANDOM_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
Expand Down Expand Up @@ -96,15 +102,14 @@ function _isUndefined(obj) {
* @private
*/
function _parseArguments(options, callback) {
if (typeof options == 'function') {
return [callback || {}, options];
}
var result = [options || {}, callback];

if (_isUndefined(options)) {
return [{}, callback];
if (typeof options == 'function') {
result[0] = {};
result[1] = options;
}

return [options, callback];
return result;
}

/**
Expand All @@ -121,6 +126,7 @@ function _generateTmpName(opts) {

// mkstemps like template
if (opts.template) {
// expects user to provide a working path
return opts.template.replace(TEMPLATE_PATTERN, _randomChars(6));
}

Expand Down Expand Up @@ -154,6 +160,7 @@ function tmpName(options, callback) {
if (opts.template && !opts.template.match(TEMPLATE_PATTERN))
return cb(new Error('Invalid template provided'));

// FIXME:get rid of duplicate code
(function _getUniqueName() {
const name = _generateTmpName(opts);

Expand Down Expand Up @@ -189,6 +196,7 @@ function tmpNameSync(options) {
if (opts.template && !opts.template.match(TEMPLATE_PATTERN))
throw new Error('Invalid template provided');

// FIXME:get rid of duplicate code
do {
const name = _generateTmpName(opts);
try {
Expand Down Expand Up @@ -517,19 +525,54 @@ const version = process.versions.node.split('.').map(function (value) {
return parseInt(value, 10);
});

if (version[0] === 0 && (version[1] < 9 || version[1] === 9 && version[2] < 5)) {
process.addListener('uncaughtException', function _uncaughtExceptionThrown(err) {
_uncaughtException = true;
_garbageCollector();
// safely install listeners
function _tmp$uncaught_exception(err) {
_uncaughtException = true;
_garbageCollector();

throw err;
});
throw err;
}

process.addListener('exit', function _exit(code) {
function _tmp$exit(code) {
// TODO:setting uncaught exception here is a no-no as it prevents
// garbage collection for a process that exited gracefully
if (code) _uncaughtException = true;
_garbageCollector();
});
}

function _is_legacy_listener(name) {
return name == '_exit' || name == '_uncaughtExceptionThrown';
}

function _safely_install_listener(evt, listener) {
var listeners = process.listeners(evt);

for (var i = 0, length = listeners.length; i < length; i++) {
var lstnr = listeners[i];
if ((lstnr.name == listener.name) || _is_legacy_listener(listener.name)) {
if (evt == 'exit') {
// make sure that the handler cleans up
try {
lstnr();
}
catch (err) {
; // just catch
}
}
process.removeListener(evt, lstnr);
break;
}
}

process.addListener(evt, listener);
}

if (version[0] === 0 && (version[1] < 9 || version[1] === 9 && version[2] < 5)) {
_safely_install_listener('uncaughtException', _tmp$uncaught_exception);
}

_safely_install_listener('exit', _tmp$exit);


/**
* Configuration options.
Expand Down
29 changes: 12 additions & 17 deletions test/file-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,16 @@ function _testFileNoDescriptor(mode) {
};
}

function _testFileAfterDetachRemove(mode) {
return function _testFileAfterDetachRemove(err, name, fd) {
assert.ok(!existsSync(name), 'File should be removed');

var fstat = fs.fstatSync(fd);
assert.equal(fstat.size, 0, 'should have zero size');
assert.ok(fstat.isFile(), 'should be a file');
Test.testStat(fstat, mode);

var data = new Buffer('something');
assert.equal(fs.writeSync(fd, data, 0, data.length, 0), data.length, 'should be writable');
assert.ok(!fs.closeSync(fd), 'should not return with error');
function _testFileAfterDetachDescriptor(mode) {
return function _testFileAfterDetachDescriptorImpl(err, name, fd) {
assert.ok(existsSync(name), 'should exist');

var stat = fs.fstatSync(fd);
assert.equal(stat.size, 0, 'should have zero size');
assert.ok(stat.isFile(), 'should be a file');
Test.testStat(stat, mode);

assert.ok(fd != undefined, 'fd must be defined');
};
}

Expand Down Expand Up @@ -144,15 +142,12 @@ vows.describe('File creation').addBatch({
'when using detachDescriptor': {
topic: function () {
var cb = this.callback;
tmp.file({ detachDescriptor: true }, function (err, name, fd, removeCallback) {
removeCallback();
return cb(err, name, fd);
});
tmp.file({ detachDescriptor: true }, this.callback)
},

'should not return with an error': assert.isNull,
'should return with a name': Test.assertName,
'should have working descriptor after removeCallback': _testFileAfterDetachRemove(0100600),
'should have working a working file': _testFileAfterDetachDescriptor(0100600),
'should have been cleaned up': Test.testCleanup
},

Expand Down

0 comments on commit b838d3a

Please sign in to comment.