Skip to content
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

[v6.x backport] test: harden test-dgram-bind-shared-ports #14327

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions test/known_issues/test-dgram-bind-shared-ports-after-port-0.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
'use strict';
const common = require('../common');

// This test should fail because at present `cluster` does not know how to share
// a socket when `worker1` binds with `port: 0`, and others try to bind to the
// assigned port number from `worker1`
//
// *Note*: since this is a `known_issue` we try to swallow all errors except
// the one we are interested in

const assert = require('assert');
const cluster = require('cluster');
const dgram = require('dgram');
const BYE = 'bye';

if (cluster.isMaster) {
const worker1 = cluster.fork();

// verify that Windows doesn't support this scenario
worker1.on('error', (err) => {
if (err.code === 'ENOTSUP') throw err;
});

worker1.on('message', (msg) => {
if (typeof msg !== 'object') process.exit(0);
if (msg.message !== 'success') process.exit(0);
if (typeof msg.port1 !== 'number') process.exit(0);

const worker2 = cluster.fork({ PRT1: msg.port1 });
worker2.on('message', () => process.exit(0));
worker2.on('exit', (code, signal) => {
// this is the droid we are looking for
assert.strictEqual(code, 0);
assert.strictEqual(signal, null);
});

// cleanup anyway
process.on('exit', () => {
worker1.send(BYE);
worker2.send(BYE);
});
});
// end master code
} else {
// worker code
process.on('message', (msg) => msg === BYE && process.exit(0));

// first worker will bind to '0', second will try the assigned port and fail
const PRT1 = process.env.PRT1 || 0;
const socket1 = dgram.createSocket('udp4', () => {});
socket1.on('error', PRT1 === 0 ? () => {} : assert.fail);
socket1.bind(
{ address: common.localhostIPv4, port: PRT1, exclusive: false },
() => process.send({ message: 'success', port1: socket1.address().port })
);
}
106 changes: 72 additions & 34 deletions test/sequential/test-dgram-bind-shared-ports.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,94 @@
'use strict';
const common = require('../common');

// This test asserts the semantics of dgram::socket.bind({ exclusive })
// when called from a cluster.Worker

const assert = require('assert');
const cluster = require('cluster');
const dgram = require('dgram');
const BYE = 'bye';
const WORKER2_NAME = 'wrker2';

function noop() { }

if (cluster.isMaster) {
const worker1 = cluster.fork();

if (common.isWindows) {
const checkErrType = (er) => {
assert.strictEqual(er.code, 'ENOTSUP');
worker1.on('error', common.mustCall((err) => {
console.log(err);
assert.strictEqual(err.code, 'ENOTSUP');
worker1.kill();
};

worker1.on('error', common.mustCall(checkErrType, 1));
}));
return;
}

worker1.on('message', (msg) => {
worker1.on('message', common.mustCall((msg) => {
console.log(msg);
assert.strictEqual(msg, 'success');
const worker2 = cluster.fork();

worker2.on('message', (msg) => {
assert.strictEqual(msg, 'socket2:EADDRINUSE');
worker1.kill();
worker2.kill();
});
});
const worker2 = cluster.fork({ WORKER2_NAME });
worker2.on('message', common.mustCall((msg) => {
console.log(msg);
assert.strictEqual(msg, 'socket3:EADDRINUSE');

// finish test
worker1.send(BYE);
worker2.send(BYE);
}));
worker2.on('exit', common.mustCall((code, signal) => {
assert.strictEqual(signal, null);
assert.strictEqual(code, 0);
}));
}));
worker1.on('exit', common.mustCall((code, signal) => {
assert.strictEqual(signal, null);
assert.strictEqual(code, 0);
}));
// end master code
} else {
const socket1 = dgram.createSocket('udp4', noop);
const socket2 = dgram.createSocket('udp4', noop);

socket1.on('error', (err) => {
// no errors expected
process.send(`socket1:${err.code}`);
});

socket2.on('error', (err) => {
// an error is expected on the second worker
process.send(`socket2:${err.code}`);
});

socket1.bind({
address: 'localhost',
port: common.PORT,
exclusive: false
}, () => {
socket2.bind({ port: common.PORT + 1, exclusive: true }, () => {
// the first worker should succeed
// worker code
process.on('message', common.mustCallAtLeast((msg) => {
if (msg === BYE) process.exit(0);
}), 1);

const isSecondWorker = process.env.WORKER2_NAME === WORKER2_NAME;
const socket1 = dgram.createSocket('udp4', common.mustNotCall());
const socket2 = dgram.createSocket('udp4', common.mustNotCall());
const socket3 = dgram.createSocket('udp4', common.mustNotCall());

socket1.on('error', (err) => assert.fail(err));
socket2.on('error', (err) => assert.fail(err));

// First worker should bind, second should err
const socket3OnBind =
isSecondWorker ?
common.mustNotCall() :
common.mustCall(() => {
const port3 = socket3.address().port;
assert.strictEqual(typeof port3, 'number');
process.send('success');
});
});
// an error is expected only in the second worker
const socket3OnError =
!isSecondWorker ?
common.mustNotCall() :
common.mustCall((err) => {
process.send(`socket3:${err.code}`);
});
const address = common.localhostIPv4;
const opt1 = { address, port: 0, exclusive: false };
const opt2 = { address, port: common.PORT, exclusive: false };
const opt3 = { address, port: common.PORT + 1, exclusive: true };
socket1.bind(opt1, common.mustCall(() => {
const port1 = socket1.address().port;
assert.strictEqual(typeof port1, 'number');
socket2.bind(opt2, common.mustCall(() => {
const port2 = socket2.address().port;
assert.strictEqual(typeof port2, 'number');
socket3.on('error', socket3OnError);
socket3.bind(opt3, socket3OnBind);
}));
}));
}