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: add and use spawnSyncAndExit() and spawnSyncAndExitWithoutError() #49200

Merged
merged 2 commits into from
Aug 18, 2023
Merged
Show file tree
Hide file tree
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
25 changes: 15 additions & 10 deletions test/common/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,16 @@ The `benchmark` module is used by tests to run benchmarks.

The `child_process` module is used by tests that launch child processes.

### `expectSyncExit(child, options)`
### `spawnSyncAndExit(command[, args][, spawnOptions], expectations)`

Checks if a _synchronous_ child process runs in the way expected. If it does
not, print the stdout and stderr output from the child process and additional
information about it to the stderr of the current process before throwing
and error. This helps gathering more information about test failures
coming from child processes.
Spawns a child process synchronously using [`child_process.spawnSync()`][] and
check if it runs in the way expected. If it does not, print the stdout and
stderr output from the child process and additional information about it to
the stderr of the current process before throwing and error. This helps
gathering more information about test failures coming from child processes.

* `child` [\<ChildProcess>][<ChildProcess>]: a `ChildProcess` instance
returned by `child_process.spawnSync()`.
* `options` [\<Object>][<Object>]
* `command`, `args`, `spawnOptions` See [`child_process.spawnSync()`][]
* `expectations` [\<Object>][<Object>]
* `status` [\<number>][<number>] Expected `child.status`
* `signal` [\<string>][<string>] | `null` Expected `child.signal`
* `stderr` [\<string>][<string>] | [\<RegExp>][<RegExp>] |
Expand All @@ -65,8 +64,13 @@ coming from child processes.
* `trim` [\<boolean>][<boolean>] Optional. Whether this method should trim
out the whitespace characters when checking `stderr` and `stdout` outputs.
Defaults to `false`.
* return [\<Object>][<Object>]
* `child` [\<ChildProcess>][<ChildProcess>] The child process returned by
[`child_process.spawnSync()`][].
* `stderr` [\<string>][<string>] The output from the child process to stderr.
* `stdout` [\<string>][<string>] The output from the child process to stdout.

### `expectSyncExitWithoutError(child[, options])`
### `spawnSyncAndExitWithoutError(command[, args][, spawnOptions], expectations)`

Similar to `expectSyncExit()` with the `status` expected to be 0 and
`signal` expected to be `null`. Any other optional options are passed
Expand Down Expand Up @@ -1160,6 +1164,7 @@ See [the WPT tests README][] for details.
[<number>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type
[<string>]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type
[Web Platform Tests]: https://github.com/web-platform-tests/wpt
[`child_process.spawnSync()`]: ../../doc/api/child_process.md#child_processspawnsynccommand-args-options
[`hijackstdio.hijackStdErr()`]: #hijackstderrlistener
[`hijackstdio.hijackStdOut()`]: #hijackstdoutlistener
[internationalization]: ../../doc/api/intl.md
Expand Down
34 changes: 22 additions & 12 deletions test/common/child_process.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const assert = require('assert');
const { spawnSync, execFileSync } = require('child_process');
const common = require('./');
const util = require('util');

Expand All @@ -14,14 +15,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.
}
Expand Down Expand Up @@ -111,11 +111,21 @@ function expectSyncExit(child, {
return { child, stderr: stderrStr, stdout: stdoutStr };
}

function expectSyncExitWithoutError(child, options) {
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,
...options,
...expectations,
});
}

Expand All @@ -124,6 +134,6 @@ module.exports = {
logAfterTime,
kExpiringChildRunTime,
kExpiringParentTimer,
expectSyncExit,
expectSyncExitWithoutError,
spawnSyncAndExit,
spawnSyncAndExitWithoutError,
};
13 changes: 4 additions & 9 deletions test/parallel/test-snapshot-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@

require('../common');
const assert = require('assert');
const { spawnSync } = require('child_process');
const tmpdir = require('../common/tmpdir');
const fixtures = require('../common/fixtures');
const { expectSyncExitWithoutError } = require('../common/child_process');
const { spawnSyncAndExitWithoutError } = require('../common/child_process');
const fs = require('fs');

