Skip to content

Commit 0f879f4

Browse files
authored
Use advanced serialization (when available) for worker communication
* Use advanced serialization (when available) for test worker communication Use advanced IPC on 12.17.0. This is currently our future minimal Node.js 12 version. * Buffer IPC sends to avoid crashes Workaround for nodejs/node#34797 * Tweak reporter integration tests Maybe it's the IPC changes, but they started to fail on Windows.
1 parent 20bc781 commit 0f879f4

15 files changed

+89
-41
lines changed

lib/cli.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ exports.run = async () => { // eslint-disable-line complexity
428428
reporter.startRun(plan);
429429

430430
if (process.env.AVA_EMIT_RUN_STATUS_OVER_IPC === 'I\'ll find a payphone baby / Take some time to talk to you') {
431-
if (process.versions.node >= '12.16.0') {
431+
if (process.versions.node >= '12.17.0') {
432432
plan.status.on('stateChange', evt => {
433433
process.send(evt);
434434
});

lib/fork.js

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const childProcess = require('child_process');
33
const path = require('path');
44
const fs = require('fs');
55
const Emittery = require('emittery');
6+
const {controlFlow} = require('./ipc-flow-control');
67

78
if (fs.realpathSync(__filename) !== __filename) {
89
console.warn('WARNING: `npm link ava` and the `--preserve-symlink` flag are incompatible. We have detected that AVA is linked via `npm link`, and that you are using either an early version of Node 6, or the `--preserve-symlink` flag. This breaks AVA. You should upgrade to Node 6.2.0+, avoid the `--preserve-symlink` flag, or avoid using `npm link ava`.');
@@ -14,6 +15,12 @@ const AVA_PATH = path.resolve(__dirname, '..');
1415

1516
const workerPath = require.resolve('./worker/subprocess');
1617

18+
const useAdvanced = process.versions.node >= '12.17.0';
19+
// FIXME: Fix this in api.js or cli.js.
20+
const serializeOptions = useAdvanced ?
21+
options => JSON.parse(JSON.stringify(options)) : // Use JSON serialization to remove non-clonable values.
22+
options => options;
23+
1724
module.exports = (file, options, execArgv = process.execArgv) => {
1825
let finished = false;
1926

@@ -34,7 +41,8 @@ module.exports = (file, options, execArgv = process.execArgv) => {
3441
cwd: options.projectDir,
3542
silent: true,
3643
env: {NODE_ENV: 'test', ...process.env, ...options.environmentVariables, AVA_PATH},
37-
execArgv
44+
execArgv,
45+
serialization: useAdvanced ? 'advanced' : 'json'
3846
});
3947

4048
subprocess.stdout.on('data', chunk => {
@@ -45,12 +53,12 @@ module.exports = (file, options, execArgv = process.execArgv) => {
4553
emitStateChange({type: 'worker-stderr', chunk});
4654
});
4755

56+
const bufferedSend = controlFlow(subprocess);
57+
4858
let forcedExit = false;
4959
const send = evt => {
50-
if (subprocess.connected && !finished && !forcedExit) {
51-
subprocess.send({ava: evt}, () => {
52-
// Disregard errors.
53-
});
60+
if (!finished && !forcedExit) {
61+
bufferedSend({ava: evt});
5462
}
5563
};
5664

@@ -66,7 +74,7 @@ module.exports = (file, options, execArgv = process.execArgv) => {
6674
}
6775

6876
if (message.ava.type === 'ready-for-options') {
69-
send({type: 'options', options});
77+
send({type: 'options', options: serializeOptions(options)});
7078
return;
7179
}
7280

lib/ipc-flow-control.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Manage how quickly messages are delivered to the channel. In theory, we
2+
// should be able to call `send()` until it returns `false` but this leads to
3+
// crashes with advanced serialization, see
4+
// <https://github.com/nodejs/node/issues/34797>.
5+
//
6+
// Even if that's fixed (and the Node.js versions with the fixes are the
7+
// minimally supported versions) we need flow control based on `send()`'s return
8+
// value.
9+
10+
function controlFlow(channel) {
11+
let sending = false;
12+
13+
const buffer = [];
14+
const deliverNext = () => {
15+
if (!channel.connected) {
16+
buffer.length = 0;
17+
}
18+
19+
if (buffer.length === 0) {
20+
sending = false;
21+
return;
22+
}
23+
24+
channel.send(buffer.shift(), deliverNext);
25+
};
26+
27+
return message => {
28+
if (!channel.connected) {
29+
return;
30+
}
31+
32+
buffer.push(message);
33+
if (!sending) {
34+
sending = true;
35+
setImmediate(deliverNext);
36+
}
37+
};
38+
}
39+
40+
exports.controlFlow = controlFlow;

lib/worker/ipc.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22
const Emittery = require('emittery');
3+
const {controlFlow} = require('../ipc-flow-control');
34

45
const emitter = new Emittery();
56
process.on('message', message => {
@@ -25,10 +26,9 @@ process.on('message', message => {
2526
exports.options = emitter.once('options');
2627
exports.peerFailed = emitter.once('peerFailed');
2728

29+
const bufferedSend = controlFlow(process);
2830
function send(evt) {
29-
if (process.connected) {
30-
process.send({ava: evt});
31-
}
31+
bufferedSend({ava: evt});
3232
}
3333

3434
exports.send = send;

test-tap/fixture/report/regular/uncaught-exception.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const test = require('../../../..');
22

33
test('passes', t => {
4-
setTimeout(() => {
4+
setImmediate(() => {
55
throw new Error('Can’t catch me');
66
});
77
t.pass();

test-tap/reporters/mini.regular.v10.log

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,13 +515,13 @@
515515

516516
uncaught-exception.js:5
517517

518-
4: setTimeout(() => {
518+
4: setImmediate(() => {
519519
 5: throw new Error('Can’t catch me');
520520
6: });
521521

522522
Error: Can’t catch me
523523

524-
› Timeout.setTimeout (test-tap/fixture/report/regular/uncaught-exception.js:5:9)
524+
› Immediate.setImmediate (test-tap/fixture/report/regular/uncaught-exception.js:5:9)
525525

526526

527527

test-tap/reporters/mini.regular.v12.log

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -497,15 +497,14 @@
497497

498498
uncaught-exception.js:5
499499

500-
4: setTimeout(() => {
500+
4: setImmediate(() => {
501501
 5: throw new Error('Can’t catch me');
502502
6: });
503503

504504
Error: Can’t catch me
505505

506-
› Timeout._onTimeout (test-tap/fixture/report/regular/uncaught-exception.js:5:9)
507-
› listOnTimeout (internal/timers.js:549:17)
508-
› processTimers (internal/timers.js:492:7)
506+
› Immediate.<anonymous> (test-tap/fixture/report/regular/uncaught-exception.js:5:9)
507+
› processImmediate (internal/timers.js:456:21)
509508

510509

511510

test-tap/reporters/mini.regular.v14.log

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -497,15 +497,14 @@
497497

498498
uncaught-exception.js:5
499499

500-
4: setTimeout(() => {
500+
4: setImmediate(() => {
501501
 5: throw new Error('Can’t catch me');
502502
6: });
503503

504504
Error: Can’t catch me
505505

506-
› Timeout._onTimeout (test-tap/fixture/report/regular/uncaught-exception.js:5:9)
507-
› listOnTimeout (internal/timers.js:551:17)
508-
› processTimers (internal/timers.js:494:7)
506+
› Immediate.<anonymous> (test-tap/fixture/report/regular/uncaught-exception.js:5:9)
507+
› processImmediate (internal/timers.js:458:21)
509508

510509

511510

test-tap/reporters/tap.regular.v10.log

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,9 @@ not ok 25 - Error: Can’t catch me
323323
---
324324
name: Error
325325
message: Can’t catch me
326-
at: 'Timeout.setTimeout (test-tap/fixture/report/regular/uncaught-exception.js:5:9)'
326+
at: >-
327+
Immediate.setImmediate
328+
(test-tap/fixture/report/regular/uncaught-exception.js:5:9)
327329
...
328330
---tty-stream-chunk-separator
329331
# uncaught-exception.js exited with a non-zero exit code: 1

test-tap/reporters/tap.regular.v12.log

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -296,10 +296,11 @@ not ok 25 - Error: Can’t catch me
296296
---
297297
name: Error
298298
message: Can’t catch me
299-
at: |-
300-
Timeout._onTimeout (test-tap/fixture/report/regular/uncaught-exception.js:5:9)
301-
listOnTimeout (internal/timers.js:549:17)
302-
processTimers (internal/timers.js:492:7)
299+
at: >-
300+
Immediate.<anonymous>
301+
(test-tap/fixture/report/regular/uncaught-exception.js:5:9)
302+
303+
processImmediate (internal/timers.js:456:21)
303304
...
304305
---tty-stream-chunk-separator
305306
# uncaught-exception.js exited with a non-zero exit code: 1

0 commit comments

Comments
 (0)