From 0eba297033556e3503af03bb4449afad68cbe4eb Mon Sep 17 00:00:00 2001 From: Carsten Klein Date: Mon, 10 Jul 2017 18:42:04 +0200 Subject: [PATCH] fix #129 --- lib/tmp.js | 50 +++++++++++++------ test/assertions.js | 4 ++ test/child-process.js | 33 +++++++++--- test/dir-sync-test.js | 16 +++--- test/dir-test.js | 16 +++--- test/file-sync-test.js | 12 ++--- test/file-test.js | 12 ++--- test/issue129-test.js | 28 +++++++++++ test/outband/issue129.js | 80 ++++++++++++++++++++++++++++++ test/outband/issue129.json | 3 ++ test/outband/issue62-sync.json | 2 +- test/outband/issue62.json | 2 +- test/outband/unlink-dir-sync.json | 2 +- test/outband/unlink-dir.json | 2 +- test/outband/unlink-file-sync.json | 2 +- test/outband/unlink-file.json | 2 +- test/outband/unlink.js | 11 ++++ test/outband/unsafe-sync.json | 2 +- test/outband/unsafe.json | 2 +- test/spawn-custom.js | 14 ++++++ test/spawn-generic.js | 35 +++++++++++++ test/spawn.js | 52 ++++--------------- test/util.js | 9 ++++ 23 files changed, 291 insertions(+), 100 deletions(-) create mode 100644 test/issue129-test.js create mode 100644 test/outband/issue129.js create mode 100644 test/outband/issue129.json create mode 100644 test/outband/unlink.js create mode 100644 test/spawn-custom.js create mode 100644 test/spawn-generic.js create mode 100644 test/util.js diff --git a/lib/tmp.js b/lib/tmp.js index 223bba2..1175a4f 100644 --- a/lib/tmp.js +++ b/lib/tmp.js @@ -40,12 +40,13 @@ const DIR_MODE = 448 /* 0o700 */, FILE_MODE = 384 /* 0o600 */, + EVENT = 'exit', + // this will hold the objects need to be removed on exit _removeObjects = []; var - _gracefulCleanup = false, - _uncaughtException = false; + _gracefulCleanup = false; /** * Random name generator based on crypto. @@ -97,7 +98,7 @@ function _isUndefined(obj) { */ function _parseArguments(options, callback) { if (typeof options == 'function') { - return [callback || {}, options]; + return [{}, options]; } if (_isUndefined(options)) { @@ -460,7 +461,7 @@ function _prepareRemoveCallback(removeFunction, arg) { * @private */ function _garbageCollector() { - if (_uncaughtException && !_gracefulCleanup) { + if (!_gracefulCleanup) { return; } @@ -515,8 +516,6 @@ function isExpectedError(error, code, errno) { /** * Sets the graceful cleanup. - * - * Also removes the created files and directories when an uncaught exception occurs. */ function setGracefulCleanup() { _gracefulCleanup = true; @@ -526,19 +525,40 @@ 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(); +/** + * If there are multiple different versions of tmp in place, make sure that + * we recognize the old listeners. + */ +function _is_legacy_listener(listener) { + return (listener.name == '_exit' || listener.name == '_uncaughtExceptionThrown') + && listener.toString().indexOf('_garbageCollector();') > -1; +} - throw err; +function _safely_install_listener() { + var listeners = process.listeners(EVENT); + + // collect any existing listeners + var existingListeners = []; + for (var i = 0, length = listeners.length; i < length; i++) { + var lstnr = listeners[i]; + if (lstnr.name == '_tmp$safe_listener' || _is_legacy_listener(lstnr)) { + if (lstnr.name != '_uncaughtExceptionThrown') existingListeners.push(lstnr); + process.removeListener(EVENT, lstnr); + } + } + + process.addListener(EVENT, function _tmp$safe_listener(data) { + if (existingListeners.length) { + for (var i = 0, length = existingListeners.length; i < length; i++) { + existingListeners[i](data); + } + } + _garbageCollector(); }); } -process.addListener('exit', function _exit(code) { - if (code) _uncaughtException = true; - _garbageCollector(); -}); +_safely_install_listener(); + /** * Configuration options. diff --git a/test/assertions.js b/test/assertions.js index a25c3de..8e7a246 100644 --- a/test/assertions.js +++ b/test/assertions.js @@ -67,3 +67,7 @@ module.exports.assertDoesNotExist = function assertDoesNotExist(name) { assert.ok(!existsSync(name), name + ' should not exist'); }; +module.exports.assertDoesNotStartWith = function assertDoesNotStartWith(s, prefix, msg) { + if (s.indexOf(prefix) == 0) assert.fail(msg || s); +}; + diff --git a/test/child-process.js b/test/child-process.js index bb017f0..20c6c02 100644 --- a/test/child-process.js +++ b/test/child-process.js @@ -7,10 +7,33 @@ var spawn = require('child_process').spawn; -module.exports = function spawnChildProcess(configFile, cb) { +module.exports.genericChildProcess = function spawnGenericChildProcess(configFile, cb) { + var + configFilePath = path.join(__dirname, 'outband', configFile), + command_args = [path.join(__dirname, 'spawn-generic.js'), configFilePath]; + + // make sure that the config file exists + if (!existsSync(configFilePath)) + return cb(new Error('ENOENT: configFile ' + configFilePath + ' does not exist')); + + _do_spawn(command_args, cb); +}; + +module.exports.childProcess = function spawnChildProcess(configFile, cb) { + var + configFilePath = path.join(__dirname, 'outband', configFile), + command_args = [path.join(__dirname, 'spawn-custom.js'), configFilePath]; + + // make sure that the config file exists + if (!existsSync(configFilePath)) + return cb(new Error('ENOENT: configFile ' + configFilePath + ' does not exist')); + + _do_spawn(command_args, cb); +} + +function _do_spawn(command_args, cb) { var node_path = process.argv[0], - command_args = [path.join(__dirname, 'spawn.js')].concat(configFile), stdoutBufs = [], stderrBufs = [], child, @@ -18,14 +41,11 @@ module.exports = function spawnChildProcess(configFile, cb) { stderrDone = false, stdoutDone = false; - // make sure that the config file exists - if (!existsSync(path.join(__dirname, configFile))) - return cb(new Error('ENOENT: configFile ' + path.join(__dirname, configFile) + ' does not exist')); - // spawn doesn’t have the quoting problems that exec does, // especially when going for Windows portability. child = spawn(node_path, command_args); child.stdin.end(); + // TODO:we no longer support node 0.6 // Cannot use 'close' event because not on node-0.6. function _close() { var @@ -56,7 +76,6 @@ module.exports = function spawnChildProcess(configFile, cb) { }); } - function _bufferConcat(buffers) { if (Buffer.concat) { return Buffer.concat.apply(this, arguments); diff --git a/test/dir-sync-test.js b/test/dir-sync-test.js index e7289f8..91e13b1 100644 --- a/test/dir-sync-test.js +++ b/test/dir-sync-test.js @@ -6,7 +6,7 @@ var fs = require('fs'), path = require('path'), inbandStandardTests = require('./inband-standard'), - childProcess = require('./child-process'), + childProcess = require('./child-process').genericChildProcess, assertions = require('./assertions'), tmp = require('../lib/tmp'); @@ -54,7 +54,7 @@ describe('tmp', function () { // API call standard outband tests describe('when running standard outband tests', function () { it('on graceful cleanup', function (done) { - childProcess('outband/graceful-dir-sync.json', function (err, stderr, stdout) { + childProcess('graceful-dir-sync.json', function (err, stderr, stdout) { if (err) return done(err); else if (!stderr) assert.fail('stderr expected'); else assertions.assertDoesNotExist(stdout); @@ -62,7 +62,7 @@ describe('tmp', function () { }); }); it('on non graceful cleanup', function (done) { - childProcess('outband/non-graceful-dir-sync.json', function (err, stderr, stdout) { + childProcess('non-graceful-dir-sync.json', function (err, stderr, stdout) { if (err) return done(err); else if (!stderr) assert.fail('stderr expected'); else { @@ -73,7 +73,7 @@ describe('tmp', function () { }); }); it('on keep', function (done) { - childProcess('outband/keep-dir-sync.json', function (err, stderr, stdout) { + childProcess('keep-dir-sync.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else { @@ -84,7 +84,7 @@ describe('tmp', function () { }); }); it('on unlink (keep == false)', function (done) { - childProcess('outband/unlink-dir-sync.json', function (err, stderr, stdout) { + childProcess('unlink-dir-sync.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else assertions.assertDoesNotExist(stdout); @@ -92,7 +92,7 @@ describe('tmp', function () { }); }); it('on unsafe cleanup', function (done) { - childProcess('outband/unsafe-sync.json', function (err, stderr, stdout) { + childProcess('unsafe-sync.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else { @@ -105,7 +105,7 @@ describe('tmp', function () { }); }); it('on non unsafe cleanup', function (done) { - childProcess('outband/non-unsafe-sync.json', function (err, stderr, stdout) { + childProcess('non-unsafe-sync.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else { @@ -128,7 +128,7 @@ describe('tmp', function () { describe('when running issue specific outband tests', function () { // add your issue specific tests here it('on issue #62', function (done) { - childProcess('outband/issue62-sync.json', function (err, stderr, stdout) { + childProcess('issue62-sync.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else assertions.assertDoesNotExist(stdout); diff --git a/test/dir-test.js b/test/dir-test.js index 2d8e682..74ce178 100644 --- a/test/dir-test.js +++ b/test/dir-test.js @@ -6,7 +6,7 @@ var fs = require('fs'), path = require('path'), inbandStandardTests = require('./inband-standard'), - childProcess = require('./child-process'), + childProcess = require('./child-process').genericChildProcess, assertions = require('./assertions'), tmp = require('../lib/tmp'); @@ -55,7 +55,7 @@ describe('tmp', function () { // API call standard outband tests describe('when running standard outband tests', function () { it('on graceful cleanup', function (done) { - childProcess('outband/graceful-dir.json', function (err, stderr, stdout) { + childProcess('graceful-dir.json', function (err, stderr, stdout) { if (err) return done(err); else if (!stderr) assert.fail('stderr expected'); else assertions.assertDoesNotExist(stdout); @@ -63,7 +63,7 @@ describe('tmp', function () { }); }); it('on non graceful cleanup', function (done) { - childProcess('outband/non-graceful-dir.json', function (err, stderr, stdout) { + childProcess('non-graceful-dir.json', function (err, stderr, stdout) { if (err) return done(err); else if (!stderr) assert.fail('stderr expected'); else { @@ -74,7 +74,7 @@ describe('tmp', function () { }); }); it('on keep', function (done) { - childProcess('outband/keep-dir.json', function (err, stderr, stdout) { + childProcess('keep-dir.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else { @@ -85,7 +85,7 @@ describe('tmp', function () { }); }); it('on unlink (keep == false)', function (done) { - childProcess('outband/unlink-dir.json', function (err, stderr, stdout) { + childProcess('unlink-dir.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else assertions.assertDoesNotExist(stdout); @@ -93,7 +93,7 @@ describe('tmp', function () { }); }); it('on unsafe cleanup', function (done) { - childProcess('outband/unsafe.json', function (err, stderr, stdout) { + childProcess('unsafe.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else { @@ -106,7 +106,7 @@ describe('tmp', function () { }); }); it('on non unsafe cleanup', function (done) { - childProcess('outband/non-unsafe.json', function (err, stderr, stdout) { + childProcess('non-unsafe.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else { @@ -129,7 +129,7 @@ describe('tmp', function () { describe('when running issue specific outband tests', function () { // add your issue specific tests here it('on issue #62', function (done) { - childProcess('outband/issue62.json', function (err, stderr, stdout) { + childProcess('issue62.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else assertions.assertDoesNotExist(stdout); diff --git a/test/file-sync-test.js b/test/file-sync-test.js index 40377b9..d418b53 100644 --- a/test/file-sync-test.js +++ b/test/file-sync-test.js @@ -6,7 +6,7 @@ var fs = require('fs'), inbandStandardTests = require('./inband-standard'), assertions = require('./assertions'), - childProcess = require('./child-process'), + childProcess = require('./child-process').genericChildProcess, tmp = require('../lib/tmp'); @@ -51,7 +51,7 @@ describe('tmp', function () { // API call standard outband tests describe('when running standard outband tests', function () { it('on graceful', function (done) { - childProcess('outband/graceful-file-sync.json', function (err, stderr, stdout) { + childProcess('graceful-file-sync.json', function (err, stderr, stdout) { if (err) return done(err); else if (!stderr) assert.fail('stderr expected'); else assertions.assertDoesNotExist(stdout); @@ -59,7 +59,7 @@ describe('tmp', function () { }); }); it('on non graceful', function (done) { - childProcess('outband/non-graceful-file-sync.json', function (err, stderr, stdout) { + childProcess('non-graceful-file-sync.json', function (err, stderr, stdout) { if (err) return done(err); else if (!stderr) assert.fail('stderr expected'); else { @@ -70,7 +70,7 @@ describe('tmp', function () { }); }); it('on keep', function (done) { - childProcess('outband/keep-file-sync.json', function (err, stderr, stdout) { + childProcess('keep-file-sync.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else { @@ -81,7 +81,7 @@ describe('tmp', function () { }); }); it('on unlink (keep == false)', function (done) { - childProcess('outband/unlink-file-sync.json', function (err, stderr, stdout) { + childProcess('unlink-file-sync.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else assertions.assertDoesNotExist(stdout); @@ -94,7 +94,7 @@ describe('tmp', function () { describe('when running issue specific outband tests', function () { // add your issue specific tests here it('on issue #115', function (done) { - childProcess('outband/issue115-sync.json', function (err, stderr, stdout) { + childProcess('issue115-sync.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else assertions.assertDoesNotExist(stdout); diff --git a/test/file-test.js b/test/file-test.js index 40a4ccf..a07899c 100644 --- a/test/file-test.js +++ b/test/file-test.js @@ -6,7 +6,7 @@ var fs = require('fs'), inbandStandardTests = require('./inband-standard'), assertions = require('./assertions'), - childProcess = require('./child-process'), + childProcess = require('./child-process').genericChildProcess, tmp = require('../lib/tmp'); @@ -54,7 +54,7 @@ describe('tmp', function () { // API call standard outband tests describe('when running standard outband tests', function () { it('on graceful', function (done) { - childProcess('outband/graceful-file.json', function (err, stderr, stdout) { + childProcess('graceful-file.json', function (err, stderr, stdout) { if (err) return done(err); else if (!stderr) assert.fail('stderr expected'); else assertions.assertDoesNotExist(stdout); @@ -62,7 +62,7 @@ describe('tmp', function () { }); }); it('on non graceful', function (done) { - childProcess('outband/non-graceful-file.json', function (err, stderr, stdout) { + childProcess('non-graceful-file.json', function (err, stderr, stdout) { if (err) return done(err); else if (!stderr) assert.fail('stderr expected'); else { @@ -73,7 +73,7 @@ describe('tmp', function () { }); }); it('on keep', function (done) { - childProcess('outband/keep-file.json', function (err, stderr, stdout) { + childProcess('keep-file.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else { @@ -84,7 +84,7 @@ describe('tmp', function () { }); }); it('on unlink (keep == false)', function (done) { - childProcess('outband/unlink-file.json', function (err, stderr, stdout) { + childProcess('unlink-file.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else assertions.assertDoesNotExist(stdout); @@ -97,7 +97,7 @@ describe('tmp', function () { describe('when running issue specific outband tests', function () { // add your issue specific tests here it('on issue #115', function (done) { - childProcess('outband/issue115.json', function (err, stderr, stdout) { + childProcess('issue115.json', function (err, stderr, stdout) { if (err) return done(err); else if (stderr) assert.fail(stderr); else assertions.assertDoesNotExist(stdout); diff --git a/test/issue129-test.js b/test/issue129-test.js new file mode 100644 index 0000000..4380f0f --- /dev/null +++ b/test/issue129-test.js @@ -0,0 +1,28 @@ +/* eslint-disable no-octal */ +// vim: expandtab:ts=2:sw=2 + +var + assert = require('assert'), + assertions = require('./assertions'), + childProcess = require('./child-process').childProcess; + +describe('tmp', function () { + describe('issue129: safely install listeners', function () { + it('when simulating sandboxed behavior', function (done) { + childProcess('issue129.json', function (err, stderr, stdout) { + if (err) return done(err); + else if (stderr) { + assertions.assertDoesNotStartWith(stderr, 'EEXISTS:LEGACY:EXIT'); + assertions.assertDoesNotStartWith(stderr, 'EEXISTS:LEGACY:UNCAUGHT'); + assertions.assertDoesNotStartWith(stderr, 'EEXISTS:NEWSTYLE'); + assertions.assertDoesNotStartWith(stderr, 'ENOAVAIL:LEGACY:EXIT'); + assertions.assertDoesNotStartWith(stderr, 'EAVAIL:LEGACY:UNCAUGHT'); + assertions.assertDoesNotStartWith(stderr, 'ENOAVAIL:NEWSTYLE'); + assert.equal(stderr, 'EOK', 'existing listeners should have been removed and called'); + } + done(); + }); + }); + }); +}); + diff --git a/test/outband/issue129.js b/test/outband/issue129.js new file mode 100644 index 0000000..653e9a1 --- /dev/null +++ b/test/outband/issue129.js @@ -0,0 +1,80 @@ +/* eslint-disable no-octal */ +// vim: expandtab:ts=2:sw=2 + +var fs = require('fs'); + +// https://github.com/raszi/node-tmp/issues/129 +module.exports = function () { + +// dup from lib/tmp.js +function _is_legacy_listener(listener) { + return (listener.name == '_exit' || listener.name == '_uncaughtExceptionThrown') + && listener.toString().indexOf('_garbageCollector();') != -1; +} + +function _garbageCollector() {} + + var callState = { + newStyleListener : false, + legacyExitListener : false, + legacyUncaughtListener : false + }; + + // simulate the new exit listener + var listener1 = (function (callState) { + return function _tmp$safe_listener(data) { + _garbageCollector(); + callState.newStyleListener = true; + }; + })(callState); + + // simulate the legacy _exit listener + var listener2 = (function (callState) { + return function _exit(code) { + _garbageCollector(); + callState.legacyExitListener = true; + }; + })(callState); + + // simulate the legacy _uncaughtExceptionThrown listener + var listener3 = (function (callState) { + return function _uncaughtExceptionThrown(err) { + _garbageCollector(); + callState.legacyUncaughtListener = true; + }; + })(callState); + + process.addListener('exit', listener1); + process.addListener('exit', listener2); + process.addListener('exit', listener3); + + // now let tmp install its listener safely + var tmp = require('../../lib/tmp'); + + var legacyExitListener = null; + var legacyUncaughtListener = null; + var newStyleListeners = []; + + var listeners = process.listeners('exit'); + for (var i = 0; i < listeners.length; i++) { + var listener = listeners[i]; + // the order here is important + if (listener.name == '_tmp$safe_listener') { + newStyleListeners.push(listener); + } + else if (_is_legacy_listener(listener)) { + if (listener.name == '_uncaughtExceptionThrown') legacyUncaughtListener = listener; + else legacyExitListener = listener; + } + } + + if (legacyExitListener) this.fail('EEXISTS:LEGACY:EXIT existing legacy exit listener was not removed', this.exit); + if (legacyUncaughtListener) this.fail('EEXISTS:LEGACY:UNCAUGHT existing legacy uncaught exception thrown listener was not removed', this.exit); + if (newStyleListeners.length > 1) this.fail('EEXISTS:NEWSTYLE: existing new style listener was not removed', this.exit); + newStyleListeners[0](); + if (!callState.legacyExitListener) this.fail('ENOAVAIL:LEGACY:EXIT existing legacy exit listener was not called', this.exit); + if (callState.legacyUncaughtListener) this.fail('EAVAIL:LEGACY:UNCAUGHT existing legacy uncaught exception thrown listener should not have been called', this.exit); + if (!callState.newStyleListener) this.fail('ENOAVAIL:NEWSTYLE: existing new style listener was not called', this.exit); + this.out('EOK', this.exit); +}; + diff --git a/test/outband/issue129.json b/test/outband/issue129.json new file mode 100644 index 0000000..3d7794c --- /dev/null +++ b/test/outband/issue129.json @@ -0,0 +1,3 @@ +{ + "tc": "issue129" +} diff --git a/test/outband/issue62-sync.json b/test/outband/issue62-sync.json index 84d1df6..c4a7118 100644 --- a/test/outband/issue62-sync.json +++ b/test/outband/issue62-sync.json @@ -3,5 +3,5 @@ "async": false, "file": false, "options": { "unsafeCleanup":true }, - "graceful": false + "graceful": true } diff --git a/test/outband/issue62.json b/test/outband/issue62.json index b1fd7b9..457bd5e 100644 --- a/test/outband/issue62.json +++ b/test/outband/issue62.json @@ -3,5 +3,5 @@ "async": true, "file": false, "options": { "unsafeCleanup":true }, - "graceful": false + "graceful": true } diff --git a/test/outband/unlink-dir-sync.json b/test/outband/unlink-dir-sync.json index e1d283c..1b0cf47 100644 --- a/test/outband/unlink-dir-sync.json +++ b/test/outband/unlink-dir-sync.json @@ -1,5 +1,5 @@ { - "tc": "keep", + "tc": "unlink", "async": false, "file": false, "options": { "keep":false }, diff --git a/test/outband/unlink-dir.json b/test/outband/unlink-dir.json index 8c9bb81..07a4e7b 100644 --- a/test/outband/unlink-dir.json +++ b/test/outband/unlink-dir.json @@ -1,5 +1,5 @@ { - "tc": "keep", + "tc": "unlink", "async": true, "file": false, "options": { "keep":false }, diff --git a/test/outband/unlink-file-sync.json b/test/outband/unlink-file-sync.json index 169a5d7..accec95 100644 --- a/test/outband/unlink-file-sync.json +++ b/test/outband/unlink-file-sync.json @@ -1,5 +1,5 @@ { - "tc": "keep", + "tc": "unlink", "async": false, "file": true, "options": { "keep":false }, diff --git a/test/outband/unlink-file.json b/test/outband/unlink-file.json index 873a685..52ab534 100644 --- a/test/outband/unlink-file.json +++ b/test/outband/unlink-file.json @@ -1,5 +1,5 @@ { - "tc": "keep", + "tc": "unlink", "async": true, "file": true, "options": { "keep":false }, diff --git a/test/outband/unlink.js b/test/outband/unlink.js new file mode 100644 index 0000000..bda80d1 --- /dev/null +++ b/test/outband/unlink.js @@ -0,0 +1,11 @@ +const fs = require('fs'); + +module.exports = function (result, tmp) { + const stat = fs.statSync(result.name); + if (stat.isFile()) { + fs.unlinkSync(result.name); + } else { + fs.rmdirSync(result.name); + } + this.out(result.name); +}; diff --git a/test/outband/unsafe-sync.json b/test/outband/unsafe-sync.json index 158a31c..566009d 100644 --- a/test/outband/unsafe-sync.json +++ b/test/outband/unsafe-sync.json @@ -3,5 +3,5 @@ "async": false, "file": false, "options": { "unsafeCleanup":true }, - "graceful": false + "graceful": true } diff --git a/test/outband/unsafe.json b/test/outband/unsafe.json index ef329b4..b9d73a8 100644 --- a/test/outband/unsafe.json +++ b/test/outband/unsafe.json @@ -3,5 +3,5 @@ "async": true, "file": false, "options": { "unsafeCleanup":true }, - "graceful": false + "graceful": true } diff --git a/test/spawn-custom.js b/test/spawn-custom.js new file mode 100644 index 0000000..bb1cc27 --- /dev/null +++ b/test/spawn-custom.js @@ -0,0 +1,14 @@ +// vim: expandtab:ts=2:sw=2 + +var + path = require('path'), + readJsonConfig = require('./util').readJsonConfig, + spawn = require('./spawn'); + +var config = readJsonConfig(process.argv[2]); +spawn.graceful = !!config.graceful; + +// import the test case function and execute it +var fn = require(path.join(__dirname, 'outband', config.tc)); +fn.apply(spawn); + diff --git a/test/spawn-generic.js b/test/spawn-generic.js new file mode 100644 index 0000000..6b4cb5b --- /dev/null +++ b/test/spawn-generic.js @@ -0,0 +1,35 @@ +// vim: expandtab:ts=2:sw=2 + +var + path = require('path'), + readJsonConfig = require('./util').readJsonConfig, + spawn = require('./spawn'), + tmp = require('../lib/tmp'); + +var config = readJsonConfig(process.argv[2]); +spawn.graceful = !!config.graceful; + +var fnUnderTest = null; + +if (config.async) fnUnderTest = (config.file) ? tmp.file : tmp.dir; +else fnUnderTest = (config.file) ? tmp.fileSync : tmp.dirSync; + +// do we test against tmp doing a graceful cleanup? +if (config.graceful) tmp.setGracefulCleanup(); + +// import the test case function and execute it +var fn = require(path.join(__dirname, 'outband', config.tc)); +if (config.async) + fnUnderTest(config.options, function (err, name, fdOrCallback, cb) { + if (err) spawn.err(err); + else { + var result = null; + if (config.file) result = { name: name, fd: fdOrCallback, removeCallback: cb }; + else result = { name: name, removeCallback: fdOrCallback }; + fn.apply(spawn, [result, tmp]); + } + }); +else { + fn.apply(spawn, [fnUnderTest(config.options), tmp]); +} + diff --git a/test/spawn.js b/test/spawn.js index efd01fa..9635e94 100644 --- a/test/spawn.js +++ b/test/spawn.js @@ -2,8 +2,7 @@ var fs = require('fs'), - path = require('path'), - tmp = require('../lib/tmp'); + path = require('path'); function _writeSync(stream, str, cb) { var flushed = stream.write(str); @@ -16,16 +15,21 @@ function _writeSync(stream, str, cb) { }); } -var spawn = { +module.exports = { + graceful: false, out: function (str, cb) { - cb = cb || spawn.exit; + cb = cb || this.exit; _writeSync(process.stdout, str, cb); }, err: function (errOrStr, cb) { - cb = cb || spawn.exit; - if (!config.graceful) _writeSync(process.stderr, (errOrStr instanceof Error) ? errOrStr.toString() : errOrStr, cb); + cb = cb || this.exit; + if (!this.graceful) _writeSync(process.stderr, (errOrStr instanceof Error) ? errOrStr.toString() : errOrStr, cb); else cb(); }, + fail: function (errOrStr, cb) { + cb = cb || this.exit; + _writeSync(process.stderr, (errOrStr instanceof Error) ? errOrStr.toString() : errOrStr, cb); + }, exit: function (code) { process.exit(code || 0); }, @@ -34,39 +38,3 @@ var spawn = { } }; -var config = {}; -try { - var contents = fs.readFileSync(path.join(__dirname, process.argv[2])); - config = JSON.parse(contents); -} -catch (err) { - spawn.err(err); -} - -var fnUnderTest = null; - -if (config.async) fnUnderTest = (config.file) ? tmp.file : tmp.dir; -else fnUnderTest = (config.file) ? tmp.fileSync : tmp.dirSync; - -// do we test against tmp doing a graceful cleanup? -if (config.graceful) tmp.setGracefulCleanup(); - -// import the test case function and execute it -var fn = require(path.join(__dirname, 'outband', config.tc)); -if (config.async) - fnUnderTest(config.options, function (err, name, fdOrCallback, cb) { - if (err) spawn.err(err); - else { - var result = null; - if (config.file) result = { name: name, fd: fdOrCallback, removeCallback: cb }; - else result = { name: name, removeCallback: fdOrCallback }; - fn.apply(spawn, [result, tmp]); - } - }); -else { - var result = null; - var err = null; - result = fnUnderTest(config.options); - fn.apply(spawn, [result, tmp]); -} - diff --git a/test/util.js b/test/util.js new file mode 100644 index 0000000..0d399df --- /dev/null +++ b/test/util.js @@ -0,0 +1,9 @@ +// vim: expandtab:ts=2:sw=2 + +var + fs = require('fs'); + +module.exports.readJsonConfig = function readJsonConfig(path) { + var contents = fs.readFileSync(path); + return JSON.parse(contents); +}