const v8 = require('v8');
Expand All @@ -29,22 +28,20 @@ const entry = fixtures.path('snapshot', 'v8-startup-snapshot-api.js');
fs.writeFileSync(tmpdir.resolve(book), content, 'utf8');
}
fs.copyFileSync(entry, tmpdir.resolve('entry.js'));
const child = spawnSync(process.execPath, [
spawnSyncAndExitWithoutError(process.execPath, [
'--snapshot-blob',
blobPath,
'--build-snapshot',
'entry.js',
], {
cwd: tmpdir.path
});

expectSyncExitWithoutError(child);
const stats = fs.statSync(tmpdir.resolve('snapshot.blob'));
assert(stats.isFile());
}

{
const child = spawnSync(process.execPath, [
spawnSyncAndExitWithoutError(process.execPath, [
'--snapshot-blob',
blobPath,
'book1',
Expand All @@ -54,9 +51,7 @@ const entry = fixtures.path('snapshot', 'v8-startup-snapshot-api.js');
...process.env,
BOOK_LANG: 'en_US',
}
});

expectSyncExitWithoutError(child, {
}, {
stderr: 'Reading book1.en_US.txt',
stdout: 'This is book1.en_US.txt',
trim: true
Expand Down
32 changes: 13 additions & 19 deletions test/parallel/test-snapshot-basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@

require('../common');
const assert = require('assert');
const { spawnSync } = require('child_process');
const tmpdir = require('../common/tmpdir');
const fixtures = require('../common/fixtures');
const { expectSyncExitWithoutError, expectSyncExit } = require('../common/child_process');
const {
spawnSyncAndExitWithoutError,
spawnSyncAndExit,
} = require('../common/child_process');
const fs = require('fs');

tmpdir.refresh();
Expand All @@ -18,14 +20,12 @@ if (!process.config.variables.node_use_node_snapshot) {
// Check that Node.js built without an embedded snapshot
// exits with 9 when node:embedded_snapshot_main is specified
// as snapshot entry point.
const child = spawnSync(process.execPath, [
spawnSyncAndExit(process.execPath, [
'--build-snapshot',
snapshotScript,
], {
cwd: tmpdir.path
});

expectSyncExit(child, {
}, {
status: 9,
signal: null,
stderr: /Node\.js was built without embedded snapshot/
Expand All @@ -37,13 +37,12 @@ if (!process.config.variables.node_use_node_snapshot) {
// By default, the snapshot blob path is cwd/snapshot.blob.
{
// Create the snapshot.
const child = spawnSync(process.execPath, [
spawnSyncAndExitWithoutError(process.execPath, [
'--build-snapshot',
snapshotScript,
], {
cwd: tmpdir.path
});
expectSyncExitWithoutError(child);
const stats = fs.statSync(tmpdir.resolve('snapshot.blob'));
assert(stats.isFile());
}
Expand All @@ -52,46 +51,41 @@ tmpdir.refresh();
const blobPath = tmpdir.resolve('my-snapshot.blob');
{
// Create the snapshot.
const child = spawnSync(process.execPath, [
spawnSyncAndExitWithoutError(process.execPath, [
'--snapshot-blob',
blobPath,
'--build-snapshot',
snapshotScript,
], {
cwd: tmpdir.path
});
expectSyncExitWithoutError(child);
const stats = fs.statSync(blobPath);
assert(stats.isFile());
}

{
// Check --help.
const child = spawnSync(process.execPath, [
spawnSyncAndExitWithoutError(process.execPath, [
'--snapshot-blob',
blobPath,
'--help',
], {
cwd: tmpdir.path
}, {
stdout: /--help/
});
expectSyncExitWithoutError(child);

assert(child.stdout.toString().includes('--help'));
}

{
// Check -c.
const child = spawnSync(process.execPath, [
spawnSyncAndExitWithoutError(process.execPath, [
'--snapshot-blob',
blobPath,
'-c',
fixtures.path('snapshot', 'marked.js'),
], {
cwd: tmpdir.path
});

// Check that it is a noop.
expectSyncExitWithoutError(child, {
}, {
stderr: '',
stdout: '',
trim: true
Expand Down
35 changes: 12 additions & 23 deletions test/parallel/test-snapshot-warning.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@
require('../common');

const assert = require('assert');
const { spawnSync } = require('child_process');
const tmpdir = require('../common/tmpdir');
const fixtures = require('../common/fixtures');
const { expectSyncExitWithoutError } = require('../common/child_process');
const { spawnSyncAndExitWithoutError } = require('../common/child_process');
const fs = require('fs');

const warningScript = fixtures.path('snapshot', 'warning.js');
Expand All @@ -20,48 +19,44 @@ const empty = fixtures.path('empty.js');
tmpdir.refresh();
{
console.log('\n# Check snapshot scripts that do not emit warnings.');
let child = spawnSync(process.execPath, [
spawnSyncAndExitWithoutError(process.execPath, [
'--snapshot-blob',
blobPath,
'--build-snapshot',
empty,
], {
cwd: tmpdir.path
});
expectSyncExitWithoutError(child);
const stats = fs.statSync(blobPath);
assert(stats.isFile());

child = spawnSync(process.execPath, [
spawnSyncAndExitWithoutError(process.execPath, [
'--snapshot-blob',
blobPath,
warningScript,
], {
cwd: tmpdir.path
});
expectSyncExitWithoutError(child, {
}, {
stderr(output) {
const match = output.match(/Warning: test warning/g);
assert.strictEqual(match.length, 1);
return true;
}
});

}

tmpdir.refresh();
{
console.log('\n# Check snapshot scripts that emit ' +
'warnings and --trace-warnings hint.');
let child = spawnSync(process.execPath, [
spawnSyncAndExitWithoutError(process.execPath, [
'--snapshot-blob',
blobPath,
'--build-snapshot',
warningScript,
], {
cwd: tmpdir.path
});
expectSyncExitWithoutError(child, {
}, {
stderr(output) {
let match = output.match(/Warning: test warning/g);
assert.strictEqual(match.length, 1);
Expand All @@ -73,15 +68,13 @@ tmpdir.refresh();
const stats = fs.statSync(blobPath);
assert(stats.isFile());

child = spawnSync(process.execPath, [
spawnSyncAndExitWithoutError(process.execPath, [
'--snapshot-blob',
blobPath,
warningScript,
], {
cwd: tmpdir.path
});

expectSyncExitWithoutError(child, {
}, {
stderr(output) {
// Warnings should not be handled more than once.
let match = output.match(/Warning: test warning/g);
Expand All @@ -99,7 +92,7 @@ tmpdir.refresh();
const warningFile1 = tmpdir.resolve('warnings.txt');
const warningFile2 = tmpdir.resolve('warnings2.txt');

let child = spawnSync(process.execPath, [
spawnSyncAndExitWithoutError(process.execPath, [
'--snapshot-blob',
blobPath,
'--redirect-warnings',
Expand All @@ -108,9 +101,7 @@ tmpdir.refresh();
warningScript,
], {
cwd: tmpdir.path
});

expectSyncExitWithoutError(child, {
}, {
stderr(output) {
assert.doesNotMatch(output, /Warning: test warning/);
}
Expand All @@ -129,17 +120,15 @@ tmpdir.refresh();
maxRetries: 3, recursive: false, force: true
});

child = spawnSync(process.execPath, [
spawnSyncAndExitWithoutError(process.execPath, [
'--snapshot-blob',
blobPath,
'--redirect-warnings',
warningFile2,
warningScript,
], {
cwd: tmpdir.path
});

expectSyncExitWithoutError(child, {
}, {
stderr(output) {
assert.doesNotMatch(output, /Warning: test warning/);
return true;
Expand Down