Browse Source

test: refactor/cleanup a number of cluster tests

* Move shared code into common
* Favor use of strictEqual
* Add some missing common.mustCalls
* Other general cleanup

PR-URL: https://github.com/nodejs/node/pull/8261
Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
v6.x
James M Snell 8 years ago
committed by Jeremiah Senkpiel
parent
commit
1aa7168e91
  1. 9
      test/common.js
  2. 81
      test/parallel/test-cluster-basic.js
  3. 16
      test/parallel/test-cluster-bind-privileged-port.js
  4. 74
      test/parallel/test-cluster-bind-twice.js
  5. 39
      test/parallel/test-cluster-dgram-1.js
  6. 22
      test/parallel/test-cluster-dgram-2.js
  7. 8
      test/parallel/test-cluster-dgram-reuse.js
  8. 8
      test/parallel/test-cluster-disconnect-before-exit.js
  9. 52
      test/parallel/test-cluster-disconnect.js
  10. 68
      test/parallel/test-cluster-master-error.js
  11. 50
      test/parallel/test-cluster-master-kill.js
  12. 62
      test/parallel/test-cluster-worker-disconnect.js
  13. 77
      test/parallel/test-cluster-worker-exit.js
  14. 62
      test/parallel/test-cluster-worker-kill.js

9
test/common.js

@ -498,3 +498,12 @@ exports.busyLoop = function busyLoop(time) {
var stopTime = startTime + time; var stopTime = startTime + time;
while (Timer.now() < stopTime) {} while (Timer.now() < stopTime) {}
}; };
exports.isAlive = function isAlive(pid) {
try {
process.kill(pid, 'SIGCONT');
return true;
} catch (e) {
return false;
}
};

81
test/parallel/test-cluster-basic.js

