-
-
Notifications
You must be signed in to change notification settings - Fork 35.4k
test: fix flaky test-dgram-exclusive-implicit-bind #10212
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
test-dgram-exclusive-implicit-bind is written assuming that dgram messages are received with 100% reliability. While missing a dgram message sent to localhost is rare, we do see it as evidenced by CI failures from time to time. The test has been rewritten to send dgram messages over and over until the test requirements have been met. Additional incidental refactoring includes: * var -> const * use of common.mustCall() instead of exit listener + boolean
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,10 +20,10 @@ | |
| // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | ||
| // USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
|
|
||
| var common = require('../common'); | ||
| var assert = require('assert'); | ||
| var cluster = require('cluster'); | ||
| var dgram = require('dgram'); | ||
| const common = require('../common'); | ||
| const assert = require('assert'); | ||
| const cluster = require('cluster'); | ||
| const dgram = require('dgram'); | ||
|
|
||
| // Without an explicit bind, send() causes an implicit bind, which always | ||
| // generate a unique per-socket ephemeral port. An explicit bind to a port | ||
|
|
@@ -40,17 +40,21 @@ var dgram = require('dgram'); | |
| // with ENOTSUP. | ||
|
|
||
| if (cluster.isMaster) { | ||
| var pass; | ||
| var messages = 0; | ||
| var ports = {}; | ||
|
|
||
| process.on('exit', function() { | ||
| assert.strictEqual(pass, true); | ||
| }); | ||
| const ports = {}; | ||
| const pids = []; | ||
|
|
||
| var target = dgram.createSocket('udp4'); | ||
|
|
||
| const done = common.mustCall(function() { | ||
| cluster.disconnect(); | ||
| target.close(); | ||
| }); | ||
|
|
||
| target.on('message', function(buf, rinfo) { | ||
| if (pids.includes(buf.toString())) | ||
| return; | ||
| pids.push(buf.toString()); | ||
| messages++; | ||
| ports[rinfo.port] = true; | ||
|
|
||
|
|
@@ -63,12 +67,6 @@ if (cluster.isMaster) { | |
| assert.strictEqual(Object.keys(ports).length, 3); | ||
| done(); | ||
| } | ||
|
|
||
| function done() { | ||
| pass = true; | ||
| cluster.disconnect(); | ||
| target.close(); | ||
| } | ||
| }); | ||
|
|
||
| target.on('listening', function() { | ||
|
|
@@ -85,7 +83,12 @@ if (cluster.isMaster) { | |
| return; | ||
| } | ||
|
|
||
| var source = dgram.createSocket('udp4'); | ||
| const source = dgram.createSocket('udp4'); | ||
| var timer; | ||
|
|
||
| source.on('close', function() { | ||
| clearTimeout(timer); | ||
| }); | ||
|
|
||
| if (process.env.BOUND === 'y') { | ||
| source.bind(0); | ||
|
|
@@ -96,4 +99,12 @@ if (process.env.BOUND === 'y') { | |
| source.unref(); | ||
| } | ||
|
|
||
| source.send(Buffer.from('abc'), 0, 3, common.PORT, '127.0.0.1'); | ||
| function send() { | ||
|
Contributor
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. Could all of this just be simplified to: setInterval(() => {
source.send(Buffer.from('abc'), 0, 3, common.PORT, '127.0.0.1');
}, 1).unref();I think you shouldn't have to worry about clearing the interval if you unref it. That would reduce some complexity.
Member
Author
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 was concerned that competing 1ms interval timers on some operating systems could result in increased flakiness, but I didn't actually test it, so yeah, let's try that. :-D
Member
Author
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. If I don't keep the timer-clearing logic, this happens: Error: Not running
at Socket._healthCheck (dgram.js:527:11)
at Socket.send (dgram.js:347:8)
at Timeout.setInterval [as _onTimeout] (/Users/trott/io.js/test/parallel/test-dgram-exclusive-implicit-bind.js:104:10)
at ontimeout (timers.js:365:14)
at Timer.unrefdHandle (timers.js:471:5)
dgram.js:527
throw new Error('Not running'); // error message from dgram_legacy.js
^ |
||
| const buf = Buffer.from(process.pid.toString()); | ||
| timer = setTimeout(function() { | ||
| source.send(buf, common.PORT, '127.0.0.1', send); | ||
| }, 1); | ||
| timer.unref(); | ||
| } | ||
|
|
||
| send(); | ||
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.
From a previous comment I'm not sure this was a problem but can't you get rid of this as the interval is already unrefed? At least locally it works for me
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.
If I remove that line, the test still passes, but it produces a messy output that looks like it's failing:
I'd prefer the processes clean up after themselves and not generate irrelevant errors like that, even if the errors don't cause the test to fail, so I'd prefer to keep the
clearInterval()call.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.
Understood