Skip to content

Commit 3da56ac

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

File tree

2 files changed

+125
-31
lines changed

2 files changed

+125
-31
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+
}

test/sequential/test-dgram-bind-shared-ports.js

+69-31
Original file line numberDiff line numberDiff line change
@@ -21,55 +21,93 @@
2121

2222
'use strict';
2323
const common = require('../common');
24+
25+
// This test asserts the semantics of dgram::socket.bind({ exclusive })
26+
// when called from a cluster.Worker
27+
2428
const assert = require('assert');
2529
const cluster = require('cluster');
2630
const dgram = require('dgram');
31+
const BYE = 'bye';
32+
const WORKER2_NAME = 'wrker2';
2733

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

3137
if (common.isWindows) {
32-
const checkErrType = (er) => {
33-
assert.strictEqual(er.code, 'ENOTSUP');
38+
worker1.on('error', common.mustCall((err) => {
39+
console.log(err);
40+
assert.strictEqual(err.code, 'ENOTSUP');
3441
worker1.kill();
35-
};
36-
37-
worker1.on('error', common.mustCall(checkErrType, 1));
42+
}));
3843
return;
3944
}
4045

41-
worker1.on('message', (msg) => {
46+
worker1.on('message', common.mustCall((msg) => {
47+
console.log(msg);
4248
assert.strictEqual(msg, 'success');
43-
const worker2 = cluster.fork();
4449

45-
worker2.on('message', (msg) => {
46-
assert.strictEqual(msg, 'socket2:EADDRINUSE');
47-
worker1.kill();
48-
worker2.kill();
49-
});
50-
});
50+
const worker2 = cluster.fork({ WORKER2_NAME });
51+
worker2.on('message', common.mustCall((msg) => {
52+
console.log(msg);
53+
assert.strictEqual(msg, 'socket3:EADDRINUSE');
54+
55+
// finish test
56+
worker1.send(BYE);
57+
worker2.send(BYE);
58+
}));
59+
worker2.on('exit', common.mustCall((code, signal) => {
60+
assert.strictEqual(signal, null);
61+
assert.strictEqual(code, 0);
62+
}));
63+
}));
64+
worker1.on('exit', common.mustCall((code, signal) => {
65+
assert.strictEqual(signal, null);
66+
assert.strictEqual(code, 0);
67+
}));
68+
// end master code
5169
} else {
52-
const socket1 = dgram.createSocket('udp4', common.noop);
53-
const socket2 = dgram.createSocket('udp4', common.noop);
70+
// worker code
71+
process.on('message', common.mustCallAtLeast((msg) => {
72+
if (msg === BYE) process.exit(0);
73+
}), 1);
5474

55-
socket1.on('error', (err) => {
56-
// no errors expected
57-
process.send(`socket1:${err.code}`);
58-
});
75+
const isSecondWorker = process.env.WORKER2_NAME === WORKER2_NAME;
76+
const socket1 = dgram.createSocket('udp4', common.mustNotCall());
77+
const socket2 = dgram.createSocket('udp4', common.mustNotCall());
78+
const socket3 = dgram.createSocket('udp4', common.mustNotCall());
5979

60-
socket2.on('error', (err) => {
61-
// an error is expected on the second worker
62-
process.send(`socket2:${err.code}`);
63-
});
80+
socket1.on('error', (err) => assert.fail(err));
81+
socket2.on('error', (err) => assert.fail(err));
6482

65-
socket1.bind({
66-
address: 'localhost',
67-
port: common.PORT,
68-
exclusive: false
69-
}, () => {
70-
socket2.bind({ port: common.PORT + 1, exclusive: true }, () => {
71-
// the first worker should succeed
83+
// First worker should bind, second should err
84+
const socket3OnBind =
85+
isSecondWorker ?
86+
common.mustNotCall() :
87+
common.mustCall(() => {
88+
const port3 = socket3.address().port;
89+
assert.strictEqual(typeof port3, 'number');
7290
process.send('success');
7391
});
74-
});
92+
// an error is expected only in the second worker
93+
const socket3OnError =
94+
!isSecondWorker ?
95+
common.mustNotCall() :
96+
common.mustCall((err) => {
97+
process.send(`socket3:${err.code}`);
98+
});
99+
const address = common.localhostIPv4;
100+
const opt1 = { address, port: 0, exclusive: false };
101+
const opt2 = { address, port: common.PORT, exclusive: false };
102+
const opt3 = { address, port: common.PORT + 1, exclusive: true };
103+
socket1.bind(opt1, common.mustCall(() => {
104+
const port1 = socket1.address().port;
105+
assert.strictEqual(typeof port1, 'number');
106+
socket2.bind(opt2, common.mustCall(() => {
107+
const port2 = socket2.address().port;
108+
assert.strictEqual(typeof port2, 'number');
109+
socket3.on('error', socket3OnError);
110+
socket3.bind(opt3, socket3OnBind);
111+
}));
112+
}));
75113
}

0 commit comments

Comments
 (0)