test: refacor spawn[Sync]Pwd
* extract the gist into common.pwdCommand * Merge test-child-process-buffering.js into test-child-process-stdio.js PR-URL: https://github.com/nodejs/node/pull/22522 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
parent
6a689c8aa3
commit
8569f4a417
@ -317,6 +317,17 @@ A port number for tests to use if one is needed.
|
|||||||
|
|
||||||
Logs '1..0 # Skipped: ' + `msg`
|
Logs '1..0 # Skipped: ' + `msg`
|
||||||
|
|
||||||
|
### pwdCommand
|
||||||
|
* [<array>] First two argument for the `spawn`/`exec` functions.
|
||||||
|
|
||||||
|
Platform normalized `pwd` command options. Usage example:
|
||||||
|
```js
|
||||||
|
const common = require('../common');
|
||||||
|
const { spawn } = require('child_process');
|
||||||
|
|
||||||
|
spawn(...common.pwdCommand, { stdio: ['pipe'] });
|
||||||
|
```
|
||||||
|
|
||||||
### rootDir
|
### rootDir
|
||||||
* [<string>]
|
* [<string>]
|
||||||
|
|
||||||
@ -350,18 +361,6 @@ was disabled at compile time.
|
|||||||
Skip the rest of the tests in the current file when the Node.js executable
|
Skip the rest of the tests in the current file when the Node.js executable
|
||||||
was compiled with a pointer size smaller than 64 bits.
|
was compiled with a pointer size smaller than 64 bits.
|
||||||
|
|
||||||
### spawnPwd(options)
|
|
||||||
* `options` [<Object>]
|
|
||||||
* return [<Object>]
|
|
||||||
|
|
||||||
Platform normalizes the `pwd` command.
|
|
||||||
|
|
||||||
### spawnSyncPwd(options)
|
|
||||||
* `options` [<Object>]
|
|
||||||
* return [<Object>]
|
|
||||||
|
|
||||||
Synchronous version of `spawnPwd`.
|
|
||||||
|
|
||||||
## ArrayStream Module
|
## ArrayStream Module
|
||||||
|
|
||||||
The `ArrayStream` module provides a simple `Stream` that pushes elements from
|
The `ArrayStream` module provides a simple `Stream` that pushes elements from
|
||||||
|
@ -26,7 +26,7 @@ const path = require('path');
|
|||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const { exec, execSync, spawn, spawnSync } = require('child_process');
|
const { exec, execSync, spawnSync } = require('child_process');
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
const { fixturesDir } = require('./fixtures');
|
const { fixturesDir } = require('./fixtures');
|
||||||
const tmpdir = require('./tmpdir');
|
const tmpdir = require('./tmpdir');
|
||||||
@ -268,23 +268,11 @@ exports.ddCommand = function(filename, kilobytes) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
exports.spawnPwd = function(options) {
|
exports.pwdCommand = exports.isWindows ?
|
||||||
if (exports.isWindows) {
|
['cmd.exe', ['/d', '/c', 'cd']] :
|
||||||
return spawn('cmd.exe', ['/d', '/c', 'cd'], options);
|
['pwd', []];
|
||||||
} else {
|
|
||||||
return spawn('pwd', [], options);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
exports.spawnSyncPwd = function(options) {
|
|
||||||
if (exports.isWindows) {
|
|
||||||
return spawnSync('cmd.exe', ['/d', '/c', 'cd'], options);
|
|
||||||
} else {
|
|
||||||
return spawnSync('pwd', [], options);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
exports.platformTimeout = function(ms) {
|
exports.platformTimeout = function(ms) {
|
||||||
if (process.features.debug)
|
if (process.features.debug)
|
||||||
ms = 2 * ms;
|
ms = 2 * ms;
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
// Copyright Joyent, Inc. and other Node contributors.
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
||||||
// copy of this software and associated documentation files (the
|
|
||||||
// "Software"), to deal in the Software without restriction, including
|
|
||||||
// without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
||||||
// persons to whom the Software is furnished to do so, subject to the
|
|
||||||
// following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included
|
|
||||||
// in all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
||||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
||||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
||||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
||||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
||||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
const common = require('../common');
|
|
||||||
const assert = require('assert');
|
|
||||||
|
|
||||||
function pwd(callback) {
|
|
||||||
let output = '';
|
|
||||||
const child = common.spawnPwd();
|
|
||||||
|
|
||||||
child.stdout.setEncoding('utf8');
|
|
||||||
child.stdout.on('data', function(s) {
|
|
||||||
console.log(`stdout: ${JSON.stringify(s)}`);
|
|
||||||
output += s;
|
|
||||||
});
|
|
||||||
|
|
||||||
child.on('exit', common.mustCall(function(c) {
|
|
||||||
console.log(`exit: ${c}`);
|
|
||||||
assert.strictEqual(0, c);
|
|
||||||
}));
|
|
||||||
|
|
||||||
child.on('close', common.mustCall(function() {
|
|
||||||
callback(output);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pwd(function(result) {
|
|
||||||
console.dir(result);
|
|
||||||
assert.strictEqual(true, result.length > 1);
|
|
||||||
assert.strictEqual('\n', result[result.length - 1]);
|
|
||||||
});
|
|
@ -2,19 +2,22 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const { spawnSync } = require('child_process');
|
||||||
const internalCp = require('internal/child_process');
|
const internalCp = require('internal/child_process');
|
||||||
const oldSpawnSync = internalCp.spawnSync;
|
|
||||||
|
|
||||||
if (!common.isMainThread)
|
if (!common.isMainThread)
|
||||||
common.skip('stdio is not associated with file descriptors in Workers');
|
common.skip('stdio is not associated with file descriptors in Workers');
|
||||||
|
|
||||||
// Verify that customFds is used if stdio is not provided.
|
// This test uses the deprecated `customFds` option. We expect a deprecation
|
||||||
{
|
// warning, but only once (per node process).
|
||||||
const msg = 'child_process: options.customFds option is deprecated. ' +
|
const msg = 'child_process: options.customFds option is deprecated. ' +
|
||||||
'Use options.stdio instead.';
|
'Use options.stdio instead.';
|
||||||
common.expectWarning('DeprecationWarning', msg, 'DEP0006');
|
common.expectWarning('DeprecationWarning', msg, 'DEP0006');
|
||||||
|
|
||||||
|
// Verify that customFds is used if stdio is not provided.
|
||||||
|
{
|
||||||
const customFds = [-1, process.stdout.fd, process.stderr.fd];
|
const customFds = [-1, process.stdout.fd, process.stderr.fd];
|
||||||
|
const oldSpawnSync = internalCp.spawnSync;
|
||||||
internalCp.spawnSync = common.mustCall(function(opts) {
|
internalCp.spawnSync = common.mustCall(function(opts) {
|
||||||
assert.deepStrictEqual(opts.options.customFds, customFds);
|
assert.deepStrictEqual(opts.options.customFds, customFds);
|
||||||
assert.deepStrictEqual(opts.options.stdio, [
|
assert.deepStrictEqual(opts.options.stdio, [
|
||||||
@ -23,13 +26,14 @@ if (!common.isMainThread)
|
|||||||
{ type: 'fd', fd: process.stderr.fd }
|
{ type: 'fd', fd: process.stderr.fd }
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
common.spawnSyncPwd({ customFds });
|
spawnSync(...common.pwdCommand, { customFds });
|
||||||
internalCp.spawnSync = oldSpawnSync;
|
internalCp.spawnSync = oldSpawnSync;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that customFds is ignored when stdio is present.
|
// Verify that customFds is ignored when stdio is present.
|
||||||
{
|
{
|
||||||
const customFds = [0, 1, 2];
|
const customFds = [0, 1, 2];
|
||||||
|
const oldSpawnSync = internalCp.spawnSync;
|
||||||
internalCp.spawnSync = common.mustCall(function(opts) {
|
internalCp.spawnSync = common.mustCall(function(opts) {
|
||||||
assert.deepStrictEqual(opts.options.customFds, customFds);
|
assert.deepStrictEqual(opts.options.customFds, customFds);
|
||||||
assert.deepStrictEqual(opts.options.stdio, [
|
assert.deepStrictEqual(opts.options.stdio, [
|
||||||
@ -38,6 +42,6 @@ if (!common.isMainThread)
|
|||||||
{ type: 'pipe', readable: false, writable: true }
|
{ type: 'pipe', readable: false, writable: true }
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
common.spawnSyncPwd({ customFds, stdio: 'pipe' });
|
spawnSync(...common.pwdCommand, { customFds, stdio: 'pipe' });
|
||||||
internalCp.spawnSync = oldSpawnSync;
|
internalCp.spawnSync = oldSpawnSync;
|
||||||
}
|
}
|
||||||
|
@ -22,47 +22,37 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const { spawn } = require('child_process');
|
||||||
let returns = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Spawns 'pwd' with given options, then test
|
Spawns 'pwd' with given options, then test
|
||||||
- whether the exit code equals forCode,
|
- whether the exit code equals expectCode,
|
||||||
- optionally whether the stdout result matches forData
|
- optionally whether the trimmed stdout result matches expectData
|
||||||
(after removing trailing whitespace)
|
|
||||||
*/
|
*/
|
||||||
function testCwd(options, forCode, forData) {
|
function testCwd(options, expectCode = 0, expectData) {
|
||||||
let data = '';
|
const child = spawn(...common.pwdCommand, options);
|
||||||
|
|
||||||
const child = common.spawnPwd(options);
|
|
||||||
|
|
||||||
child.stdout.setEncoding('utf8');
|
child.stdout.setEncoding('utf8');
|
||||||
|
|
||||||
|
// No need to assert callback since `data` is asserted.
|
||||||
|
let data = '';
|
||||||
child.stdout.on('data', function(chunk) {
|
child.stdout.on('data', function(chunk) {
|
||||||
data += chunk;
|
data += chunk;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Can't assert callback, as stayed in to API:
|
||||||
|
// _The 'exit' event may or may not fire after an error has occurred._
|
||||||
child.on('exit', function(code, signal) {
|
child.on('exit', function(code, signal) {
|
||||||
assert.strictEqual(forCode, code);
|
assert.strictEqual(expectCode, code);
|
||||||
});
|
});
|
||||||
|
|
||||||
child.on('close', function() {
|
child.on('close', common.mustCall(function() {
|
||||||
forData && assert.strictEqual(forData, data.replace(/[\s\r\n]+$/, ''));
|
expectData && assert.strictEqual(data.trim(), expectData);
|
||||||
returns--;
|
}));
|
||||||
});
|
|
||||||
|
|
||||||
returns++;
|
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assume these exist, and 'pwd' gives us the right directory back
|
|
||||||
testCwd({ cwd: common.rootDir }, 0, common.rootDir);
|
|
||||||
if (common.isWindows) {
|
|
||||||
testCwd({ cwd: process.env.windir }, 0, process.env.windir);
|
|
||||||
} else {
|
|
||||||
testCwd({ cwd: '/dev' }, 0, '/dev');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assume does-not-exist doesn't exist, expect exitCode=-1 and errno=ENOENT
|
// Assume does-not-exist doesn't exist, expect exitCode=-1 and errno=ENOENT
|
||||||
{
|
{
|
||||||
@ -72,15 +62,12 @@ if (common.isWindows) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn() shouldn't try to chdir() so this should just work
|
// Assume these exist, and 'pwd' gives us the right directory back
|
||||||
testCwd(undefined, 0);
|
testCwd({ cwd: common.rootDir }, 0, common.rootDir);
|
||||||
testCwd({}, 0);
|
const shouldExistDir = common.isWindows ? process.env.windir : '/dev';
|
||||||
testCwd({ cwd: '' }, 0);
|
testCwd({ cwd: shouldExistDir }, 0, shouldExistDir);
|
||||||
testCwd({ cwd: undefined }, 0);
|
|
||||||
testCwd({ cwd: null }, 0);
|
|
||||||
|
|
||||||
// Check whether all tests actually returned
|
// Spawn() shouldn't try to chdir() to invalid arg, so this should just work
|
||||||
assert.notStrictEqual(returns, 0);
|
testCwd({ cwd: '' });
|
||||||
process.on('exit', function() {
|
testCwd({ cwd: undefined });
|
||||||
assert.strictEqual(returns, 0);
|
testCwd({ cwd: null });
|
||||||
});
|
|
||||||
|
@ -22,10 +22,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
const { spawnSync } = require('child_process');
|
||||||
|
|
||||||
const spawnSync = require('child_process').spawnSync;
|
// `sleep` does different things on Windows and Unix, but in both cases, it does
|
||||||
|
|
||||||
// Echo does different things on Windows and Unix, but in both cases, it does
|
|
||||||
// more-or-less nothing if there are no parameters
|
// more-or-less nothing if there are no parameters
|
||||||
const ret = spawnSync('sleep', ['0']);
|
const ret = spawnSync('sleep', ['0']);
|
||||||
assert.strictEqual(ret.status, 0);
|
assert.strictEqual(ret.status, 0);
|
||||||
@ -42,21 +41,23 @@ assert.deepStrictEqual(ret_err.spawnargs, ['bar']);
|
|||||||
{
|
{
|
||||||
// Test the cwd option
|
// Test the cwd option
|
||||||
const cwd = common.rootDir;
|
const cwd = common.rootDir;
|
||||||
const response = common.spawnSyncPwd({ cwd });
|
const response = spawnSync(...common.pwdCommand, { cwd });
|
||||||
|
|
||||||
assert.strictEqual(response.stdout.toString().trim(), cwd);
|
assert.strictEqual(response.stdout.toString().trim(), cwd);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
// Test the encoding option
|
|
||||||
const noEncoding = common.spawnSyncPwd();
|
|
||||||
const bufferEncoding = common.spawnSyncPwd({ encoding: 'buffer' });
|
|
||||||
const utf8Encoding = common.spawnSyncPwd({ encoding: 'utf8' });
|
|
||||||
|
|
||||||
assert.deepStrictEqual(noEncoding.output, bufferEncoding.output);
|
{
|
||||||
assert.deepStrictEqual([
|
// Assert Buffer is the default encoding
|
||||||
|
const retDefault = spawnSync(...common.pwdCommand);
|
||||||
|
const retBuffer = spawnSync(...common.pwdCommand, { encoding: 'buffer' });
|
||||||
|
assert.deepStrictEqual(retDefault.output, retBuffer.output);
|
||||||
|
|
||||||
|
const retUTF8 = spawnSync(...common.pwdCommand, { encoding: 'utf8' });
|
||||||
|
const stringifiedDefault = [
|
||||||
null,
|
null,
|
||||||
noEncoding.stdout.toString(),
|
retDefault.stdout.toString(),
|
||||||
noEncoding.stderr.toString()
|
retDefault.stderr.toString()
|
||||||
], utf8Encoding.output);
|
];
|
||||||
|
assert.deepStrictEqual(retUTF8.output, stringifiedDefault);
|
||||||
}
|
}
|
||||||
|
@ -22,24 +22,56 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const spawnSync = require('child_process').spawnSync;
|
const { spawn } = require('child_process');
|
||||||
|
|
||||||
let options = { stdio: ['pipe'] };
|
|
||||||
let child = common.spawnPwd(options);
|
|
||||||
|
|
||||||
|
// Test stdio piping.
|
||||||
|
{
|
||||||
|
const child = spawn(...common.pwdCommand, { stdio: ['pipe'] });
|
||||||
assert.notStrictEqual(child.stdout, null);
|
assert.notStrictEqual(child.stdout, null);
|
||||||
assert.notStrictEqual(child.stderr, null);
|
assert.notStrictEqual(child.stderr, null);
|
||||||
|
}
|
||||||
|
|
||||||
options = { stdio: 'ignore' };
|
// Test stdio ignoring.
|
||||||
child = common.spawnPwd(options);
|
{
|
||||||
|
const child = spawn(...common.pwdCommand, { stdio: 'ignore' });
|
||||||
assert.strictEqual(child.stdout, null);
|
assert.strictEqual(child.stdout, null);
|
||||||
assert.strictEqual(child.stderr, null);
|
assert.strictEqual(child.stderr, null);
|
||||||
|
}
|
||||||
|
|
||||||
options = { stdio: 'ignore' };
|
// Asset options invariance.
|
||||||
child = spawnSync('cat', [], options);
|
{
|
||||||
|
const options = { stdio: 'ignore' };
|
||||||
|
spawn(...common.pwdCommand, options);
|
||||||
assert.deepStrictEqual(options, { stdio: 'ignore' });
|
assert.deepStrictEqual(options, { stdio: 'ignore' });
|
||||||
|
}
|
||||||
|
|
||||||
common.expectsError(() => {
|
// Test stdout buffering.
|
||||||
common.spawnPwd({ stdio: ['pipe', 'pipe', 'pipe', 'ipc', 'ipc'] });
|
{
|
||||||
}, { code: 'ERR_IPC_ONE_PIPE', type: Error });
|
let output = '';
|
||||||
|
const child = spawn(...common.pwdCommand);
|
||||||
|
|
||||||
|
child.stdout.setEncoding('utf8');
|
||||||
|
child.stdout.on('data', function(s) {
|
||||||
|
output += s;
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on('exit', common.mustCall(function(code) {
|
||||||
|
assert.strictEqual(code, 0);
|
||||||
|
}));
|
||||||
|
|
||||||
|
child.on('close', common.mustCall(function() {
|
||||||
|
assert.strictEqual(true, output.length > 1);
|
||||||
|
assert.strictEqual('\n', output[output.length - 1]);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert only one IPC pipe allowed.
|
||||||
|
common.expectsError(
|
||||||
|
() => {
|
||||||
|
spawn(
|
||||||
|
...common.pwdCommand,
|
||||||
|
{ stdio: ['pipe', 'pipe', 'pipe', 'ipc', 'ipc'] }
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ code: 'ERR_IPC_ONE_PIPE', type: Error }
|
||||||
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user