mirror of
https://github.com/nodejs/node.git
synced 2025-05-04 20:09:32 +00:00

Replaces expectSyncExit() and expectSyncExitWithoutError(). Since we usually just check the child process right after its spawned, these shorthands also takes care of the spawning. This makes the tests more concise. PR-URL: https://github.com/nodejs/node/pull/49200 Reviewed-By: LiviaMedeiros <livia@cirno.name> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
140 lines
4.0 KiB
JavaScript
140 lines
4.0 KiB
JavaScript
'use strict';
|
|
|
|
const assert = require('assert');
|
|
const { spawnSync, execFileSync } = require('child_process');
|
|
const common = require('./');
|
|
const util = require('util');
|
|
|
|
// Workaround for Windows Server 2008R2
|
|
// When CMD is used to launch a process and CMD is killed too quickly, the
|
|
// process can stay behind running in suspended state, never completing.
|
|
function cleanupStaleProcess(filename) {
|
|
if (!common.isWindows) {
|
|
return;
|
|
}
|
|
process.once('beforeExit', () => {
|
|
const basename = filename.replace(/.*[/\\]/g, '');
|
|
try {
|
|
execFileSync(`${process.env.SystemRoot}\\System32\\wbem\\WMIC.exe`, [
|
|
'process',
|
|
'where',
|
|
`commandline like '%${basename}%child'`,
|
|
'delete',
|
|
'/nointeractive',
|
|
]);
|
|
} catch {
|
|
// Ignore failures, there might not be any stale process to clean up.
|
|
}
|
|
});
|
|
}
|
|
|
|
// This should keep the child process running long enough to expire
|
|
// the timeout.
|
|
const kExpiringChildRunTime = common.platformTimeout(20 * 1000);
|
|
const kExpiringParentTimer = 1;
|
|
assert(kExpiringChildRunTime > kExpiringParentTimer);
|
|
|
|
function logAfterTime(time) {
|
|
setTimeout(() => {
|
|
// The following console statements are part of the test.
|
|
console.log('child stdout');
|
|
console.error('child stderr');
|
|
}, time);
|
|
}
|
|
|
|
function checkOutput(str, check) {
|
|
if ((check instanceof RegExp && !check.test(str)) ||
|
|
(typeof check === 'string' && check !== str)) {
|
|
return { passed: false, reason: `did not match ${util.inspect(check)}` };
|
|
}
|
|
if (typeof check === 'function') {
|
|
try {
|
|
check(str);
|
|
} catch (error) {
|
|
return {
|
|
passed: false,
|
|
reason: `did not match expectation, checker throws:\n${util.inspect(error)}`,
|
|
};
|
|
}
|
|
}
|
|
return { passed: true };
|
|
}
|
|
|
|
function expectSyncExit(child, {
|
|
status,
|
|
signal,
|
|
stderr: stderrCheck,
|
|
stdout: stdoutCheck,
|
|
trim = false,
|
|
}) {
|
|
const failures = [];
|
|
let stderrStr, stdoutStr;
|
|
if (status !== undefined && child.status !== status) {
|
|
failures.push(`- process terminated with status ${child.status}, expected ${status}`);
|
|
}
|
|
if (signal !== undefined && child.signal !== signal) {
|
|
failures.push(`- process terminated with signal ${child.signal}, expected ${signal}`);
|
|
}
|
|
|
|
function logAndThrow() {
|
|
const tag = `[process ${child.pid}]:`;
|
|
console.error(`${tag} --- stderr ---`);
|
|
console.error(stderrStr === undefined ? child.stderr.toString() : stderrStr);
|
|
console.error(`${tag} --- stdout ---`);
|
|
console.error(stdoutStr === undefined ? child.stdout.toString() : stdoutStr);
|
|
console.error(`${tag} status = ${child.status}, signal = ${child.signal}`);
|
|
throw new Error(`${failures.join('\n')}`);
|
|
}
|
|
|
|
// If status and signal are not matching expectations, fail early.
|
|
if (failures.length !== 0) {
|
|
logAndThrow();
|
|
}
|
|
|
|
if (stderrCheck !== undefined) {
|
|
stderrStr = child.stderr.toString();
|
|
const { passed, reason } = checkOutput(trim ? stderrStr.trim() : stderrStr, stderrCheck);
|
|
if (!passed) {
|
|
failures.push(`- stderr ${reason}`);
|
|
}
|
|
}
|
|
if (stdoutCheck !== undefined) {
|
|
stdoutStr = child.stdout.toString();
|
|
const { passed, reason } = checkOutput(trim ? stdoutStr.trim() : stdoutStr, stdoutCheck);
|
|
if (!passed) {
|
|
failures.push(`- stdout ${reason}`);
|
|
}
|
|
}
|
|
if (failures.length !== 0) {
|
|
logAndThrow();
|
|
}
|
|
return { child, stderr: stderrStr, stdout: stdoutStr };
|
|
}
|
|
|
|
function spawnSyncAndExit(...args) {
|
|
const spawnArgs = args.slice(0, args.length - 1);
|
|
const expectations = args[args.length - 1];
|
|
const child = spawnSync(...spawnArgs);
|
|
return expectSyncExit(child, expectations);
|
|
}
|
|
|
|
function spawnSyncAndExitWithoutError(...args) {
|
|
const spawnArgs = args.slice(0, args.length);
|
|
const expectations = args[args.length - 1];
|
|
const child = spawnSync(...spawnArgs);
|
|
return expectSyncExit(child, {
|
|
status: 0,
|
|
signal: null,
|
|
...expectations,
|
|
});
|
|
}
|
|
|
|
module.exports = {
|
|
cleanupStaleProcess,
|
|
logAfterTime,
|
|
kExpiringChildRunTime,
|
|
kExpiringParentTimer,
|
|
spawnSyncAndExit,
|
|
spawnSyncAndExitWithoutError,
|
|
};
|