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'; 23const common = require('../common'); 24 25const assert = require('assert'); 26const cluster = require('cluster'); 27 28assert.strictEqual('NODE_UNIQUE_ID' in process.env, false, 29 `NODE_UNIQUE_ID (${process.env.NODE_UNIQUE_ID}) ` + 30 'should be removed on startup'); 31 32function forEach(obj, fn) { 33 Object.keys(obj).forEach((name, index) => { 34 fn(obj[name], name, index); 35 }); 36} 37 38 39if (cluster.isWorker) { 40 require('http').Server(common.mustNotCall()).listen(0, '127.0.0.1'); 41} else if (cluster.isMaster) { 42 43 const checks = { 44 cluster: { 45 events: { 46 fork: false, 47 online: false, 48 listening: false, 49 exit: false 50 }, 51 equal: { 52 fork: false, 53 online: false, 54 listening: false, 55 exit: false 56 } 57 }, 58 59 worker: { 60 events: { 61 online: false, 62 listening: false, 63 exit: false 64 }, 65 equal: { 66 online: false, 67 listening: false, 68 exit: false 69 }, 70 states: { 71 none: false, 72 online: false, 73 listening: false, 74 dead: false 75 } 76 } 77 }; 78 79 const stateNames = Object.keys(checks.worker.states); 80 81 // Check events, states, and emit arguments 82 forEach(checks.cluster.events, (bool, name, index) => { 83 84 // Listen on event 85 cluster.on(name, common.mustCall(function(/* worker */) { 86 87 // Set event 88 checks.cluster.events[name] = true; 89 90 // Check argument 91 checks.cluster.equal[name] = worker === arguments[0]; 92 93 // Check state 94 const state = stateNames[index]; 95 checks.worker.states[state] = (state === worker.state); 96 })); 97 }); 98 99 // Kill worker when listening 100 cluster.on('listening', common.mustCall(() => { 101 worker.kill(); 102 })); 103 104 // Kill process when worker is killed 105 cluster.on('exit', common.mustCall()); 106 107 // Create worker 108 const worker = cluster.fork(); 109 assert.strictEqual(worker.id, 1); 110 assert(worker instanceof cluster.Worker, 111 'the worker is not a instance of the Worker constructor'); 112 113 // Check event 114 forEach(checks.worker.events, function(bool, name, index) { 115 worker.on(name, common.mustCall(function() { 116 // Set event 117 checks.worker.events[name] = true; 118 119 // Check argument 120 checks.worker.equal[name] = (worker === this); 121 122 switch (name) { 123 case 'exit': 124 assert.strictEqual(arguments[0], worker.process.exitCode); 125 assert.strictEqual(arguments[1], worker.process.signalCode); 126 assert.strictEqual(arguments.length, 2); 127 break; 128 129 case 'listening': 130 assert.strictEqual(arguments.length, 1); 131 assert.strictEqual(Object.keys(arguments[0]).length, 4); 132 assert.strictEqual(arguments[0].address, '127.0.0.1'); 133 assert.strictEqual(arguments[0].addressType, 4); 134 assert(arguments[0].hasOwnProperty('fd')); 135 assert.strictEqual(arguments[0].fd, undefined); 136 const port = arguments[0].port; 137 assert(Number.isInteger(port)); 138 assert(port >= 1); 139 assert(port <= 65535); 140 break; 141 142 default: 143 assert.strictEqual(arguments.length, 0); 144 break; 145 } 146 })); 147 }); 148 149 // Check all values 150 process.once('exit', () => { 151 // Check cluster events 152 forEach(checks.cluster.events, (check, name) => { 153 assert(check, 154 `The cluster event "${name}" on the cluster object did not fire`); 155 }); 156 157 // Check cluster event arguments 158 forEach(checks.cluster.equal, (check, name) => { 159 assert(check, 160 `The cluster event "${name}" did not emit with correct argument`); 161 }); 162 163 // Check worker states 164 forEach(checks.worker.states, (check, name) => { 165 assert(check, 166 `The worker state "${name}" was not set to true`); 167 }); 168 169 // Check worker events 170 forEach(checks.worker.events, (check, name) => { 171 assert(check, 172 `The worker event "${name}" on the worker object did not fire`); 173 }); 174 175 // Check worker event arguments 176 forEach(checks.worker.equal, (check, name) => { 177 assert(check, 178 `The worker event "${name}" did not emit with correct argument`); 179 }); 180 }); 181 182} 183