summaryrefslogtreecommitdiff
path: root/tests/node_compat/test/common
diff options
context:
space:
mode:
Diffstat (limited to 'tests/node_compat/test/common')
-rw-r--r--tests/node_compat/test/common/child_process.js106
-rw-r--r--tests/node_compat/test/common/index.js33
-rw-r--r--tests/node_compat/test/common/index.mjs132
-rw-r--r--tests/node_compat/test/common/tmpdir.js39
4 files changed, 228 insertions, 82 deletions
diff --git a/tests/node_compat/test/common/child_process.js b/tests/node_compat/test/common/child_process.js
index d46ec39d1..e30ec0c00 100644
--- a/tests/node_compat/test/common/child_process.js
+++ b/tests/node_compat/test/common/child_process.js
@@ -8,7 +8,9 @@
'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
@@ -20,14 +22,13 @@ function cleanupStaleProcess(filename) {
process.once('beforeExit', () => {
const basename = filename.replace(/.*[/\\]/g, '');
try {
- require('child_process')
- .execFileSync(`${process.env.SystemRoot}\\System32\\wbem\\WMIC.exe`, [
- 'process',
- 'where',
- `commandline like '%${basename}%child'`,
- 'delete',
- '/nointeractive',
- ]);
+ 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.
}
@@ -48,9 +49,98 @@ function logAfterTime(time) {
}, 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,
};
diff --git a/tests/node_compat/test/common/index.js b/tests/node_compat/test/common/index.js
index 9f5b4814c..2ebb22da2 100644
--- a/tests/node_compat/test/common/index.js
+++ b/tests/node_compat/test/common/index.js
@@ -11,10 +11,12 @@
*/
'use strict';
const assert = require("assert");
+const { spawn } = require('child_process');
const path = require("path");
const util = require("util");
const tmpdir = require("./tmpdir");
+
function platformTimeout(ms) {
return ms;
}
@@ -442,6 +444,36 @@ const pwdCommand = isWindows ?
['cmd.exe', ['/d', '/c', 'cd']] :
['pwd', []];
+ function spawnPromisified(...args) {
+ let stderr = '';
+ let stdout = '';
+
+ const child = spawn(...args);
+ child.stderr.setEncoding('utf8');
+ child.stderr.on('data', (data) => { stderr += data; });
+ child.stdout.setEncoding('utf8');
+ child.stdout.on('data', (data) => { stdout += data; });
+
+ return new Promise((resolve, reject) => {
+ child.on('close', (code, signal) => {
+ resolve({
+ code,
+ signal,
+ stderr,
+ stdout,
+ });
+ });
+ child.on('error', (code, signal) => {
+ reject({
+ code,
+ signal,
+ stderr,
+ stdout,
+ });
+ });
+ });
+ }
+
module.exports = {
allowGlobals,
expectsError,
@@ -464,6 +496,7 @@ module.exports = {
printSkipMessage,
pwdCommand,
skipIfDumbTerminal,
+ spawnPromisified,
isDumbTerminal,
isWindows,
isAIX,
diff --git a/tests/node_compat/test/common/index.mjs b/tests/node_compat/test/common/index.mjs
index d5473eaea..d9992e67d 100644
--- a/tests/node_compat/test/common/index.mjs
+++ b/tests/node_compat/test/common/index.mjs
@@ -11,105 +11,105 @@ const require = createRequire(import.meta.url);
const common = require('./index.js');
const {
- isMainThread,
- isWindows,
+ allowGlobals,
+ buildType,
+ canCreateSymLink,
+ checkoutEOL,
+ childShouldThrowAndAbort,
+ createZeroFilledFile,
+ enoughTestMem,
+ expectsError,
+ expectWarning,
+ getArrayBufferViews,
+ getBufferSources,
+ getCallSite,
+ getTTYfd,
+ hasCrypto,
+ hasIPv6,
+ hasMultiLocalhost,
isAIX,
- isIBMi,
- isLinuxPPCBE,
- isSunOS,
+ isAlive,
isDumbTerminal,
isFreeBSD,
- isOpenBSD,
+ isIBMi,
isLinux,
+ isLinuxPPCBE,
+ isMainThread,
+ isOpenBSD,
isOSX,
- enoughTestMem,
- buildType,
+ isSunOS,
+ isWindows,
localIPv6Hosts,
- opensslCli,
- PIPE,
- hasCrypto,
- hasIPv6,
- childShouldThrowAndAbort,
- checkoutEOL,
- createZeroFilledFile,
- platformTimeout,
- allowGlobals,
mustCall,
mustCallAtLeast,
- mustSucceed,
- hasMultiLocalhost,
- skipIfDumbTerminal,
- skipIfEslintMissing,
- canCreateSymLink,
- getCallSite,
mustNotCall,
mustNotMutateObjectDeep,
+ mustSucceed,
+ nodeProcessAborted,
+ opensslCli,
parseTestFlags,
+ PIPE,
+ platformTimeout,
printSkipMessage,
+ runWithInvalidFD,
skip,
- nodeProcessAborted,
- isAlive,
- expectWarning,
- expectsError,
- skipIfInspectorDisabled,
skipIf32Bits,
- getArrayBufferViews,
- getBufferSources,
- getTTYfd,
- runWithInvalidFD,
+ skipIfDumbTerminal,
+ skipIfEslintMissing,
+ skipIfInspectorDisabled,
spawnPromisified,
} = common;
const getPort = () => common.PORT;
export {
- isMainThread,
- isWindows,
+ allowGlobals,
+ buildType,
+ canCreateSymLink,
+ checkoutEOL,
+ childShouldThrowAndAbort,
+ createRequire,
+ createZeroFilledFile,
+ enoughTestMem,
+ expectsError,
+ expectWarning,
+ getArrayBufferViews,
+ getBufferSources,
+ getCallSite,
+ getPort,
+ getTTYfd,
+ hasCrypto,
+ hasIPv6,
+ hasMultiLocalhost,
isAIX,
- isIBMi,
- isLinuxPPCBE,
- isSunOS,
+ isAlive,
isDumbTerminal,
isFreeBSD,
- isOpenBSD,
+ isIBMi,
isLinux,
+ isLinuxPPCBE,
+ isMainThread,
+ isOpenBSD,
isOSX,
- enoughTestMem,
- buildType,
+ isSunOS,
+ isWindows,
localIPv6Hosts,
- opensslCli,
- PIPE,
- hasCrypto,
- hasIPv6,
- childShouldThrowAndAbort,
- checkoutEOL,
- createZeroFilledFile,
- platformTimeout,
- allowGlobals,
mustCall,
mustCallAtLeast,
- mustSucceed,
- hasMultiLocalhost,
- skipIfDumbTerminal,
- skipIfEslintMissing,
- canCreateSymLink,
- getCallSite,
mustNotCall,
mustNotMutateObjectDeep,
+ mustSucceed,
+ nodeProcessAborted,
+ opensslCli,
parseTestFlags,
+ PIPE,
+ platformTimeout,
printSkipMessage,
+ runWithInvalidFD,
skip,
- nodeProcessAborted,
- isAlive,
- expectWarning,
- expectsError,
- skipIfInspectorDisabled,
skipIf32Bits,
- getArrayBufferViews,
- getBufferSources,
- getTTYfd,
- runWithInvalidFD,
- createRequire,
+ skipIfDumbTerminal,
+ skipIfEslintMissing,
+ skipIfInspectorDisabled,
spawnPromisified,
- getPort,
};
diff --git a/tests/node_compat/test/common/tmpdir.js b/tests/node_compat/test/common/tmpdir.js
index 668424cdc..9315b8747 100644
--- a/tests/node_compat/test/common/tmpdir.js
+++ b/tests/node_compat/test/common/tmpdir.js
@@ -7,12 +7,25 @@
'use strict';
+const { spawnSync } = require('child_process');
const fs = require('fs');
const path = require('path');
+const { pathToFileURL } = require('url');
const { isMainThread } = require('worker_threads');
-function rmSync(pathname) {
- fs.rmSync(pathname, { maxRetries: 3, recursive: true, force: true });
+function rmSync(pathname, useSpawn) {
+ if (useSpawn) {
+ const escapedPath = pathname.replaceAll('\\', '\\\\');
+ spawnSync(
+ process.execPath,
+ [
+ '-e',
+ `require("fs").rmSync("${escapedPath}", { maxRetries: 3, recursive: true, force: true });`,
+ ],
+ );
+ } else {
+ fs.rmSync(pathname, { maxRetries: 3, recursive: true, force: true });
+ }
}
const testRoot = process.env.NODE_TEST_DIR ?
@@ -25,25 +38,27 @@ const tmpdirName = '.tmp.' +
const tmpPath = path.join(testRoot, tmpdirName);
let firstRefresh = true;
-function refresh() {
- rmSync(tmpPath);
+function refresh(useSpawn = false) {
+ rmSync(tmpPath, useSpawn);
fs.mkdirSync(tmpPath);
if (firstRefresh) {
firstRefresh = false;
// Clean only when a test uses refresh. This allows for child processes to
// use the tmpdir and only the parent will clean on exit.
- process.on('exit', onexit);
+ process.on('exit', () => {
+ return onexit(useSpawn);
+ });
}
}
-function onexit() {
+function onexit(useSpawn) {
// Change directory to avoid possible EBUSY
if (isMainThread)
process.chdir(testRoot);
try {
- rmSync(tmpPath);
+ rmSync(tmpPath, useSpawn);
} catch (e) {
console.error('Can\'t clean tmpdir:', tmpPath);
@@ -71,9 +86,17 @@ function hasEnoughSpace(size) {
return bavail >= Math.ceil(size / bsize);
}
+function fileURL(...paths) {
+ // When called without arguments, add explicit trailing slash
+ const fullPath = path.resolve(tmpPath + path.sep, ...paths);
+
+ return pathToFileURL(fullPath);
+}
+
module.exports = {
+ fileURL,
+ hasEnoughSpace,
path: tmpPath,
refresh,
- hasEnoughSpace,
resolve,
};