@ -1,26 +1,26 @@
'use strict'; 'use strict';
var common = require('../common'); const common = require('../common');
var assert = require('assert'); const assert = require('assert');
var cluster = require('cluster'); const cluster = require('cluster');
assert.equal('NODE_UNIQUE_ID' in process.env, false, assert.strictEqual('NODE_UNIQUE_ID' in process.env, false,
'NODE_UNIQUE_ID should be removed on startup'); 'NODE_UNIQUE_ID should be removed on startup');
function forEach(obj, fn) { function forEach(obj, fn) {
Object.keys(obj).forEach(function(name, index) { Object.keys(obj).forEach((name, index) => {
fn(obj[name], name, index); fn(obj[name], name, index);
}); });
} }
if (cluster.isWorker) { if (cluster.isWorker) {
var http = require('http'); const http = require('http');
http.Server(function() { http.Server(function() {
}).listen(common.PORT, '127.0.0.1'); }).listen(common.PORT, '127.0.0.1');
} else if (cluster.isMaster) { } else if (cluster.isMaster) {
var checks = { const checks = {
cluster: { cluster: {
events: { events: {
fork: false, fork: false,
@ -57,13 +57,13 @@ if (cluster.isWorker) {
}; };
var worker; var worker;
var stateNames = Object.keys(checks.worker.states); const stateNames = Object.keys(checks.worker.states);
//Check events, states, and emit arguments //Check events, states, and emit arguments
forEach(checks.cluster.events, function(bool, name, index) { forEach(checks.cluster.events, (bool, name, index) => {
//Listen on event //Listen on event
cluster.on(name, function(/* worker */) { cluster.on(name, common.mustCall(function(/* worker */) {
//Set event //Set event
checks.cluster.events[name] = true; checks.cluster.events[name] = true;
@ -74,28 +74,26 @@ if (cluster.isWorker) {
//Check state //Check state
var state = stateNames[index]; var state = stateNames[index];
checks.worker.states[state] = (state === worker.state); checks.worker.states[state] = (state === worker.state);
}); }));
}); });
//Kill worker when listening //Kill worker when listening
cluster.on('listening', function() { cluster.on('listening', common.mustCall(() => {
worker.kill(); worker.kill();
}); }));
//Kill process when worker is killed //Kill process when worker is killed
cluster.on('exit', function() { cluster.on('exit', common.mustCall(() => {}));
process.exit(0);
});
//Create worker //Create worker
worker = cluster.fork(); worker = cluster.fork();
assert.equal(worker.id, 1); assert.strictEqual(worker.id, 1);
assert.ok(worker instanceof cluster.Worker, assert(worker instanceof cluster.Worker,
'the worker is not a instance of the Worker constructor'); 'the worker is not a instance of the Worker constructor');
//Check event //Check event
forEach(checks.worker.events, function(bool, name, index) { forEach(checks.worker.events, function(bool, name, index) {
worker.on(name, function() { worker.on(name, common.mustCall(function() {
//Set event //Set event
checks.worker.events[name] = true; checks.worker.events[name] = true;
@ -104,14 +102,14 @@ if (cluster.isWorker) {
switch (name) { switch (name) {
case 'exit': case 'exit':
assert.equal(arguments[0], worker.process.exitCode); assert.strictEqual(arguments[0], worker.process.exitCode);
assert.equal(arguments[1], worker.process.signalCode); assert.strictEqual(arguments[1], worker.process.signalCode);
assert.equal(arguments.length, 2); assert.strictEqual(arguments.length, 2);
break; break;
case 'listening': case 'listening':
assert.equal(arguments.length, 1); assert.strictEqual(arguments.length, 1);
var expect = { address: '127.0.0.1', const expect = { address: '127.0.0.1',
port: common.PORT, port: common.PORT,
addressType: 4, addressType: 4,
fd: undefined }; fd: undefined };
@ -119,41 +117,42 @@ if (cluster.isWorker) {
break; break;
default: default:
assert.equal(arguments.length, 0); assert.strictEqual(arguments.length, 0);
break; break;
} }
}); }));
}); });
//Check all values //Check all values
process.once('exit', function() { process.once('exit', () => {
//Check cluster events //Check cluster events
forEach(checks.cluster.events, function(check, name) { forEach(checks.cluster.events, (check, name) => {
assert.ok(check, 'The cluster event "' + name + '" on the cluster ' + assert(check,
'object did not fire'); `The cluster event "${name}" on the cluster object did not fire`);
}); });
//Check cluster event arguments //Check cluster event arguments
forEach(checks.cluster.equal, function(check, name) { forEach(checks.cluster.equal, (check, name) => {
assert.ok(check, 'The cluster event "' + name + '" did not emit ' + assert(check,
'with correct argument'); `The cluster event "${name}" did not emit with correct argument`);
}); });
//Check worker states //Check worker states
forEach(checks.worker.states, function(check, name) { forEach(checks.worker.states, (check, name) => {
assert.ok(check, 'The worker state "' + name + '" was not set to true'); assert(check,
`The worker state "${name}" was not set to true`);
}); });
//Check worker events //Check worker events
forEach(checks.worker.events, function(check, name) { forEach(checks.worker.events, (check, name) => {
assert.ok(check, 'The worker event "' + name + '" on the worker object ' + assert(check,
'did not fire'); `The worker event "${name}" on the worker object did not fire`);
}); });
//Check worker event arguments //Check worker event arguments
forEach(checks.worker.equal, function(check, name) { forEach(checks.worker.equal, (check, name) => {
assert.ok(check, 'The worker event "' + name + '" did not emit with ' + assert(check,
'corrent argument'); `The worker event "${name}" did not emit with correct argument`);
}); });
}); });

16
test/parallel/test-cluster-bind-privileged-port.js

@ -1,8 +1,8 @@
'use strict'; 'use strict';
var common = require('../common'); const common = require('../common');
var assert = require('assert'); const assert = require('assert');
var cluster = require('cluster'); const cluster = require('cluster');
var net = require('net'); const net = require('net');
if (common.isWindows) { if (common.isWindows) {
common.skip('not reliable on Windows.'); common.skip('not reliable on Windows.');
@ -15,14 +15,14 @@ if (process.getuid() === 0) {
} }
if (cluster.isMaster) { if (cluster.isMaster) {
cluster.fork().on('exit', common.mustCall(function(exitCode) { cluster.fork().on('exit', common.mustCall((exitCode) => {
assert.equal(exitCode, 0); assert.strictEqual(exitCode, 0);
})); }));
} else { } else {
var s = net.createServer(common.fail); var s = net.createServer(common.fail);
s.listen(42, common.fail.bind(null, 'listen should have failed')); s.listen(42, common.fail.bind(null, 'listen should have failed'));
s.on('error', common.mustCall(function(err) { s.on('error', common.mustCall((err) => {
assert.equal(err.code, 'EACCES'); assert.strictEqual(err.code, 'EACCES');
process.disconnect(); process.disconnect();
})); }));
} }

74
test/parallel/test-cluster-bind-twice.js

@ -18,88 +18,74 @@
// //
// See https://github.com/joyent/node/issues/2721 for more details. // See https://github.com/joyent/node/issues/2721 for more details.
var common = require('../common'); const common = require('../common');
var assert = require('assert'); const assert = require('assert');
var cluster = require('cluster'); const cluster = require('cluster');
var fork = require('child_process').fork; const fork = require('child_process').fork;
var http = require('http'); const http = require('http');
var id = process.argv[2]; const id = process.argv[2];
if (!id) { if (!id) {
var a = fork(__filename, ['one']); const a = fork(__filename, ['one']);
var b = fork(__filename, ['two']); const b = fork(__filename, ['two']);
a.on('exit', function(c) { a.on('exit', common.mustCall((c) => {
if (c) { if (c) {
b.send('QUIT'); b.send('QUIT');
throw new Error('A exited with ' + c); throw new Error('A exited with ' + c);
} }
}); }));
b.on('exit', function(c) { b.on('exit', common.mustCall((c) => {
if (c) { if (c) {
a.send('QUIT'); a.send('QUIT');
throw new Error('B exited with ' + c); throw new Error('B exited with ' + c);
} }
}); }));
a.on('message', function(m) { a.on('message', common.mustCall((m) => {
if (typeof m === 'object') return; if (typeof m === 'object') return;
assert.equal(m, 'READY'); assert.strictEqual(m, 'READY');
b.send('START'); b.send('START');
}); }));
let ok = false; b.on('message', common.mustCall((m) => {
assert.strictEqual(m, 'EADDRINUSE');
b.on('message', function(m) {
if (typeof m === 'object') return; // ignore system messages
assert.equal(m, 'EADDRINUSE');
ok = true;
a.send('QUIT'); a.send('QUIT');
b.send('QUIT'); b.send('QUIT');
}); }));
process.on('exit', function() {
assert(ok);
});
} else if (id === 'one') { } else if (id === 'one') {
if (cluster.isMaster) return startWorker(); if (cluster.isMaster) return startWorker();
http.createServer(common.fail).listen(common.PORT, function() { http.createServer(common.fail).listen(common.PORT, common.mustCall(() => {
process.send('READY'); process.send('READY');
}); }));
process.on('message', function(m) { process.on('message', common.mustCall((m) => {
if (m === 'QUIT') process.exit(); if (m === 'QUIT') process.exit();
}); }));
} else if (id === 'two') { } else if (id === 'two') {
if (cluster.isMaster) return startWorker(); if (cluster.isMaster) return startWorker();
let ok = false; const server = http.createServer(common.fail);
process.on('exit', function() { process.on('message', common.mustCall((m) => {
assert(ok);
});
var server = http.createServer(common.fail);
process.on('message', function(m) {
if (typeof m === 'object') return; // ignore system messages
if (m === 'QUIT') process.exit(); if (m === 'QUIT') process.exit();
assert.equal(m, 'START'); assert.strictEqual(m, 'START');
server.listen(common.PORT, common.fail); server.listen(common.PORT, common.fail);
server.on('error', function(e) { server.on('error', common.mustCall((e) => {
assert.equal(e.code, 'EADDRINUSE'); assert.strictEqual(e.code, 'EADDRINUSE');
process.send(e.code); process.send(e.code);
ok = true; }));
}); }, 2));
});
} else { } else {
assert(0); // bad command line argument assert(0); // bad command line argument
} }
function startWorker() { function startWorker() {
var worker = cluster.fork(); const worker = cluster.fork();
worker.on('exit', process.exit); worker.on('exit', process.exit);
worker.on('message', process.send.bind(process)); worker.on('message', process.send.bind(process));
process.on('message', worker.send.bind(worker)); process.on('message', worker.send.bind(worker));

39
test/parallel/test-cluster-dgram-1.js

@ -1,11 +1,11 @@
'use strict'; 'use strict';
const common = require('../common'); const common = require('../common');
var NUM_WORKERS = 4; const NUM_WORKERS = 4;
var PACKETS_PER_WORKER = 10; const PACKETS_PER_WORKER = 10;
var assert = require('assert'); const assert = require('assert');
var cluster = require('cluster'); const cluster = require('cluster');
var dgram = require('dgram'); const dgram = require('dgram');
if (common.isWindows) { if (common.isWindows) {
@ -28,13 +28,13 @@ function master() {
cluster.fork(); cluster.fork();
// Wait until all workers are listening. // Wait until all workers are listening.
cluster.on('listening', function() { cluster.on('listening', common.mustCall(() => {
if (++listening < NUM_WORKERS) if (++listening < NUM_WORKERS)
return; return;
// Start sending messages. // Start sending messages.
var buf = Buffer.from('hello world'); const buf = Buffer.from('hello world');
var socket = dgram.createSocket('udp4'); const socket = dgram.createSocket('udp4');
var sent = 0; var sent = 0;
doSend(); doSend();
@ -47,15 +47,14 @@ function master() {
if (sent < NUM_WORKERS * PACKETS_PER_WORKER) { if (sent < NUM_WORKERS * PACKETS_PER_WORKER) {
doSend(); doSend();
} else { } else {
console.log('master sent %d packets', sent);
socket.close(); socket.close();
} }
} }
}); }, NUM_WORKERS));
// Set up event handlers for every worker. Each worker sends a message when // Set up event handlers for every worker. Each worker sends a message when
// it has received the expected number of packets. After that it disconnects. // it has received the expected number of packets. After that it disconnects.
for (var key in cluster.workers) { for (const key in cluster.workers) {
if (cluster.workers.hasOwnProperty(key)) if (cluster.workers.hasOwnProperty(key))
setupWorker(cluster.workers[key]); setupWorker(cluster.workers[key]);
} }
@ -63,15 +62,13 @@ function master() {
function setupWorker(worker) { function setupWorker(worker) {
var received = 0; var received = 0;
worker.on('message', function(msg) { worker.on('message', common.mustCall((msg) => {
received = msg.received; received = msg.received;
console.log('worker %d received %d packets', worker.id, received); }));
});
worker.on('disconnect', function() { worker.on('disconnect', common.mustCall(() => {
assert(received === PACKETS_PER_WORKER); assert.strictEqual(received, PACKETS_PER_WORKER);
console.log('worker %d disconnected', worker.id); }));
});
} }
} }
@ -82,15 +79,15 @@ function worker() {
// Create udp socket and start listening. // Create udp socket and start listening.
var socket = dgram.createSocket('udp4'); var socket = dgram.createSocket('udp4');
socket.on('message', function(data, info) { socket.on('message', common.mustCall((data, info) => {
received++; received++;
// Every 10 messages, notify the master. // Every 10 messages, notify the master.
if (received == PACKETS_PER_WORKER) { if (received === PACKETS_PER_WORKER) {
process.send({received: received}); process.send({received: received});
process.disconnect(); process.disconnect();
} }
}); }, PACKETS_PER_WORKER));
socket.bind(common.PORT); socket.bind(common.PORT);
} }

22
test/parallel/test-cluster-dgram-2.js

@ -1,10 +1,10 @@
'use strict'; 'use strict';
const common = require('../common'); const common = require('../common');
var NUM_WORKERS = 4; const NUM_WORKERS = 4;
var PACKETS_PER_WORKER = 10; const PACKETS_PER_WORKER = 10;
var cluster = require('cluster'); const cluster = require('cluster');
var dgram = require('dgram'); const dgram = require('dgram');
if (common.isWindows) { if (common.isWindows) {
@ -28,11 +28,10 @@ function master() {
// Disconnect workers when the expected number of messages have been // Disconnect workers when the expected number of messages have been
// received. // received.
socket.on('message', function(data, info) { socket.on('message', common.mustCall((data, info) => {
received++; received++;
if (received == PACKETS_PER_WORKER * NUM_WORKERS) { if (received === PACKETS_PER_WORKER * NUM_WORKERS) {
console.log('master received %d packets', received);
// Close the socket. // Close the socket.
socket.close(); socket.close();
@ -40,7 +39,7 @@ function master() {
// Disconnect all workers. // Disconnect all workers.
cluster.disconnect(); cluster.disconnect();
} }
}); }, NUM_WORKERS * PACKETS_PER_WORKER));
// Fork workers. // Fork workers.
for (var i = 0; i < NUM_WORKERS; i++) for (var i = 0; i < NUM_WORKERS; i++)
@ -50,8 +49,8 @@ function master() {
function worker() { function worker() {
// Create udp socket and send packets to master. // Create udp socket and send packets to master.
var socket = dgram.createSocket('udp4'); const socket = dgram.createSocket('udp4');
var buf = Buffer.from('hello world'); const buf = Buffer.from('hello world');
// This test is intended to exercise the cluster binding of udp sockets, but // This test is intended to exercise the cluster binding of udp sockets, but
// since sockets aren't clustered when implicitly bound by at first call of // since sockets aren't clustered when implicitly bound by at first call of
@ -60,7 +59,4 @@ function worker() {
for (var i = 0; i < PACKETS_PER_WORKER; i++) for (var i = 0; i < PACKETS_PER_WORKER; i++)
socket.send(buf, 0, buf.length, common.PORT, '127.0.0.1'); socket.send(buf, 0, buf.length, common.PORT, '127.0.0.1');
console.log('worker %d sent %d packets', cluster.worker.id,
PACKETS_PER_WORKER);
} }

8
test/parallel/test-cluster-dgram-reuse.js

@ -11,9 +11,9 @@ if (common.isWindows) {
} }
if (cluster.isMaster) { if (cluster.isMaster) {
cluster.fork().on('exit', function(code) { cluster.fork().on('exit', common.mustCall((code) => {
assert.equal(code, 0); assert.strictEqual(code, 0);
}); }));
return; return;
} }
@ -24,7 +24,7 @@ function next() {
return; return;
// Work around health check issue // Work around health check issue
process.nextTick(function() { process.nextTick(() => {
for (var i = 0; i < sockets.length; i++) for (var i = 0; i < sockets.length; i++)
sockets[i].close(close); sockets[i].close(close);
}); });

8
test/parallel/test-cluster-disconnect-before-exit.js

@ -1,9 +1,9 @@
'use strict'; 'use strict';
require('../common'); const common = require('../common');
var cluster = require('cluster'); const cluster = require('cluster');
if (cluster.isMaster) { if (cluster.isMaster) {
var worker = cluster.fork().on('online', disconnect); const worker = cluster.fork().on('online', common.mustCall(disconnect));
function disconnect() { function disconnect() {
worker.disconnect(); worker.disconnect();
@ -11,6 +11,6 @@ if (cluster.isMaster) {
// Disconnect is supposed to disconnect all workers, but not workers that // Disconnect is supposed to disconnect all workers, but not workers that
// are already disconnected, since calling disconnect() on an already // are already disconnected, since calling disconnect() on an already
// disconnected worker would error. // disconnected worker would error.
worker.on('disconnect', cluster.disconnect); worker.on('disconnect', common.mustCall(cluster.disconnect));
} }
} }

52
test/parallel/test-cluster-disconnect.js

@ -1,15 +1,15 @@
'use strict'; 'use strict';
var common = require('../common'); const common = require('../common');
var assert = require('assert'); const assert = require('assert');
var cluster = require('cluster'); const cluster = require('cluster');
var net = require('net'); const net = require('net');
if (cluster.isWorker) { if (cluster.isWorker) {
net.createServer(function(socket) { net.createServer((socket) => {
socket.end('echo'); socket.end('echo');
}).listen(common.PORT, '127.0.0.1'); }).listen(common.PORT, '127.0.0.1');
net.createServer(function(socket) { net.createServer((socket) => {
socket.end('echo'); socket.end('echo');
}).listen(common.PORT + 1, '127.0.0.1'); }).listen(common.PORT + 1, '127.0.0.1');
@ -17,25 +17,25 @@ if (cluster.isWorker) {
var servers = 2; var servers = 2;
// test a single TCP server // test a single TCP server
var testConnection = function(port, cb) { const testConnection = function(port, cb) {
var socket = net.connect(port, '127.0.0.1', function() { var socket = net.connect(port, '127.0.0.1', () => {
// buffer result // buffer result
var result = ''; var result = '';
socket.on('data', function(chunk) { result += chunk; }); socket.on('data', common.mustCall((chunk) => { result += chunk; }));
// check result // check result
socket.on('end', function() { socket.on('end', common.mustCall(() => {
cb(result === 'echo'); cb(result === 'echo');
}); }));
}); });
}; };
// test both servers created in the cluster // test both servers created in the cluster
var testCluster = function(cb) { const testCluster = function(cb) {
var done = 0; var done = 0;
for (var i = 0, l = servers; i < l; i++) { for (var i = 0, l = servers; i < l; i++) {
testConnection(common.PORT + i, function(success) { testConnection(common.PORT + i, (success) => {
assert.ok(success); assert.ok(success);
done += 1; done += 1;
if (done === servers) { if (done === servers) {
@ -46,40 +46,38 @@ if (cluster.isWorker) {
}; };
// start two workers and execute callback when both is listening // start two workers and execute callback when both is listening
var startCluster = function(cb) { const startCluster = function(cb) {
var workers = 8; var workers = 8;
var online = 0; var online = 0;
for (var i = 0, l = workers; i < l; i++) { for (var i = 0, l = workers; i < l; i++) {
cluster.fork().on('listening', common.mustCall(() => {
var worker = cluster.fork();
worker.on('listening', function() {
online += 1; online += 1;
if (online === workers * servers) { if (online === workers * servers) {
cb(); cb();
} }
}); }, servers));
} }
}; };
var results = { const results = {
start: 0, start: 0,
test: 0, test: 0,
disconnect: 0 disconnect: 0
}; };
var test = function(again) { const test = function(again) {
//1. start cluster //1. start cluster
startCluster(function() { startCluster(() => {
results.start += 1; results.start += 1;
//2. test cluster //2. test cluster
testCluster(function() { testCluster(() => {
results.test += 1; results.test += 1;
//3. disconnect cluster //3. disconnect cluster
cluster.disconnect(function() { cluster.disconnect(() => {
results.disconnect += 1; results.disconnect += 1;
// run test again to confirm cleanup // run test again to confirm cleanup
@ -93,9 +91,9 @@ if (cluster.isWorker) {
test(true); test(true);
process.once('exit', function() { process.once('exit', () => {
assert.equal(results.start, 2); assert.strictEqual(results.start, 2);
assert.equal(results.test, 2); assert.strictEqual(results.test, 2);
assert.equal(results.disconnect, 2); assert.strictEqual(results.disconnect, 2);
}); });
} }

68
test/parallel/test-cluster-master-error.js

@ -1,22 +1,22 @@
'use strict'; 'use strict';
var common = require('../common'); const common = require('../common');
var assert = require('assert'); const assert = require('assert');
var cluster = require('cluster'); const cluster = require('cluster');
const totalWorkers = 2;
// Cluster setup // Cluster setup
if (cluster.isWorker) { if (cluster.isWorker) {
var http = require('http'); const http = require('http');
http.Server(function() { http.Server(() => {
}).listen(common.PORT, '127.0.0.1'); }).listen(common.PORT, '127.0.0.1');
} else if (process.argv[2] === 'cluster') { } else if (process.argv[2] === 'cluster') {
var totalWorkers = 2;
// Send PID to testcase process // Send PID to testcase process
var forkNum = 0; var forkNum = 0;
cluster.on('fork', function forkEvent(worker) { cluster.on('fork', common.mustCall(function forkEvent(worker) {
// Send PID // Send PID
process.send({ process.send({
@ -28,11 +28,11 @@ if (cluster.isWorker) {
if (++forkNum === totalWorkers) { if (++forkNum === totalWorkers) {
cluster.removeListener('fork', forkEvent); cluster.removeListener('fork', forkEvent);
} }
}); }));
// Throw accidental error when all workers are listening // Throw accidental error when all workers are listening
var listeningNum = 0; var listeningNum = 0;
cluster.on('listening', function listeningEvent() { cluster.on('listening', common.mustCall(function listeningEvent() {
// When all workers are listening // When all workers are listening
if (++listeningNum === totalWorkers) { if (++listeningNum === totalWorkers) {
@ -40,13 +40,12 @@ if (cluster.isWorker) {
cluster.removeListener('listening', listeningEvent); cluster.removeListener('listening', listeningEvent);
// Throw accidental error // Throw accidental error
process.nextTick(function() { process.nextTick(() => {
console.error('about to throw');
throw new Error('accidental error'); throw new Error('accidental error');
}); });
} }
}); }));
// Startup a basic cluster // Startup a basic cluster
cluster.fork(); cluster.fork();
@ -55,51 +54,36 @@ if (cluster.isWorker) {
} else { } else {
// This is the testcase // This is the testcase
var fork = require('child_process').fork; const fork = require('child_process').fork;
var isAlive = function(pid) {
try {
//this will throw an error if the process is dead
process.kill(pid, 0);
return true;
} catch (e) {
return false;
}
};
var masterExited = false; var masterExited = false;
var workersExited = false; var workersExited = false;
// List all workers // List all workers
var workers = []; const workers = [];
// Spawn a cluster process // Spawn a cluster process
var master = fork(process.argv[1], ['cluster'], {silent: true}); const master = fork(process.argv[1], ['cluster'], {silent: true});
// Handle messages from the cluster // Handle messages from the cluster
master.on('message', function(data) { master.on('message', common.mustCall((data) => {
// Add worker pid to list and progress tracker // Add worker pid to list and progress tracker
if (data.cmd === 'worker') { if (data.cmd === 'worker') {
workers.push(data.workerPID); workers.push(data.workerPID);
} }
}); }, totalWorkers));
// When cluster is dead // When cluster is dead
master.on('exit', function(code) { master.on('exit', common.mustCall((code) => {
// Check that the cluster died accidentally (non-zero exit code) // Check that the cluster died accidentally (non-zero exit code)
masterExited = !!code; masterExited = !!code;
var pollWorkers = function() { const pollWorkers = function() {
// When master is dead all workers should be dead too // When master is dead all workers should be dead too
var alive = false; var alive = false;
workers.forEach(function(pid) { workers.forEach((pid) => alive = common.isAlive(pid));
if (isAlive(pid)) {
alive = true;
}
});
if (alive) { if (alive) {
setTimeout(pollWorkers, 50); setTimeout(pollWorkers, 50);
} else { } else {
@ -109,13 +93,13 @@ if (cluster.isWorker) {
// Loop indefinitely until worker exit // Loop indefinitely until worker exit
pollWorkers(); pollWorkers();
}); }));
process.once('exit', function() { process.once('exit', () => {
var m = 'The master did not die after an error was thrown'; assert(masterExited,
assert.ok(masterExited, m); 'The master did not die after an error was thrown');
m = 'The workers did not die after an error in the master'; assert(workersExited,
assert.ok(workersExited, m); 'The workers did not die after an error in the master');
}); });
} }

50
test/parallel/test-cluster-master-kill.js

@ -1,17 +1,17 @@
'use strict'; 'use strict';
var common = require('../common'); const common = require('../common');
var assert = require('assert'); const assert = require('assert');
var cluster = require('cluster'); const cluster = require('cluster');
if (cluster.isWorker) { if (cluster.isWorker) {
// keep the worker alive // keep the worker alive
var http = require('http'); const http = require('http');
http.Server().listen(common.PORT, '127.0.0.1'); http.Server().listen(common.PORT, '127.0.0.1');
} else if (process.argv[2] === 'cluster') { } else if (process.argv[2] === 'cluster') {
var worker = cluster.fork(); const worker = cluster.fork();
// send PID info to testcase process // send PID info to testcase process
process.send({ process.send({
@ -19,59 +19,47 @@ if (cluster.isWorker) {
}); });
// terminate the cluster process // terminate the cluster process
worker.once('listening', function() { worker.once('listening', common.mustCall(() => {
setTimeout(function() { setTimeout(() => {
process.exit(0); process.exit(0);
}, 1000); }, 1000);
}); }));
} else { } else {
// This is the testcase // This is the testcase
var fork = require('child_process').fork; const fork = require('child_process').fork;
// is process alive helper
var isAlive = function(pid) {
try {
//this will throw an error if the process is dead
process.kill(pid, 0);
return true;
} catch (e) {
return false;
}
};
// Spawn a cluster process // Spawn a cluster process
var master = fork(process.argv[1], ['cluster']); const master = fork(process.argv[1], ['cluster']);
// get pid info // get pid info
var pid = null; var pid = null;
master.once('message', function(data) { master.once('message', (data) => {
pid = data.pid; pid = data.pid;
}); });
// When master is dead // When master is dead
var alive = true; var alive = true;
master.on('exit', function(code) { master.on('exit', common.mustCall((code) => {
// make sure that the master died on purpose // make sure that the master died on purpose
assert.equal(code, 0); assert.strictEqual(code, 0);
// check worker process status // check worker process status
var pollWorker = function() { const pollWorker = function() {
alive = isAlive(pid); alive = common.isAlive(pid);
if (alive) { if (alive) {
setTimeout(pollWorker, 50); setTimeout(pollWorker, 50);
} }
}; };
// Loop indefinitely until worker exit. // Loop indefinitely until worker exit.
pollWorker(); pollWorker();
}); }));
process.once('exit', function() { process.once('exit', () => {
assert.equal(typeof pid, 'number', 'did not get worker pid info'); assert.strictEqual(typeof pid, 'number', 'did not get worker pid info');
assert.equal(alive, false, 'worker was alive after master died'); assert.strictEqual(alive, false, 'worker was alive after master died');
}); });
} }

62
test/parallel/test-cluster-worker-disconnect.js

@ -1,25 +1,25 @@
'use strict'; 'use strict';
var common = require('../common'); const common = require('../common');
var assert = require('assert'); const assert = require('assert');
var cluster = require('cluster'); const cluster = require('cluster');
if (cluster.isWorker) { if (cluster.isWorker) {
var http = require('http'); const http = require('http');
http.Server(function() { http.Server(() => {
}).listen(common.PORT, '127.0.0.1'); }).listen(common.PORT, '127.0.0.1');
const worker = cluster.worker; const worker = cluster.worker;
assert.strictEqual(worker.exitedAfterDisconnect, worker.suicide); assert.strictEqual(worker.exitedAfterDisconnect, worker.suicide);
cluster.worker.on('disconnect', function() { cluster.worker.on('disconnect', common.mustCall(() => {
assert.strictEqual(cluster.worker.exitedAfterDisconnect, assert.strictEqual(cluster.worker.exitedAfterDisconnect,
cluster.worker.suicide); cluster.worker.suicide);
process.exit(42); process.exit(42);
}); }));
} else if (cluster.isMaster) { } else if (cluster.isMaster) {
var checks = { const checks = {
cluster: { cluster: {
emitDisconnect: false, emitDisconnect: false,
emitExit: false, emitExit: false,
@ -35,50 +35,40 @@ if (cluster.isWorker) {
} }
}; };
// helper function to check if a process is alive
var alive = function(pid) {
try {
process.kill(pid, 0);
return true;
} catch (e) {
return false;
}
};
// start worker // start worker
var worker = cluster.fork(); const worker = cluster.fork();
// Disconnect worker when it is ready // Disconnect worker when it is ready
worker.once('listening', function() { worker.once('listening', common.mustCall(() => {
worker.disconnect(); worker.disconnect();
}); }));
// Check cluster events // Check cluster events
cluster.once('disconnect', function() { cluster.once('disconnect', common.mustCall(() => {
checks.cluster.emitDisconnect = true; checks.cluster.emitDisconnect = true;
}); }));
cluster.once('exit', function() { cluster.once('exit', common.mustCall(() => {
checks.cluster.emitExit = true; checks.cluster.emitExit = true;
}); }));
// Check worker events and properties // Check worker events and properties
worker.once('disconnect', function() { worker.once('disconnect', common.mustCall(() => {
checks.worker.emitDisconnect = true; checks.worker.emitDisconnect = true;
checks.worker.voluntaryMode = worker.exitedAfterDisconnect; checks.worker.voluntaryMode = worker.exitedAfterDisconnect;
checks.worker.state = worker.state; checks.worker.state = worker.state;
}); }));
// Check that the worker died // Check that the worker died
worker.once('exit', function(code) { worker.once('exit', common.mustCall((code) => {
checks.worker.emitExit = true; checks.worker.emitExit = true;
checks.worker.died = !alive(worker.process.pid); checks.worker.died = !common.isAlive(worker.process.pid);
checks.worker.emitDisconnectInsideWorker = code === 42; checks.worker.emitDisconnectInsideWorker = code === 42;
}); }));
process.once('exit', function() { process.once('exit', () => {
var w = checks.worker; const w = checks.worker;
var c = checks.cluster; const c = checks.cluster;
// events // events
assert.ok(w.emitDisconnect, 'Disconnect event did not emit'); assert.ok(w.emitDisconnect, 'Disconnect event did not emit');
@ -89,8 +79,10 @@ if (cluster.isWorker) {
assert.ok(c.emitExit, 'Exit event did not emit'); assert.ok(c.emitExit, 'Exit event did not emit');
// flags // flags
assert.equal(w.state, 'disconnected', 'The state property was not set'); assert.strictEqual(w.state, 'disconnected',
assert.equal(w.voluntaryMode, true, 'Voluntary exit mode was not set'); 'The state property was not set');
assert.strictEqual(w.voluntaryMode, true,
'Voluntary exit mode was not set');
// is process alive // is process alive
assert.ok(w.died, 'The worker did not die'); assert.ok(w.died, 'The worker did not die');

77
test/parallel/test-cluster-worker-exit.js

@ -6,24 +6,24 @@
// - the worker.exitedAfterDisconnect flag, and worker.state are correct // - the worker.exitedAfterDisconnect flag, and worker.state are correct
// - the worker process actually goes away // - the worker process actually goes away
var common = require('../common'); const common = require('../common');
var assert = require('assert'); const assert = require('assert');
var cluster = require('cluster'); const cluster = require('cluster');
var EXIT_CODE = 42; const EXIT_CODE = 42;
if (cluster.isWorker) { if (cluster.isWorker) {
var http = require('http'); const http = require('http');
var server = http.Server(function() { }); const server = http.Server(() => { });
server.once('listening', function() { server.once('listening', common.mustCall(() => {
process.exit(EXIT_CODE); process.exit(EXIT_CODE);
}); }));
server.listen(common.PORT, '127.0.0.1'); server.listen(common.PORT, '127.0.0.1');
} else if (cluster.isMaster) { } else if (cluster.isMaster) {
var expected_results = { const expected_results = {
cluster_emitDisconnect: [1, "the cluster did not emit 'disconnect'"], cluster_emitDisconnect: [1, "the cluster did not emit 'disconnect'"],
cluster_emitExit: [1, "the cluster did not emit 'exit'"], cluster_emitExit: [1, "the cluster did not emit 'exit'"],
cluster_exitCode: [EXIT_CODE, 'the cluster exited w/ incorrect exitCode'], cluster_exitCode: [EXIT_CODE, 'the cluster exited w/ incorrect exitCode'],
@ -38,7 +38,7 @@ if (cluster.isWorker) {
worker_exitCode: [EXIT_CODE, 'the worker exited w/ incorrect exitCode'], worker_exitCode: [EXIT_CODE, 'the worker exited w/ incorrect exitCode'],
worker_signalCode: [null, 'the worker exited w/ incorrect signalCode'] worker_signalCode: [null, 'the worker exited w/ incorrect signalCode']
}; };
var results = { const results = {
cluster_emitDisconnect: 0, cluster_emitDisconnect: 0,
cluster_emitExit: 0, cluster_emitExit: 0,
worker_emitDisconnect: 0, worker_emitDisconnect: 0,
@ -47,51 +47,45 @@ if (cluster.isWorker) {
// start worker // start worker
var worker = cluster.fork(); const worker = cluster.fork();
worker.once('listening', function() {
// the worker is up and running...
});
// Check cluster events // Check cluster events
cluster.on('disconnect', function() { cluster.on('disconnect', common.mustCall(() => {
results.cluster_emitDisconnect += 1; results.cluster_emitDisconnect += 1;
}); }));
cluster.on('exit', function(worker) { cluster.on('exit', common.mustCall((worker) => {
results.cluster_exitCode = worker.process.exitCode; results.cluster_exitCode = worker.process.exitCode;
results.cluster_signalCode = worker.process.signalCode; results.cluster_signalCode = worker.process.signalCode;
results.cluster_emitExit += 1; results.cluster_emitExit += 1;
}); }));
// Check worker events and properties // Check worker events and properties
worker.on('disconnect', function() { worker.on('disconnect', common.mustCall(() => {
results.worker_emitDisconnect += 1; results.worker_emitDisconnect += 1;
results.worker_suicideMode = worker.suicide; results.worker_suicideMode = worker.suicide;
results.worker_exitedAfterDisconnect = worker.exitedAfterDisconnect; results.worker_exitedAfterDisconnect = worker.exitedAfterDisconnect;
results.worker_state = worker.state; results.worker_state = worker.state;
if (results.worker_emitExit > 0) { if (results.worker_emitExit > 0) {
process.nextTick(function() { finish_test(); }); process.nextTick(() => finish_test());
} }
}); }));
// Check that the worker died // Check that the worker died
worker.once('exit', function(exitCode, signalCode) { worker.once('exit', common.mustCall((exitCode, signalCode) => {
results.worker_exitCode = exitCode; results.worker_exitCode = exitCode;
results.worker_signalCode = signalCode; results.worker_signalCode = signalCode;
results.worker_emitExit += 1; results.worker_emitExit += 1;
results.worker_died = !alive(worker.process.pid); results.worker_died = !common.isAlive(worker.process.pid);
if (results.worker_emitDisconnect > 0) { if (results.worker_emitDisconnect > 0) {
process.nextTick(function() { finish_test(); }); process.nextTick(() => finish_test());
} }
}); }));
var finish_test = function() { const finish_test = function() {
try { try {
checkResults(expected_results, results); checkResults(expected_results, results);
} catch (exc) { } catch (exc) {
console.error('FAIL: ' + exc.message); if (exc.name !== 'AssertionError') {
if (exc.name != 'AssertionError') {
console.trace(exc); console.trace(exc);
} }
@ -105,26 +99,13 @@ if (cluster.isWorker) {
// some helper functions ... // some helper functions ...
function checkResults(expected_results, results) { function checkResults(expected_results, results) {
for (var k in expected_results) { for (const k in expected_results) {
const actual = results[k]; const actual = results[k];
const expected = expected_results[k]; const expected = expected_results[k];
var msg = (expected[1] || '') + assert.strictEqual(actual,
(' [expected: ' + expected[0] + ' / actual: ' + actual + ']'); expected && expected.length ? expected[0] : expected,
(expected[1] || '') +
if (expected && expected.length) { ` [expected: ${expected[0]} / actual: ${actual}]`);
assert.equal(actual, expected[0], msg);
} else {
assert.equal(actual, expected, msg);
}
}
}
function alive(pid) {
try {
process.kill(pid, 'SIGCONT');
return true;
} catch (e) {
return false;
} }
} }

62
test/parallel/test-cluster-worker-kill.js

@ -6,20 +6,20 @@
// - the worker.exitedAfterDisconnect flag, and worker.state are correct // - the worker.exitedAfterDisconnect flag, and worker.state are correct
// - the worker process actually goes away // - the worker process actually goes away
var common = require('../common'); const common = require('../common');
var assert = require('assert'); const assert = require('assert');
var cluster = require('cluster'); const cluster = require('cluster');
if (cluster.isWorker) { if (cluster.isWorker) {
var http = require('http'); const http = require('http');
var server = http.Server(function() { }); const server = http.Server(() => { });
server.once('listening', function() { }); server.once('listening', common.mustCall(() => { }));
server.listen(common.PORT, '127.0.0.1'); server.listen(common.PORT, '127.0.0.1');
} else if (cluster.isMaster) { } else if (cluster.isMaster) {
var KILL_SIGNAL = 'SIGKILL', const KILL_SIGNAL = 'SIGKILL',
expected_results = { expected_results = {
cluster_emitDisconnect: [1, "the cluster did not emit 'disconnect'"], cluster_emitDisconnect: [1, "the cluster did not emit 'disconnect'"],
cluster_emitExit: [1, "the cluster did not emit 'exit'"], cluster_emitExit: [1, "the cluster did not emit 'exit'"],
@ -45,40 +45,40 @@ if (cluster.isWorker) {
// start worker // start worker
var worker = cluster.fork(); const worker = cluster.fork();
// when the worker is up and running, kill it // when the worker is up and running, kill it
worker.once('listening', function() { worker.once('listening', common.mustCall(() => {
worker.process.kill(KILL_SIGNAL); worker.process.kill(KILL_SIGNAL);
}); }));
// Check cluster events // Check cluster events
cluster.on('disconnect', function() { cluster.on('disconnect', common.mustCall(() => {
results.cluster_emitDisconnect += 1; results.cluster_emitDisconnect += 1;
}); }));
cluster.on('exit', function(worker) { cluster.on('exit', common.mustCall((worker) => {
results.cluster_exitCode = worker.process.exitCode; results.cluster_exitCode = worker.process.exitCode;
results.cluster_signalCode = worker.process.signalCode; results.cluster_signalCode = worker.process.signalCode;
results.cluster_emitExit += 1; results.cluster_emitExit += 1;
}); }));
// Check worker events and properties // Check worker events and properties
worker.on('disconnect', function() { worker.on('disconnect', common.mustCall(() => {
results.worker_emitDisconnect += 1; results.worker_emitDisconnect += 1;
results.worker_exitedAfter = worker.exitedAfterDisconnect; results.worker_exitedAfter = worker.exitedAfterDisconnect;
results.worker_state = worker.state; results.worker_state = worker.state;
}); }));
// Check that the worker died // Check that the worker died
worker.once('exit', function(exitCode, signalCode) { worker.once('exit', common.mustCall((exitCode, signalCode) => {
results.worker_exitCode = exitCode; results.worker_exitCode = exitCode;
results.worker_signalCode = signalCode; results.worker_signalCode = signalCode;
results.worker_emitExit += 1; results.worker_emitExit += 1;
results.worker_died = !alive(worker.process.pid); results.worker_died = !common.isAlive(worker.process.pid);
}); }));
process.on('exit', function() { process.on('exit', () => {
checkResults(expected_results, results); checkResults(expected_results, results);
}); });
} }
@ -86,25 +86,13 @@ if (cluster.isWorker) {
// some helper functions ... // some helper functions ...
function checkResults(expected_results, results) { function checkResults(expected_results, results) {
for (var k in expected_results) { for (const k in expected_results) {
const actual = results[k]; const actual = results[k];
const expected = expected_results[k]; const expected = expected_results[k];
var msg = (expected[1] || '') + assert.strictEqual(actual,
(' [expected: ' + expected[0] + ' / actual: ' + actual + ']'); expected && expected.length ? expected[0] : expected,
if (expected && expected.length) { (expected[1] || '') +
assert.equal(actual, expected[0], msg); ` [expected: ${expected[0]} / actual: ${actual}]`);
} else {
assert.equal(actual, expected, msg);
}
}
}
function alive(pid) {
try {
process.kill(pid, 'SIGCONT');
return true;
} catch (e) {
return false;
} }
} }

Loading…
Cancel
Save