Skip to content

Commit a1cef1f

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 f578c9b commit a1cef1f

File tree

2 files changed

+128
-36
lines changed

2 files changed

+128
-36
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,92 @@
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');
6-
7-
function noop() { }
10+
const BYE = 'bye';
11+
const WORKER2_NAME = 'wrker2';
812

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

1216
if (common.isWindows) {
13-
const checkErrType = (er) => {
14-
assert.strictEqual(er.code, 'ENOTSUP');
17+
worker1.on('error', common.mustCall((err) => {
18+
console.log(err);
19+
assert.strictEqual(err.code, 'ENOTSUP');
1520
worker1.kill();
16-
};
17-
18-
worker1.on('error', common.mustCall(checkErrType, 1));
21+
}));
1922
return;
2023
}
2124

22-
worker1.on('message', (msg) => {
25+
worker1.on('message', common.mustCall((msg) => {
26+
console.log(msg);
2327
assert.strictEqual(msg, 'success');
24-
const worker2 = cluster.fork();
2528

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

0 commit comments

Comments
 (0)