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

test: kill subprocess only after last ACK #15186

Merged
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
64 changes: 47 additions & 17 deletions test/parallel/test-child-process-send-returns-boolean.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,58 @@
'use strict';
const common = require('../common');

// subprocess.send() will return false if the channel has closed or when the
// backlog of unsent messages exceeds a threshold that makes it unwise to send
// more. Otherwise, the method returns true.

const assert = require('assert');
const net = require('net');
const { fork, spawn } = require('child_process');
const fixtures = require('../common/fixtures');

const emptyFile = fixtures.path('empty.js');
// Just a script that stays alive (does not listen to `process.on('message')`).
const subScript = fixtures.path('child-process-persistent.js');

{
// Test `send` return value on `fork` that opens and IPC by deafult.
const n = fork(subScript);
// `subprocess.send` should always return `true` for the first send.
const rv = n.send({ h: 'w' }, (err) => { if (err) assert.fail(err); });
assert.strictEqual(rv, true);
n.kill();
}

const n = fork(emptyFile);
{
// Test `send` return value on `spawn` and saturate backlog with handles.
// Call `spawn` with options that open an IPC channel.
const spawnOptions = { stdio: ['pipe', 'pipe', 'pipe', 'ipc'] };
const s = spawn(process.execPath, [subScript], spawnOptions);

const rv = n.send({ hello: 'world' });
assert.strictEqual(rv, true);
const server = net.createServer(common.mustNotCall()).listen(0, () => {
const handle = server._handle;

const spawnOptions = { stdio: ['pipe', 'pipe', 'pipe', 'ipc'] };
const s = spawn(process.execPath, [emptyFile], spawnOptions);
let handle = null;
s.on('exit', function() {
handle.close();
});
// Sending a handle and not giving the tickQueue time to acknoladge should
// create the internal backlog, but leave it empty.
const rv1 = s.send('one', handle, (err) => { if (err) assert.fail(err); });
assert.strictEqual(rv1, true);
// Since the first `send` included a handle (should be unackoladged),
// we can safly queue up only one more message.
const rv2 = s.send('two', (err) => { if (err) assert.fail(err); });
assert.strictEqual(rv2, true);
// The backlog should now be indicate to backoff.
const rv3 = s.send('three', (err) => { if (err) assert.fail(err); });
assert.strictEqual(rv3, false);
const rv4 = s.send('four', (err) => {
if (err) assert.fail(err);
// `send` queue should have been drained.
const rv5 = s.send('5', handle, (err) => { if (err) assert.fail(err); });
assert.strictEqual(rv5, true);

net.createServer(common.mustNotCall()).listen(0, function() {
handle = this._handle;
assert.strictEqual(s.send('one', handle), true);
assert.strictEqual(s.send('two', handle), true);
assert.strictEqual(s.send('three'), false);
assert.strictEqual(s.send('four'), false);
});
// End test and cleanup.
s.kill();
handle.close();
server.close();
});
assert.strictEqual(rv4, false);
});
}