Skip to content

Commit ac21bfd

Browse files
refackMylesBorins
authored andcommitted
test: harden test-dgram-bind-shared-ports
* add `mustCall` and `mustNotCall` to all callbacks * added `known_issue` for port binding Backport-PR-URL: #14327 PR-URL: #13100 Refs: #13055 Refs: #12999 Refs: #13526 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
1 parent ce86b8e commit ac21bfd

File tree

2 files changed

+128
-34
lines changed

2 files changed

+128
-34
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
'use strict';
2+
const common = require('../common');
3+
4+
// This test should fail because at present `cluster` does not know how to share
5+
// a socket when `worker1` binds with `port: 0`, and others try to bind to the
6+
// assigned port number from `worker1`
7+
//
8+
// *Note*: since this is a `known_issue` we try to swallow all errors except
9+
// the one we are interested in
10+
11+
const assert = require('assert');
12+
const cluster = require('cluster');
13+
const dgram = require('dgram');
14+
const BYE = 'bye';
15+
16+
if (cluster.isMaster) {
17+
const worker1 = cluster.fork();
18+
19+
// verify that Windows doesn't support this scenario
20+
worker1.on('error', (err) => {
21+
if (err.code === 'ENOTSUP') throw err;
22+
});
23+
24+
worker1.on('message', (msg) => {
25+
if (typeof msg !== 'object') process.exit(0);
26+
if (msg.message !== 'success') process.exit(0);
27+
if (typeof msg.port1 !== 'number') process.exit(0);
28+
29+
const worker2 = cluster.fork({ PRT1: msg.port1 });
30+
worker2.on('message', () => process.exit(0));
31+
worker2.on('exit', (code, signal) => {
32+
// this is the droid we are looking for
33+
assert.strictEqual(code, 0);
34+
assert.strictEqual(signal, null);
35+
});
36+
37+
// cleanup anyway
38+
process.on('exit', () => {
39+
worker1.send(BYE);
40+
worker2.send(BYE);
41+
});
42+
});
43+
// end master code
44+
} else {
45+
// worker code
46+
process.on('message', (msg) => msg === BYE && process.exit(0));
47+
48+
// first worker will bind to '0', second will try the assigned port and fail
49+
const PRT1 = process.env.PRT1 || 0;
50+
const socket1 = dgram.createSocket('udp4', () => {});
51+
socket1.on('error', PRT1 === 0 ? () => {} : assert.fail);
52+
socket1.bind(
53+
{ address: common.localhostIPv4, port: PRT1, exclusive: false },
54+
() => process.send({ message: 'success', port1: socket1.address().port })
55+
);
56+
}
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,94 @@
11
'use strict';
22
const common = require('../common');
3+
4+
// This test asserts the semantics of dgram::socket.bind({ exclusive })
5+
// when called from a cluster.Worker
6+
37
const assert = require('assert');
48
const cluster = require('cluster');
59
const dgram = require('dgram');
10+
const BYE = 'bye';
11+
const WORKER2_NAME = 'wrker2';
612

713
function noop() { }
814

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

1218
if (common.isWindows) {
13-
const checkErrType = (er) => {
14-
assert.strictEqual(er.code, 'ENOTSUP');
19+
worker1.on('error', common.mustCall((err) => {
20+
console.log(err);
21+
assert.strictEqual(err.code, 'ENOTSUP');
1522
worker1.kill();
16-
};
17-
18-
worker1.on('error', common.mustCall(checkErrType, 1));
23+
}));
1924
return;
2025
}
2126

22-
worker1.on('message', (msg) => {
27+
worker1.on('message', common.mustCall((msg) => {
28+
console.log(msg);
2329
assert.strictEqual(msg, 'success');
24-
const worker2 = cluster.fork();
2530

26-
worker2.on('message', (msg) => {
27-
assert.strictEqual(msg, 'socket2:EADDRINUSE');
28-
worker1.kill();
29-
worker2.kill();
30-
});
31-
});
31+
const worker2 = cluster.fork({ WORKER2_NAME });
32+
worker2.on('message', common.mustCall((msg) => {
33+
console.log(msg);
34+
assert.strictEqual(msg, 'socket3:EADDRINUSE');
35+
36+
// finish test
37+
worker1.send(BYE);
38+
worker2.send(BYE);
39+
}));
40+
worker2.on('exit', common.mustCall((code, signal) => {
41+
assert.strictEqual(signal, null);
42+
assert.strictEqual(code, 0);
43+
}));
44+
}));
45+
worker1.on('exit', common.mustCall((code, signal) => {
46+
assert.strictEqual(signal, null);
47+
assert.strictEqual(code, 0);
48+
}));
49+
// end master code
3250
} else {
33-
const socket1 = dgram.createSocket('udp4', noop);
34-
const socket2 = dgram.createSocket('udp4', noop);
35-
36-
socket1.on('error', (err) => {
37-
// no errors expected
38-
process.send(`socket1:${err.code}`);
39-
});
40-
41-
socket2.on('error', (err) => {
42-
// an error is expected on the second worker
43-
process.send(`socket2:${err.code}`);
44-
});
45-
46-
socket1.bind({
47-
address: 'localhost',
48-
port: common.PORT,
49-
exclusive: false
50-
}, () => {
51-
socket2.bind({ port: common.PORT + 1, exclusive: true }, () => {
52-
// the first worker should succeed
51+
// worker code
52+
process.on('message', common.mustCallAtLeast((msg) => {
53+
if (msg === BYE) process.exit(0);
54+
}), 1);
55+
56+
const isSecondWorker = process.env.WORKER2_NAME === WORKER2_NAME;
57+
const socket1 = dgram.createSocket('udp4', common.mustNotCall());
58+
const socket2 = dgram.createSocket('udp4', common.mustNotCall());
59+
const socket3 = dgram.createSocket('udp4', common.mustNotCall());
60+
61+
socket1.on('error', (err) => assert.fail(err));
62+
socket2.on('error', (err) => assert.fail(err));
63+
64+
// First worker should bind, second should err
65+
const socket3OnBind =
66+
isSecondWorker ?
67+
common.mustNotCall() :
68+
common.mustCall(() => {
69+
const port3 = socket3.address().port;
70+
assert.strictEqual(typeof port3, 'number');
5371
process.send('success');
5472
});
55-
});
73+
// an error is expected only in the second worker
74+
const socket3OnError =
75+
!isSecondWorker ?
76+
common.mustNotCall() :
77+
common.mustCall((err) => {
78+
process.send(`socket3:${err.code}`);
79+
});
80+
const address = common.localhostIPv4;
81+
const opt1 = { address, port: 0, exclusive: false };
82+
const opt2 = { address, port: common.PORT, exclusive: false };
83+
const opt3 = { address, port: common.PORT + 1, exclusive: true };
84+
socket1.bind(opt1, common.mustCall(() => {
85+
const port1 = socket1.address().port;
86+
assert.strictEqual(typeof port1, 'number');
87+
socket2.bind(opt2, common.mustCall(() => {
88+
const port2 = socket2.address().port;
89+
assert.strictEqual(typeof port2, 'number');
90+
socket3.on('error', socket3OnError);
91+
socket3.bind(opt3, socket3OnBind);
92+
}));
93+
}));
5694
}

0 commit comments

Comments
 (0)