1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22'use strict'; 23// test-cluster-worker-exit.js 24// verifies that, when a child process exits (by calling `process.exit(code)`) 25// - the parent receives the proper events in the proper order, no duplicates 26// - the exitCode and signalCode are correct in the 'exit' event 27// - the worker.exitedAfterDisconnect flag, and worker.state are correct 28// - the worker process actually goes away 29 30const common = require('../common'); 31const assert = require('assert'); 32const cluster = require('cluster'); 33 34const EXIT_CODE = 42; 35 36if (cluster.isWorker) { 37 const http = require('http'); 38 const server = http.Server(() => { }); 39 40 server.once('listening', common.mustCall(() => { 41 process.exit(EXIT_CODE); 42 })); 43 server.listen(0, '127.0.0.1'); 44 45} else if (cluster.isMaster) { 46 47 const expected_results = { 48 cluster_emitDisconnect: [1, "the cluster did not emit 'disconnect'"], 49 cluster_emitExit: [1, "the cluster did not emit 'exit'"], 50 cluster_exitCode: [EXIT_CODE, 'the cluster exited w/ incorrect exitCode'], 51 cluster_signalCode: [null, 'the cluster exited w/ incorrect signalCode'], 52 worker_emitDisconnect: [1, "the worker did not emit 'disconnect'"], 53 worker_emitExit: [1, "the worker did not emit 'exit'"], 54 worker_state: ['disconnected', 'the worker state is incorrect'], 55 worker_exitedAfterDisconnect: [ 56 false, 'the .exitedAfterDisconnect flag is incorrect', 57 ], 58 worker_died: [true, 'the worker is still running'], 59 worker_exitCode: [EXIT_CODE, 'the worker exited w/ incorrect exitCode'], 60 worker_signalCode: [null, 'the worker exited w/ incorrect signalCode'] 61 }; 62 const results = { 63 cluster_emitDisconnect: 0, 64 cluster_emitExit: 0, 65 worker_emitDisconnect: 0, 66 worker_emitExit: 0 67 }; 68 69 70 // start worker 71 const worker = cluster.fork(); 72 73 // Check cluster events 74 cluster.on('disconnect', common.mustCall(() => { 75 results.cluster_emitDisconnect += 1; 76 })); 77 cluster.on('exit', common.mustCall((worker) => { 78 results.cluster_exitCode = worker.process.exitCode; 79 results.cluster_signalCode = worker.process.signalCode; 80 results.cluster_emitExit += 1; 81 })); 82 83 // Check worker events and properties 84 worker.on('disconnect', common.mustCall(() => { 85 results.worker_emitDisconnect += 1; 86 results.worker_exitedAfterDisconnect = worker.exitedAfterDisconnect; 87 results.worker_state = worker.state; 88 if (results.worker_emitExit > 0) { 89 process.nextTick(() => finish_test()); 90 } 91 })); 92 93 // Check that the worker died 94 worker.once('exit', common.mustCall((exitCode, signalCode) => { 95 results.worker_exitCode = exitCode; 96 results.worker_signalCode = signalCode; 97 results.worker_emitExit += 1; 98 results.worker_died = !common.isAlive(worker.process.pid); 99 if (results.worker_emitDisconnect > 0) { 100 process.nextTick(() => finish_test()); 101 } 102 })); 103 104 const finish_test = () => { 105 try { 106 checkResults(expected_results, results); 107 } catch (exc) { 108 if (exc.name !== 'AssertionError') { 109 console.trace(exc); 110 } 111 112 process.exit(1); 113 return; 114 } 115 process.exit(0); 116 }; 117} 118 119// Some helper functions ... 120 121function checkResults(expected_results, results) { 122 for (const k in expected_results) { 123 const actual = results[k]; 124 const expected = expected_results[k]; 125 126 assert.strictEqual( 127 actual, expected && expected.length ? expected[0] : expected, 128 `${expected[1] || ''} [expected: ${expected[0]} / actual: ${actual}]`); 129 } 130} 131