pax_global_header00006660000000000000000000000064130207056230014510gustar00rootroot0000000000000052 comment=9c5ad9809fe6135ef22e2623989deaffe2a4fa8a signal-exit-3.0.2/000077500000000000000000000000001302070562300137365ustar00rootroot00000000000000signal-exit-3.0.2/.gitignore000066400000000000000000000000671302070562300157310ustar00rootroot00000000000000node_modules .DS_Store nyc_output coverage .nyc_output signal-exit-3.0.2/.travis.yml000066400000000000000000000001021302070562300160400ustar00rootroot00000000000000sudo: false language: node_js node_js: - '0.12' - '4' - '5' signal-exit-3.0.2/CHANGELOG.md000066400000000000000000000020571302070562300155530ustar00rootroot00000000000000# Change Log All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. ## [3.0.1](https://github.com/tapjs/signal-exit/compare/v3.0.0...v3.0.1) (2016-09-08) ### Bug Fixes * do not listen on SIGBUS, SIGFPE, SIGSEGV and SIGILL ([#40](https://github.com/tapjs/signal-exit/issues/40)) ([5b105fb](https://github.com/tapjs/signal-exit/commit/5b105fb)) # [3.0.0](https://github.com/tapjs/signal-exit/compare/v2.1.2...v3.0.0) (2016-06-13) ### Bug Fixes * get our test suite running on Windows ([#23](https://github.com/tapjs/signal-exit/issues/23)) ([6f3eda8](https://github.com/tapjs/signal-exit/commit/6f3eda8)) * hooking SIGPROF was interfering with profilers see [#21](https://github.com/tapjs/signal-exit/issues/21) ([#24](https://github.com/tapjs/signal-exit/issues/24)) ([1248a4c](https://github.com/tapjs/signal-exit/commit/1248a4c)) ### BREAKING CHANGES * signal-exit no longer wires into SIGPROF signal-exit-3.0.2/LICENSE.txt000066400000000000000000000013541302070562300155640ustar00rootroot00000000000000The ISC License Copyright (c) 2015, Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. signal-exit-3.0.2/README.md000066400000000000000000000027311302070562300152200ustar00rootroot00000000000000# signal-exit [![Build Status](https://travis-ci.org/tapjs/signal-exit.png)](https://travis-ci.org/tapjs/signal-exit) [![Coverage](https://coveralls.io/repos/tapjs/signal-exit/badge.svg?branch=master)](https://coveralls.io/r/tapjs/signal-exit?branch=master) [![NPM version](https://img.shields.io/npm/v/signal-exit.svg)](https://www.npmjs.com/package/signal-exit) [![Windows Tests](https://img.shields.io/appveyor/ci/bcoe/signal-exit/master.svg?label=Windows%20Tests)](https://ci.appveyor.com/project/bcoe/signal-exit) [![Standard Version](https://img.shields.io/badge/release-standard%20version-brightgreen.svg)](https://github.com/conventional-changelog/standard-version) When you want to fire an event no matter how a process exits: * reaching the end of execution. * explicitly having `process.exit(code)` called. * having `process.kill(pid, sig)` called. * receiving a fatal signal from outside the process Use `signal-exit`. ```js var onExit = require('signal-exit') onExit(function (code, signal) { console.log('process exited!') }) ``` ## API `var remove = onExit(function (code, signal) {}, options)` The return value of the function is a function that will remove the handler. Note that the function *only* fires for signals if the signal would cause the proces to exit. That is, there are no other listeners, and it is a fatal signal. ## Options * `alwaysLast`: Run this handler after any other signal or exit handlers. This causes `process.emit` to be monkeypatched. signal-exit-3.0.2/appveyor.yml000066400000000000000000000005711302070562300163310ustar00rootroot00000000000000environment: matrix: - nodejs_version: '5' - nodejs_version: '4' - nodejs_version: '0.12' install: - ps: Install-Product node $env:nodejs_version - set CI=true - npm -g install npm@latest - set PATH=%APPDATA%\npm;%PATH% - npm install matrix: fast_finish: true build: off version: '{build}' shallow_clone: true clone_depth: 1 test_script: - npm test signal-exit-3.0.2/index.js000066400000000000000000000075051302070562300154120ustar00rootroot00000000000000// Note: since nyc uses this module to output coverage, any lines // that are in the direct sync flow of nyc's outputCoverage are // ignored, since we can never get coverage for them. var assert = require('assert') var signals = require('./signals.js') var EE = require('events') /* istanbul ignore if */ if (typeof EE !== 'function') { EE = EE.EventEmitter } var emitter if (process.__signal_exit_emitter__) { emitter = process.__signal_exit_emitter__ } else { emitter = process.__signal_exit_emitter__ = new EE() emitter.count = 0 emitter.emitted = {} } // Because this emitter is a global, we have to check to see if a // previous version of this library failed to enable infinite listeners. // I know what you're about to say. But literally everything about // signal-exit is a compromise with evil. Get used to it. if (!emitter.infinite) { emitter.setMaxListeners(Infinity) emitter.infinite = true } module.exports = function (cb, opts) { assert.equal(typeof cb, 'function', 'a callback must be provided for exit handler') if (loaded === false) { load() } var ev = 'exit' if (opts && opts.alwaysLast) { ev = 'afterexit' } var remove = function () { emitter.removeListener(ev, cb) if (emitter.listeners('exit').length === 0 && emitter.listeners('afterexit').length === 0) { unload() } } emitter.on(ev, cb) return remove } module.exports.unload = unload function unload () { if (!loaded) { return } loaded = false signals.forEach(function (sig) { try { process.removeListener(sig, sigListeners[sig]) } catch (er) {} }) process.emit = originalProcessEmit process.reallyExit = originalProcessReallyExit emitter.count -= 1 } function emit (event, code, signal) { if (emitter.emitted[event]) { return } emitter.emitted[event] = true emitter.emit(event, code, signal) } // { : , ... } var sigListeners = {} signals.forEach(function (sig) { sigListeners[sig] = function listener () { // If there are no other listeners, an exit is coming! // Simplest way: remove us and then re-send the signal. // We know that this will kill the process, so we can // safely emit now. var listeners = process.listeners(sig) if (listeners.length === emitter.count) { unload() emit('exit', null, sig) /* istanbul ignore next */ emit('afterexit', null, sig) /* istanbul ignore next */ process.kill(process.pid, sig) } } }) module.exports.signals = function () { return signals } module.exports.load = load var loaded = false function load () { if (loaded) { return } loaded = true // This is the number of onSignalExit's that are in play. // It's important so that we can count the correct number of // listeners on signals, and don't wait for the other one to // handle it instead of us. emitter.count += 1 signals = signals.filter(function (sig) { try { process.on(sig, sigListeners[sig]) return true } catch (er) { return false } }) process.emit = processEmit process.reallyExit = processReallyExit } var originalProcessReallyExit = process.reallyExit function processReallyExit (code) { process.exitCode = code || 0 emit('exit', process.exitCode, null) /* istanbul ignore next */ emit('afterexit', process.exitCode, null) /* istanbul ignore next */ originalProcessReallyExit.call(process, process.exitCode) } var originalProcessEmit = process.emit function processEmit (ev, arg) { if (ev === 'exit') { if (arg !== undefined) { process.exitCode = arg } var ret = originalProcessEmit.apply(this, arguments) emit('exit', process.exitCode, null) /* istanbul ignore next */ emit('afterexit', process.exitCode, null) return ret } else { return originalProcessEmit.apply(this, arguments) } } signal-exit-3.0.2/package.json000066400000000000000000000016151302070562300162270ustar00rootroot00000000000000{ "name": "signal-exit", "version": "3.0.2", "description": "when you want to fire an event no matter how a process exits.", "main": "index.js", "scripts": { "pretest": "standard", "test": "tap --timeout=240 ./test/*.js --cov", "coverage": "nyc report --reporter=text-lcov | coveralls", "release": "standard-version" }, "files": [ "index.js", "signals.js" ], "repository": { "type": "git", "url": "https://github.com/tapjs/signal-exit.git" }, "keywords": [ "signal", "exit" ], "author": "Ben Coe ", "license": "ISC", "bugs": { "url": "https://github.com/tapjs/signal-exit/issues" }, "homepage": "https://github.com/tapjs/signal-exit", "devDependencies": { "chai": "^3.5.0", "coveralls": "^2.11.10", "nyc": "^8.1.0", "standard": "^7.1.2", "standard-version": "^2.3.0", "tap": "^8.0.1" } } signal-exit-3.0.2/signals.js000066400000000000000000000024171302070562300157400ustar00rootroot00000000000000// This is not the set of all possible signals. // // It IS, however, the set of all signals that trigger // an exit on either Linux or BSD systems. Linux is a // superset of the signal names supported on BSD, and // the unknown signals just fail to register, so we can // catch that easily enough. // // Don't bother with SIGKILL. It's uncatchable, which // means that we can't fire any callbacks anyway. // // If a user does happen to register a handler on a non- // fatal signal like SIGWINCH or something, and then // exit, it'll end up firing `process.emit('exit')`, so // the handler will be fired anyway. // // SIGBUS, SIGFPE, SIGSEGV and SIGILL, when not raised // artificially, inherently leave the process in a // state from which it is not safe to try and enter JS // listeners. module.exports = [ 'SIGABRT', 'SIGALRM', 'SIGHUP', 'SIGINT', 'SIGTERM' ] if (process.platform !== 'win32') { module.exports.push( 'SIGVTALRM', 'SIGXCPU', 'SIGXFSZ', 'SIGUSR2', 'SIGTRAP', 'SIGSYS', 'SIGQUIT', 'SIGIOT' // should detect profiler and enable/disable accordingly. // see #21 // 'SIGPROF' ) } if (process.platform === 'linux') { module.exports.push( 'SIGIO', 'SIGPOLL', 'SIGPWR', 'SIGSTKFLT', 'SIGUNUSED' ) } signal-exit-3.0.2/test/000077500000000000000000000000001302070562300147155ustar00rootroot00000000000000signal-exit-3.0.2/test/all-integration-test.js000066400000000000000000000057401302070562300213270ustar00rootroot00000000000000/* global describe, it */ var exec = require('child_process').exec var assert = require('assert') var isWindows = process.platform === 'win32' var shell = isWindows ? null : { shell: '/bin/bash' } var node = isWindows ? '"' + process.execPath + '"' : process.execPath require('chai').should() require('tap').mochaGlobals() var onSignalExit = require('../') describe('all-signals-integration-test', function () { // These are signals that are aliases for other signals, so // the result will sometimes be one of the others. For these, // we just verify that we GOT a signal, not what it is. function weirdSignal (sig) { return sig === 'SIGIOT' || sig === 'SIGIO' || sig === 'SIGSYS' || sig === 'SIGIOT' || sig === 'SIGABRT' || sig === 'SIGPOLL' || sig === 'SIGUNUSED' } // Exhaustively test every signal, and a few numbers. // signal-exit does not currently support process.kill() // on win32. var signals = isWindows ? [] : onSignalExit.signals() signals.concat('', 0, 1, 2, 3, 54).forEach(function (sig) { var js = require.resolve('./fixtures/exiter.js') it('exits properly: ' + sig, function (done) { // issues with SIGUSR1 on Node 0.10.x if (process.version.match(/^v0\.10\./) && sig === 'SIGUSR1') return done() var cmd = node + ' ' + js + ' ' + sig exec(cmd, shell, function (err, stdout, stderr) { if (sig) { if (!isWindows) assert(err) if (!isNaN(sig)) { if (!isWindows) assert.equal(err.code, sig) } else if (!weirdSignal(sig)) { if (!isWindows) err.signal.should.equal(sig) } else if (sig) { if (!isWindows) assert(err.signal) } } else { assert.ifError(err) } try { var data = JSON.parse(stdout) } catch (er) { console.error('invalid json: %j', stdout, stderr) throw er } if (weirdSignal(sig)) { data.wanted[1] = true data.found[1] = !!data.found[1] } assert.deepEqual(data.found, data.wanted) done() }) }) }) signals.forEach(function (sig) { var js = require.resolve('./fixtures/parent.js') it('exits properly: (external sig) ' + sig, function (done) { // issues with SIGUSR1 on Node 0.10.x if (process.version.match(/^v0\.10\./) && sig === 'SIGUSR1') return done() var cmd = node + ' ' + js + ' ' + sig exec(cmd, shell, function (err, stdout, stderr) { assert.ifError(err) try { var data = JSON.parse(stdout) } catch (er) { console.error('invalid json: %j', stdout, stderr) throw er } if (weirdSignal(sig)) { data.wanted[1] = true data.found[1] = !!data.found[1] data.external[1] = !!data.external[1] } assert.deepEqual(data.found, data.wanted) assert.deepEqual(data.external, data.wanted) done() }) }) }) }) signal-exit-3.0.2/test/fixtures/000077500000000000000000000000001302070562300165665ustar00rootroot00000000000000signal-exit-3.0.2/test/fixtures/awaiter.js000066400000000000000000000012611302070562300205600ustar00rootroot00000000000000var expectSignal = process.argv[2] if (!expectSignal || !isNaN(expectSignal)) { throw new Error('signal not provided') } var onSignalExit = require('../../') onSignalExit(function (code, signal) { // some signals don't always get recognized properly, because // they have the same numeric code. if (wanted[1] === true) { signal = !!signal } console.log('%j', { found: [ code, signal ], wanted: wanted }) }) var wanted switch (expectSignal) { case 'SIGIOT': case 'SIGUNUSED': case 'SIGPOLL': wanted = [ null, true ] break default: wanted = [ null, expectSignal ] break } console.error('want', wanted) setTimeout(function () {}, 1000) signal-exit-3.0.2/test/fixtures/change-code-expect.json000066400000000000000000000362211302070562300231100ustar00rootroot00000000000000{ "explicit 0 nochange sigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 0, "actualSignal": null, "stderr": [ "first code=0", "second code=0" ] }, "explicit 0 nochange nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 0, "actualSignal": null, "stderr": [ "first code=0", "second code=0" ] }, "explicit 0 change sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "explicit 0 change nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "explicit 0 code sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "second code=0" ] }, "explicit 0 code nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "second code=0" ] }, "explicit 0 twice sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "explicit 0 twice nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "explicit 0 twicecode sigexit": { "code": 6, "signal": null, "exitCode": 6, "actualCode": 6, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "set code from 5 to 6" ] }, "explicit 0 twicecode nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 6, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "set code from 5 to 6" ] }, "explicit 2 nochange sigexit": { "code": 2, "signal": null, "exitCode": 2, "actualCode": 2, "actualSignal": null, "stderr": [ "first code=2", "second code=2" ] }, "explicit 2 nochange nosigexit": { "code": 2, "signal": null, "exitCode": 2, "actualCode": 2, "actualSignal": null, "stderr": [ "first code=2", "second code=2" ] }, "explicit 2 change sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5" ] }, "explicit 2 change nosigexit": { "code": 2, "signal": null, "exitCode": 2, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5" ] }, "explicit 2 code sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5", "second code=2" ] }, "explicit 2 code nosigexit": { "code": 2, "signal": null, "exitCode": 2, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5", "second code=2" ] }, "explicit 2 twice sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5" ] }, "explicit 2 twice nosigexit": { "code": 2, "signal": null, "exitCode": 2, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5" ] }, "explicit 2 twicecode sigexit": { "code": 6, "signal": null, "exitCode": 6, "actualCode": 6, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5", "set code from 5 to 6" ] }, "explicit 2 twicecode nosigexit": { "code": 2, "signal": null, "exitCode": 2, "actualCode": 6, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5", "set code from 5 to 6" ] }, "explicit null nochange sigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 0, "actualSignal": null, "stderr": [ "first code=0", "second code=0" ] }, "explicit null nochange nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 0, "actualSignal": null, "stderr": [ "first code=0", "second code=0" ] }, "explicit null change sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "explicit null change nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "explicit null code sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "second code=0" ] }, "explicit null code nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "second code=0" ] }, "explicit null twice sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "explicit null twice nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "explicit null twicecode sigexit": { "code": 6, "signal": null, "exitCode": 6, "actualCode": 6, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "set code from 5 to 6" ] }, "explicit null twicecode nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 6, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "set code from 5 to 6" ] }, "code 0 nochange sigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 0, "actualSignal": null, "stderr": [ "first code=0", "second code=0" ] }, "code 0 nochange nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 0, "actualSignal": null, "stderr": [ "first code=0", "second code=0" ] }, "code 0 change sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "code 0 change nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "code 0 code sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "second code=0" ] }, "code 0 code nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "second code=0" ] }, "code 0 twice sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "code 0 twice nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "code 0 twicecode sigexit": { "code": 6, "signal": null, "exitCode": 6, "actualCode": 6, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "set code from 5 to 6" ] }, "code 0 twicecode nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 6, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "set code from 5 to 6" ] }, "code 2 nochange sigexit": { "code": 2, "signal": null, "exitCode": 2, "actualCode": 2, "actualSignal": null, "stderr": [ "first code=2", "second code=2" ] }, "code 2 nochange nosigexit": { "code": 2, "signal": null, "exitCode": 2, "actualCode": 2, "actualSignal": null, "stderr": [ "first code=2", "second code=2" ] }, "code 2 change sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5" ] }, "code 2 change nosigexit": { "code": 2, "signal": null, "exitCode": 2, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5" ] }, "code 2 code sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5", "second code=2" ] }, "code 2 code nosigexit": { "code": 2, "signal": null, "exitCode": 2, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5", "second code=2" ] }, "code 2 twice sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5" ] }, "code 2 twice nosigexit": { "code": 2, "signal": null, "exitCode": 2, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5" ] }, "code 2 twicecode sigexit": { "code": 6, "signal": null, "exitCode": 6, "actualCode": 6, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5", "set code from 5 to 6" ] }, "code 2 twicecode nosigexit": { "code": 2, "signal": null, "exitCode": 2, "actualCode": 6, "actualSignal": null, "stderr": [ "first code=2", "set code from 2 to 5", "set code from 5 to 6" ] }, "code null nochange sigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 0, "actualSignal": null, "stderr": [ "first code=0", "second code=0" ] }, "code null nochange nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 0, "actualSignal": null, "stderr": [ "first code=0", "second code=0" ] }, "code null change sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "code null change nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "code null code sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "second code=0" ] }, "code null code nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "second code=0" ] }, "code null twice sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "code null twice nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "code null twicecode sigexit": { "code": 6, "signal": null, "exitCode": 6, "actualCode": 6, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "set code from 5 to 6" ] }, "code null twicecode nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 6, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "set code from 5 to 6" ] }, "normal 0 nochange sigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 0, "actualSignal": null, "stderr": [ "first code=0", "second code=0" ] }, "normal 0 nochange nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 0, "actualSignal": null, "stderr": [ "first code=0", "second code=0" ] }, "normal 0 change sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "normal 0 change nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "normal 0 code sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "second code=0" ] }, "normal 0 code nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "second code=0" ] }, "normal 0 twice sigexit": { "code": 5, "signal": null, "exitCode": 5, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "normal 0 twice nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 5, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5" ] }, "normal 0 twicecode sigexit": { "code": 6, "signal": null, "exitCode": 6, "actualCode": 6, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "set code from 5 to 6" ] }, "normal 0 twicecode nosigexit": { "code": 0, "signal": null, "exitCode": 0, "actualCode": 6, "actualSignal": null, "stderr": [ "first code=0", "set code from 0 to 5", "set code from 5 to 6" ] } } signal-exit-3.0.2/test/fixtures/change-code.js000066400000000000000000000050371302070562300212660ustar00rootroot00000000000000var join = require('path').join if (process.argv.length === 2) { var types = [ 'explicit', 'code', 'normal' ] var codes = [ 0, 2, 'null' ] var changes = [ 'nochange', 'change', 'code', 'twice', 'twicecode' ] var handlers = [ 'sigexit', 'nosigexit' ] var opts = [] types.forEach(function (type) { var testCodes = type === 'normal' ? [ 0 ] : codes testCodes.forEach(function (code) { changes.forEach(function (change) { handlers.forEach(function (handler) { opts.push([type, code, change, handler].join(' ')) }) }) }) }) var results = {} var exec = require('child_process').exec run(opts.shift()) } else { var type = process.argv[2] var code = +process.argv[3] var change = process.argv[4] var sigexit = process.argv[5] !== 'nosigexit' if (sigexit) { var onSignalExit = require('../../') onSignalExit(listener) } else { process.on('exit', listener) } process.on('exit', function (code) { console.error('first code=%j', code) }) if (change !== 'nochange') { process.once('exit', function (code) { console.error('set code from %j to %j', code, 5) if (change === 'code' || change === 'twicecode') { process.exitCode = 5 } else { process.exit(5) } }) if (change === 'twicecode' || change === 'twice') { process.once('exit', function (code) { code = process.exitCode || code console.error('set code from %j to %j', code, code + 1) process.exit(code + 1) }) } } process.on('exit', function (code) { console.error('second code=%j', code) }) if (type === 'explicit') { if (code || code === 0) { process.exit(code) } else { process.exit() } } else if (type === 'code') { process.exitCode = +code || 0 } } function listener (code, signal) { signal = signal || null console.log('%j', { code: code, signal: signal, exitCode: process.exitCode || 0 }) } function run (opt) { console.error(opt) var shell = process.platform === 'win32' ? null : { shell: '/bin/bash' } exec(join(process.execPath, ' ', __filename, ' ' + opt), shell, function (err, stdout, stderr) { var res = JSON.parse(stdout) if (err) { res.actualCode = err.code res.actualSignal = err.signal } else { res.actualCode = 0 res.actualSignal = null } res.stderr = stderr.trim().split('\n') results[opt] = res if (opts.length) { run(opts.shift()) } else { console.log(JSON.stringify(results, null, 2)) } }) } signal-exit-3.0.2/test/fixtures/end-of-execution.js000066400000000000000000000002231302070562300222720ustar00rootroot00000000000000var onSignalExit = require('../../') onSignalExit(function (code, signal) { console.log('reached end of execution, ' + code + ', ' + signal) }) signal-exit-3.0.2/test/fixtures/exit-last.js000066400000000000000000000005541302070562300210420ustar00rootroot00000000000000var onSignalExit = require('../../') var counter = 0 onSignalExit(function (code, signal) { counter++ console.log('last counter=%j, code=%j, signal=%j', counter, code, signal) }, {alwaysLast: true}) onSignalExit(function (code, signal) { counter++ console.log('first counter=%j, code=%j, signal=%j', counter, code, signal) }) signal-exit-3.0.2/test/fixtures/exit.js000066400000000000000000000002471302070562300201000ustar00rootroot00000000000000var onSignalExit = require('../../') onSignalExit(function (code, signal) { console.log('exited with process.exit(), ' + code + ', ' + signal) }) process.exit(32) signal-exit-3.0.2/test/fixtures/exiter.js000066400000000000000000000015721302070562300204310ustar00rootroot00000000000000var exit = process.argv[2] || 0 var onSignalExit = require('../../') onSignalExit(function (code, signal) { // some signals don't always get recognized properly, because // they have the same numeric code. if (wanted[1] === true) { signal = !!signal } console.log('%j', { found: [ code, signal ], wanted: wanted }) }) var wanted if (isNaN(exit)) { switch (exit) { case 'SIGIOT': case 'SIGUNUSED': case 'SIGPOLL': wanted = [ null, true ] break default: wanted = [ null, exit ] break } try { process.kill(process.pid, exit) setTimeout(function () {}, 1000) } catch (er) { wanted = [ 0, null ] } } else { exit = +exit wanted = [ exit, null ] // If it's explicitly requested 0, then explicitly call it. // "no arg" = "exit naturally" if (exit || process.argv[2]) { process.exit(exit) } } signal-exit-3.0.2/test/fixtures/load-unload.js000066400000000000000000000003441302070562300213240ustar00rootroot00000000000000// just be silly with calling these functions a bunch // mostly just to get coverage of the guard branches var onSignalExit = require('../../') onSignalExit.load() onSignalExit.load() onSignalExit.unload() onSignalExit.unload() signal-exit-3.0.2/test/fixtures/multiple-load.js000066400000000000000000000025641302070562300217030ustar00rootroot00000000000000// simulate cases where the module could be loaded from multiple places var onSignalExit = require('../../') var counter = 0 onSignalExit(function (code, signal) { counter++ console.log('last counter=%j, code=%j, signal=%j', counter, code, signal) }, {alwaysLast: true}) onSignalExit(function (code, signal) { counter++ console.log('first counter=%j, code=%j, signal=%j', counter, code, signal) }) delete require('module')._cache[require.resolve('../../')] onSignalExit = require('../../') onSignalExit(function (code, signal) { counter++ console.log('last counter=%j, code=%j, signal=%j', counter, code, signal) }, {alwaysLast: true}) onSignalExit(function (code, signal) { counter++ console.log('first counter=%j, code=%j, signal=%j', counter, code, signal) }) // Lastly, some that should NOT be shown delete require('module')._cache[require.resolve('../../')] onSignalExit = require('../../') var unwrap = onSignalExit(function (code, signal) { counter++ console.log('last counter=%j, code=%j, signal=%j', counter, code, signal) }, {alwaysLast: true}) unwrap() unwrap = onSignalExit(function (code, signal) { counter++ console.log('first counter=%j, code=%j, signal=%j', counter, code, signal) }) unwrap() process.kill(process.pid, 'SIGHUP') setTimeout(function () {}, 1000) signal-exit-3.0.2/test/fixtures/parent.js000066400000000000000000000020261302070562300204150ustar00rootroot00000000000000var signal = process.argv[2] var gens = +process.argv[3] || 0 if (!signal || !isNaN(signal)) { throw new Error('signal not provided') } var spawn = require('child_process').spawn var file = require.resolve('./awaiter.js') console.error(process.pid, signal, gens) if (gens > 0) { file = __filename } var child = spawn(process.execPath, [file, signal, gens - 1], { stdio: [ 0, 'pipe', 'pipe' ] }) if (!gens) { child.stderr.on('data', function () { child.kill(signal) }) } var result = '' child.stdout.on('data', function (c) { result += c }) child.on('close', function (code, sig) { try { result = JSON.parse(result) } catch (er) { console.log('%j', { error: 'failed to parse json\n' + er.message, result: result, pid: process.pid, child: child.pid, gens: gens, expect: [ null, signal ], actual: [ code, sig ] }) return } if (result.wanted[1] === true) { sig = !!sig } result.external = result.external || [ code, sig ] console.log('%j', result) }) signal-exit-3.0.2/test/fixtures/sigint.js000066400000000000000000000005261302070562300204240ustar00rootroot00000000000000var onSignalExit = require('../../') onSignalExit(function (code, signal) { console.log('exited with sigint, ' + code + ', ' + signal) }) // For some reason, signals appear to not always be fast enough // to come in before the process exits. Just a few ticks needed. setTimeout(function () {}, 1000) process.kill(process.pid, 'SIGINT') signal-exit-3.0.2/test/fixtures/sigkill.js000066400000000000000000000010511302070562300205570ustar00rootroot00000000000000// SIGKILL can't be caught, and in fact, even trying to add the // listener will throw an error. // We handle that nicely. // // This is just here to get another few more lines of test // coverage. That's also why it lies about being on a linux // platform so that we pull in those other event types. Object.defineProperty(process, 'platform', { value: 'linux', writable: false, enumerable: true, configurable: true }) var signals = require('../../signals.js') signals.push('SIGKILL') var onSignalExit = require('../../') onSignalExit.load() signal-exit-3.0.2/test/fixtures/signal-default.js000066400000000000000000000041431302070562300220250ustar00rootroot00000000000000// This fixture is not used in any tests. It is here merely as a way to // do research into the various signal behaviors on Linux and Darwin. // Run with no args to cycle through every signal type. Run with a signal // arg to learn about how that signal behaves. if (process.argv[2]) { child(process.argv[2]) } else { var signals = [ 'SIGABRT', 'SIGALRM', 'SIGBUS', 'SIGCHLD', 'SIGCLD', 'SIGCONT', 'SIGEMT', 'SIGFPE', 'SIGHUP', 'SIGILL', 'SIGINFO', 'SIGINT', 'SIGIO', 'SIGIOT', 'SIGKILL', 'SIGLOST', 'SIGPIPE', 'SIGPOLL', // 'SIGPROF', see #21 'SIGPWR', 'SIGQUIT', 'SIGSEGV', 'SIGSTKFLT', 'SIGSTOP', 'SIGSYS', 'SIGTERM', 'SIGTRAP', 'SIGTSTP', 'SIGTTIN', 'SIGTTOU', 'SIGUNUSED', 'SIGURG', 'SIGUSR1', 'SIGUSR2', 'SIGVTALRM', 'SIGWINCH', 'SIGXCPU', 'SIGXFSZ' ] var spawn = require('child_process').spawn ;(function test (signal) { if (!signal) { return } var child = spawn(process.execPath, [__filename, signal], { stdio: 'inherit' }) var timer = setTimeout(function () { console.log('requires SIGCONT') process.kill(child.pid, 'SIGCONT') }, 750) child.on('close', function (code, signal) { console.log('code=%j signal=%j\n', code, signal) clearTimeout(timer) test(signals.pop()) }) })(signals.pop()) } function child (signal) { console.log('signal=%s', signal) // set a timeout so we know whether or not the process terminated. setTimeout(function () { console.log('not terminated') }, 200) process.on('exit', function (code) { console.log('emit exit code=%j', code) }) try { process.on(signal, function fn () { console.log('signal is catchable', signal) process.removeListener(signal, fn) setTimeout(function () { console.error('signal again') process.kill(process.pid, signal) }) }) } catch (er) { console.log('not listenable') } try { process.kill(process.pid, signal) } catch (er) { console.log('not issuable') } } signal-exit-3.0.2/test/fixtures/signal-last.js000066400000000000000000000006621302070562300213460ustar00rootroot00000000000000var onSignalExit = require('../../') var counter = 0 onSignalExit(function (code, signal) { counter++ console.log('last counter=%j, code=%j, signal=%j', counter, code, signal) }, {alwaysLast: true}) onSignalExit(function (code, signal) { counter++ console.log('first counter=%j, code=%j, signal=%j', counter, code, signal) }) process.kill(process.pid, 'SIGHUP') setTimeout(function () {}, 1000) signal-exit-3.0.2/test/fixtures/signal-listener.js000066400000000000000000000007661302070562300222350ustar00rootroot00000000000000var onSignalExit = require('../../') setTimeout(function () {}) var calledListener = 0 onSignalExit(function (code, signal) { console.log('exited calledListener=%j, code=%j, signal=%j', calledListener, code, signal) }) process.on('SIGHUP', listener) process.kill(process.pid, 'SIGHUP') function listener () { calledListener++ if (calledListener > 3) { process.removeListener('SIGHUP', listener) } setTimeout(function () { process.kill(process.pid, 'SIGHUP') }) } signal-exit-3.0.2/test/fixtures/sigpipe.js000066400000000000000000000003331302070562300205630ustar00rootroot00000000000000var onSignalExit = require('../..') onSignalExit(function (code, signal) { console.error('onSignalExit(%j,%j)', code, signal) }) setTimeout(function () { console.log('hello') }) process.kill(process.pid, 'SIGPIPE') signal-exit-3.0.2/test/fixtures/sigterm.js000066400000000000000000000003261302070562300205770ustar00rootroot00000000000000var onSignalExit = require('../../') onSignalExit(function (code, signal) { console.log('exited with sigterm, ' + code + ', ' + signal) }) setTimeout(function () {}, 1000) process.kill(process.pid, 'SIGTERM') signal-exit-3.0.2/test/fixtures/unwrap.js000066400000000000000000000020521302070562300204370ustar00rootroot00000000000000// simulate cases where the module could be loaded from multiple places // Need to lie about this a little bit, since nyc uses this module // for its coverage wrap-up handling if (process.env.NYC_CWD) { var emitter = process.__signal_exit_emitter__ var listeners = emitter.listeners('afterexit') process.removeAllListeners('SIGHUP') delete process.__signal_exit_emitter__ delete require('module')._cache[require.resolve('../../')] } var onSignalExit = require('../../') var counter = 0 var unwrap = onSignalExit(function (code, signal) { counter++ console.log('last counter=%j, code=%j, signal=%j', counter, code, signal) }, {alwaysLast: true}) unwrap() unwrap = onSignalExit(function (code, signal) { counter++ console.log('first counter=%j, code=%j, signal=%j', counter, code, signal) }) unwrap() if (global.__coverage__ && listeners && listeners.length) { listeners.forEach(function (fn) { onSignalExit(fn, { alwaysLast: true }) }) } process.kill(process.pid, 'SIGHUP') setTimeout(function () {}, 1000) signal-exit-3.0.2/test/many-handlers.js000066400000000000000000000013521302070562300200160ustar00rootroot00000000000000var onexit = require('../') var spawn = require('child_process').spawn var t = require('tap') var node = process.execPath var f = __filename if (process.argv[2] === 'child') { for (var i = 0; i < 15; i++) { onexit(function () { console.log('ok') }) } } else { t.test('parent', function (t) { var child = spawn(node, [f, 'child']) var err = '' var out = '' var expectOut = new Array(16).join('ok\n') child.stderr.on('data', function (c) { err += c }) child.stdout.on('data', function (c) { out += c }) child.on('close', function (code, signal) { t.equal(code, 0) t.equal(signal, null) t.equal(err, '') t.equal(out, expectOut) t.end() }) }) } signal-exit-3.0.2/test/multi-exit.js000066400000000000000000000036311302070562300173570ustar00rootroot00000000000000var exec = require('child_process').exec var t = require('tap') var isWindows = process.platform === 'win32' var shell = isWindows ? null : { shell: '/bin/bash' } var node = isWindows ? '"' + process.execPath + '"' : process.execPath var fixture = require.resolve('./fixtures/change-code.js') var expect = require('./fixtures/change-code-expect.json') // process.exitCode has problems prior to: // https://github.com/joyent/node/commit/c0d81f90996667a658aa4403123e02161262506a function isZero10 () { return /^v0\.10\..+$/.test(process.version) } // process.exit(code), process.exitCode = code, normal exit var types = [ 'explicit', 'normal' ] if (!isZero10()) types.push('code') // initial code that is set. Note, for 'normal' exit, there's no // point doing these, because we just exit without modifying code var codes = [ 0, 2, 'null' ] // do not change, change to 5 with exit(), change to 5 with exitCode, // change to 5 and then to 2 with exit(), change twice with exitcode var changes = [ 'nochange', 'change', 'twice' ] if (!isZero10()) changes.push('code', 'twicecode') // use signal-exit, use process.on('exit') var handlers = [ 'sigexit', 'nosigexit' ] var opts = [] types.forEach(function (type) { var testCodes = type === 'normal' ? [0] : codes testCodes.forEach(function (code) { changes.forEach(function (change) { handlers.forEach(function (handler) { opts.push([type, code, change, handler].join(' ')) }) }) }) }) opts.forEach(function (opt) { t.test(opt, function (t) { var cmd = node + ' ' + fixture + ' ' + opt exec(cmd, shell, function (err, stdout, stderr) { var res = JSON.parse(stdout) if (err) { res.actualCode = err.code res.actualSignal = err.signal } else { res.actualCode = 0 res.actualSignal = null } res.stderr = stderr.trim().split('\n') t.same(res, expect[opt]) t.end() }) }) }) signal-exit-3.0.2/test/signal-exit-test.js000066400000000000000000000076111302070562300204610ustar00rootroot00000000000000/* global describe, it */ var exec = require('child_process').exec var expect = require('chai').expect var assert = require('assert') var isWindows = process.platform === 'win32' var shell = isWindows ? null : { shell: '/bin/bash' } var node = isWindows ? '"' + process.execPath + '"' : process.execPath require('chai').should() require('tap').mochaGlobals() describe('signal-exit', function () { it('receives an exit event when a process exits normally', function (done) { exec(node + ' ./test/fixtures/end-of-execution.js', shell, function (err, stdout, stderr) { expect(err).to.equal(null) stdout.should.match(/reached end of execution, 0, null/) done() }) }) it('receives an exit event when process.exit() is called', function (done) { exec(node + ' ./test/fixtures/exit.js', shell, function (err, stdout, stderr) { if (!isWindows) err.code.should.equal(32) stdout.should.match(/exited with process\.exit\(\), 32, null/) done() }) }) it('ensures that if alwaysLast=true, the handler is run last (signal)', function (done) { exec(node + ' ./test/fixtures/signal-last.js', shell, function (err, stdout, stderr) { assert(err) stdout.should.match(/first counter=1/) stdout.should.match(/last counter=2/) done() }) }) it('ensures that if alwaysLast=true, the handler is run last (normal exit)', function (done) { exec(node + ' ./test/fixtures/exit-last.js', shell, function (err, stdout, stderr) { assert.ifError(err) stdout.should.match(/first counter=1/) stdout.should.match(/last counter=2/) done() }) }) it('works when loaded multiple times', function (done) { exec(node + ' ./test/fixtures/multiple-load.js', shell, function (err, stdout, stderr) { assert(err) stdout.should.match(/first counter=1/) stdout.should.match(/first counter=2/) stdout.should.match(/last counter=3/) stdout.should.match(/last counter=4/) done() }) }) it('removes handlers when fully unwrapped', function (done) { exec(node + ' ./test/fixtures/unwrap.js', shell, function (err, stdout, stderr) { assert(err) if (!isWindows) err.signal.should.equal('SIGHUP') if (!isWindows) expect(err.code).to.equal(null) done() }) }) it('does not load() or unload() more than once', function (done) { exec(node + ' ./test/fixtures/load-unload.js', shell, function (err, stdout, stderr) { assert.ifError(err) done() }) }) if (!isWindows) { it('receives an exit event when a process is terminated with sigint', function (done) { exec(node + ' ./test/fixtures/sigint.js', shell, function (err, stdout, stderr) { assert(err) stdout.should.match(/exited with sigint, null, SIGINT/) done() }) }) it('receives an exit event when a process is terminated with sigterm', function (done) { exec(node + ' ./test/fixtures/sigterm.js', shell, function (err, stdout, stderr) { assert(err) stdout.should.match(/exited with sigterm, null, SIGTERM/) done() }) }) it('does not exit on sigpipe', function (done) { exec(node + ' ./test/fixtures/sigpipe.js', shell, function (err, stdout, stderr) { assert.ifError(err) stdout.should.match(/hello/) stderr.should.match(/onSignalExit\(0,null\)/) done() }) }) it('handles uncatchable signals with grace and poise', function (done) { exec(node + ' ./test/fixtures/sigkill.js', shell, function (err, stdout, stderr) { assert.ifError(err) done() }) }) it('does not exit if user handles signal', function (done) { exec(node + ' ./test/fixtures/signal-listener.js', shell, function (err, stdout, stderr) { assert(err) assert.equal(stdout, 'exited calledListener=4, code=null, signal="SIGHUP"\n') done() }) }) } })