-
Notifications
You must be signed in to change notification settings - Fork 30.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
test: eliminate multicast test FreeBSD flakiness #4042
Changes from 3 commits
c623001
0f2782b
8021d83
0b5c3cb
26b56c0
9b527da
fef9193
71470b5
615356a
ccafb10
bd8a3c1
ec975e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,126 @@ | ||
'use strict'; | ||
var common = require('../common'), | ||
assert = require('assert'), | ||
dgram = require('dgram'), | ||
util = require('util'), | ||
Buffer = require('buffer').Buffer, | ||
fork = require('child_process').fork, | ||
LOCAL_BROADCAST_HOST = '224.0.0.114', | ||
TIMEOUT = common.platformTimeout(5000), | ||
messages = [ | ||
new Buffer('First message to send'), | ||
new Buffer('Second message to send'), | ||
new Buffer('Third message to send'), | ||
new Buffer('Fourth message to send') | ||
]; | ||
const common = require('../common'); | ||
const assert = require('assert'); | ||
const dgram = require('dgram'); | ||
const Buffer = require('buffer').Buffer; | ||
const fork = require('child_process').fork; | ||
const LOCAL_BROADCAST_HOST = '224.0.0.114'; | ||
const TIMEOUT = common.platformTimeout(5000); | ||
const messages = [ | ||
new Buffer('First message to send'), | ||
new Buffer('Second message to send'), | ||
new Buffer('Third message to send'), | ||
new Buffer('Fourth message to send') | ||
]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Funny indent but if the linter is happy... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since I'm doing a bunch of other cosmetic-ish changes on the pre-existing code, I'll fix the funky indent. |
||
|
||
// skip test in FreeBSD jails | ||
if (common.inFreeBSDJail) { | ||
console.log('1..0 # Skipped: In a FreeBSD jail'); | ||
return; | ||
} | ||
|
||
function launchChildProcess(index) { | ||
const worker = fork(process.argv[1], ['child']); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, why not. |
||
workers[worker.pid] = worker; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe hoist There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that does make it easier to follow. I'll also fix up the remaining bits of the related |
||
|
||
worker.messagesReceived = []; | ||
|
||
//handle the death of workers | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you capitalize and punctuate comments while you're here? EDIT: And add a space after the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I used to describe myself as The Open Source Copyeditor, so adding capitalization, punctuation, and appropriate spacing is right up my alley. (It's an incredibly dull alley, but it's my incredibly dull alley.) Done! |
||
worker.on('exit', function(code, signal) { | ||
// don't consider this the true death if the | ||
// worker has finished successfully | ||
|
||
// or if the exit code is 0 | ||
if (worker.isDone || code === 0) { | ||
return; | ||
} | ||
|
||
dead += 1; | ||
console.error('[PARENT] Worker %d died. %d dead of %d', | ||
worker.pid, | ||
dead, | ||
listeners); | ||
|
||
if (dead === listeners) { | ||
console.error('[PARENT] All workers have died.'); | ||
console.error('[PARENT] Fail'); | ||
|
||
killChildren(workers); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this necessary? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suppose not. Deleted. |
||
|
||
process.exit(1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not a nit, more a stream-of-consciousness remark, but I would have thrown an exception here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really a response but getting all stream-of-consciousness over here too: FWIW, I agree and probably would have chosen to throw an exception too and would have also not included |
||
} | ||
}); | ||
|
||
worker.on('message', function(msg) { | ||
if (msg.listening) { | ||
listening += 1; | ||
|
||
if (listening === listeners) { | ||
//all child process are listening, so start sending | ||
sendSocket.sendNext(); | ||
} | ||
} | ||
else if (msg.message) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll do a |
||
worker.messagesReceived.push(msg.message); | ||
|
||
if (worker.messagesReceived.length === messages.length) { | ||
done += 1; | ||
worker.isDone = true; | ||
console.error('[PARENT] %d received %d messages total.', | ||
worker.pid, | ||
worker.messagesReceived.length); | ||
} | ||
|
||
if (done === listeners) { | ||
console.error('[PARENT] All workers have received the ' + | ||
'required number of messages. Will now compare.'); | ||
|
||
Object.keys(workers).forEach(function(pid) { | ||
const worker = workers[pid]; | ||
|
||
var count = 0; | ||
|
||
worker.messagesReceived.forEach(function(buf) { | ||
for (var i = 0; i < messages.length; ++i) { | ||
if (buf.toString() === messages[i].toString()) { | ||
count++; | ||
break; | ||
} | ||
} | ||
}); | ||
|
||
console.error('[PARENT] %d received %d matching messages.', | ||
worker.pid, count); | ||
|
||
assert.equal(count, messages.length, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. strictEqual? |
||
'A worker received an invalid multicast message'); | ||
}); | ||
|
||
clearTimeout(timer); | ||
console.error('[PARENT] Success'); | ||
killChildren(workers); | ||
} | ||
} | ||
}); | ||
} | ||
|
||
function killChildren(children) { | ||
Object.keys(children).forEach(function(key) { | ||
const child = children[key]; | ||
child.kill(); | ||
}); | ||
} | ||
|
||
if (process.argv[2] !== 'child') { | ||
var workers = {}, | ||
listeners = 3, | ||
listening = 0, | ||
dead = 0, | ||
i = 0, | ||
done = 0, | ||
timer = null; | ||
done = 0; | ||
|
||
//exit the test if it doesn't succeed within TIMEOUT | ||
timer = setTimeout(function() { | ||
var timer = setTimeout(function() { | ||
console.error('[PARENT] Responses were not received within %d ms.', | ||
TIMEOUT); | ||
console.error('[PARENT] Fail'); | ||
|
@@ -36,90 +132,7 @@ if (process.argv[2] !== 'child') { | |
|
||
//launch child processes | ||
for (var x = 0; x < listeners; x++) { | ||
(function() { | ||
var worker = fork(process.argv[1], ['child']); | ||
workers[worker.pid] = worker; | ||
|
||
worker.messagesReceived = []; | ||
|
||
//handle the death of workers | ||
worker.on('exit', function(code, signal) { | ||
// don't consider this the true death if the | ||
// worker has finished successfully | ||
|
||
// or if the exit code is 0 | ||
if (worker.isDone || code === 0) { | ||
return; | ||
} | ||
|
||
dead += 1; | ||
console.error('[PARENT] Worker %d died. %d dead of %d', | ||
worker.pid, | ||
dead, | ||
listeners); | ||
|
||
if (dead === listeners) { | ||
console.error('[PARENT] All workers have died.'); | ||
console.error('[PARENT] Fail'); | ||
|
||
killChildren(workers); | ||
|
||
process.exit(1); | ||
} | ||
}); | ||
|
||
worker.on('message', function(msg) { | ||
if (msg.listening) { | ||
listening += 1; | ||
|
||
if (listening === listeners) { | ||
//all child process are listening, so start sending | ||
sendSocket.sendNext(); | ||
} | ||
} | ||
else if (msg.message) { | ||
worker.messagesReceived.push(msg.message); | ||
|
||
if (worker.messagesReceived.length === messages.length) { | ||
done += 1; | ||
worker.isDone = true; | ||
console.error('[PARENT] %d received %d messages total.', | ||
worker.pid, | ||
worker.messagesReceived.length); | ||
} | ||
|
||
if (done === listeners) { | ||
console.error('[PARENT] All workers have received the ' + | ||
'required number of messages. Will now compare.'); | ||
|
||
Object.keys(workers).forEach(function(pid) { | ||
var worker = workers[pid]; | ||
|
||
var count = 0; | ||
|
||
worker.messagesReceived.forEach(function(buf) { | ||
for (var i = 0; i < messages.length; ++i) { | ||
if (buf.toString() === messages[i].toString()) { | ||
count++; | ||
break; | ||
} | ||
} | ||
}); | ||
|
||
console.error('[PARENT] %d received %d matching messages.', | ||
worker.pid, count); | ||
|
||
assert.equal(count, messages.length, | ||
'A worker received an invalid multicast message'); | ||
}); | ||
|
||
clearTimeout(timer); | ||
console.error('[PARENT] Success'); | ||
killChildren(workers); | ||
} | ||
} | ||
}); | ||
})(x); | ||
launchChildProcess(x); | ||
} | ||
|
||
var sendSocket = dgram.createSocket('udp4'); | ||
|
@@ -141,7 +154,7 @@ if (process.argv[2] !== 'child') { | |
}); | ||
|
||
sendSocket.sendNext = function() { | ||
var buf = messages[i++]; | ||
const buf = messages[i++]; | ||
|
||
if (!buf) { | ||
try { sendSocket.close(); } catch (e) {} | ||
|
@@ -151,61 +164,51 @@ if (process.argv[2] !== 'child') { | |
sendSocket.send(buf, 0, buf.length, | ||
common.PORT, LOCAL_BROADCAST_HOST, function(err) { | ||
if (err) throw err; | ||
console.error('[PARENT] sent %s to %s:%s', | ||
util.inspect(buf.toString()), | ||
console.error('[PARENT] sent "%s" to %s:%s', | ||
buf.toString(), | ||
LOCAL_BROADCAST_HOST, common.PORT); | ||
process.nextTick(sendSocket.sendNext); | ||
}); | ||
}; | ||
|
||
function killChildren(children) { | ||
Object.keys(children).forEach(function(key) { | ||
var child = children[key]; | ||
child.kill(); | ||
}); | ||
} | ||
} | ||
|
||
if (process.argv[2] === 'child') { | ||
var receivedMessages = []; | ||
var listenSocket = dgram.createSocket({ | ||
const receivedMessages = []; | ||
const listenSocket = dgram.createSocket({ | ||
type: 'udp4', | ||
reuseAddr: true | ||
}); | ||
|
||
listenSocket.on('message', function(buf, rinfo) { | ||
console.error('[CHILD] %s received %s from %j', process.pid, | ||
util.inspect(buf.toString()), rinfo); | ||
listenSocket.on('listening', function() { | ||
listenSocket.addMembership(LOCAL_BROADCAST_HOST); | ||
|
||
receivedMessages.push(buf); | ||
listenSocket.on('message', function(buf, rinfo) { | ||
console.error('[CHILD] %s received "%s" from %j', process.pid, | ||
buf.toString(), rinfo); | ||
|
||
process.send({ message: buf.toString() }); | ||
receivedMessages.push(buf); | ||
|
||
if (receivedMessages.length == messages.length) { | ||
// .dropMembership() not strictly needed but here as a sanity check | ||
listenSocket.dropMembership(LOCAL_BROADCAST_HOST); | ||
process.nextTick(function() { | ||
listenSocket.close(); | ||
}); | ||
} | ||
}); | ||
process.send({ message: buf.toString() }); | ||
|
||
listenSocket.on('close', function() { | ||
//HACK: Wait to exit the process to ensure that the parent | ||
//process has had time to receive all messages via process.send() | ||
//This may be indicitave of some other issue. | ||
setTimeout(function() { | ||
process.exit(); | ||
}, 1000); | ||
}); | ||
if (receivedMessages.length == messages.length) { | ||
// .dropMembership() not strictly needed but here as a sanity check | ||
listenSocket.dropMembership(LOCAL_BROADCAST_HOST); | ||
process.nextTick(function() { | ||
listenSocket.close(); | ||
}); | ||
} | ||
}); | ||
|
||
listenSocket.on('listening', function() { | ||
listenSocket.on('close', function() { | ||
//HACK: Wait to exit the process to ensure that the parent | ||
//process has had time to receive all messages via process.send() | ||
//This may be indicitave of some other issue. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/indicitave/indicative/ |
||
setTimeout(function() { | ||
process.exit(); | ||
}, common.platformTimeout(1000)); | ||
}); | ||
process.send({ listening: true }); | ||
}); | ||
|
||
listenSocket.bind(common.PORT); | ||
|
||
listenSocket.on('listening', function() { | ||
listenSocket.addMembership(LOCAL_BROADCAST_HOST); | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can safely drop this, I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, done.