Skip to content

Commit

Permalink
Add filterNodeArgumentsForWorkerThreads option
Browse files Browse the repository at this point in the history
This filter function can be used to remove node arguments that may be applied to the main process, but cannot be used to start worker threads. It can only be configured in a JavaScript configuration file. It does not apply when using child processes.

Co-authored-by: Tommy <tmitchell7@uh.edu>
Co-authored-by: Mark Wubben <mark@novemberborn.net>
3 people authored Aug 20, 2024

Partially verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
We cannot verify signatures from co-authors, and some of the co-authors attributed to this commit require their commits to be signed.
1 parent b15df53 commit 86185b4
Showing 16 changed files with 141 additions and 0 deletions.
16 changes: 16 additions & 0 deletions docs/06-configuration.md
Original file line number Diff line number Diff line change
@@ -337,3 +337,19 @@ These may also export a function which is then invoked, and can receive argument
The `nodeArguments` configuration may be used to specify additional arguments for launching worker processes. These are combined with `--node-arguments` passed on the CLI and any arguments passed to the `node` binary when starting AVA.

[CLI]: ./05-command-line.md

## Node arguments filter for worker threads

In a config file only, `filterNodeArgumentsForWorkerThreads` may provide a function used for filtering `nodeArguments` sent to worker threads. This enables excluding arguments that throw if sent to a thread. The filter is ignored by worker processes.

`ava.config.js`:
```js
const processOnly = new Set([
'--allow-natives-syntax',
'--expose-gc'
]);

export default {
filterNodeArgumentsForWorkerThreads: argument => !processOnly.has(argument)
}
```
6 changes: 6 additions & 0 deletions lib/cli.js
Original file line number Diff line number Diff line change
@@ -388,9 +388,15 @@ export default async function loadCli() { // eslint-disable-line complexity
exit(error.message);
}

const workerThreads = combined.workerThreads !== false;

let nodeArguments;
try {
nodeArguments = normalizeNodeArguments(conf.nodeArguments, argv['node-arguments']);
if (workerThreads && 'filterNodeArgumentsForWorkerThreads' in conf) {
const {filterNodeArgumentsForWorkerThreads: filter} = conf;
nodeArguments = nodeArguments.filter(argument => filter(argument));
}
} catch (error) {
exit(error.message);
}
7 changes: 7 additions & 0 deletions lib/load-config.js
Original file line number Diff line number Diff line change
@@ -157,6 +157,13 @@ export async function loadConfig({configFile, resolveFrom = process.cwd(), defau
...defaults, nonSemVerExperiments: {}, ...fileConf, ...packageConf, projectDir, configFile,
};

if (
'filterNodeArgumentsForWorkerThreads' in config
&& typeof config.filterNodeArgumentsForWorkerThreads !== 'function'
) {
throw new Error(`filterNodeArgumentsForWorkerThreads from ${fileForErrorMessage} must be a function`);
}

const {nonSemVerExperiments: experiments} = config;
if (!isPlainObject(experiments)) {
throw new Error(`nonSemVerExperiments from ${fileForErrorMessage} must be an object`);
2 changes: 2 additions & 0 deletions test-tap/api.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import fs from 'node:fs';
import path from 'node:path';
import process from 'node:process';
import {fileURLToPath} from 'node:url';

import ciInfo from 'ci-info';
@@ -20,6 +21,7 @@ async function apiCreator(options = {}) {
options.globs = normalizeGlobs({
files: options.files, ignoredByWatcher: options.watchMode?.ignoreChanges, extensions: options.extensions, providers: [],
});
options.nodeArguments = process.execArgv;
const instance = new Api(options);

return instance;
3 changes: 3 additions & 0 deletions test-tap/fixture/load-config/non-function/ava.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
filterNodeArgumentsForWorkerThreads: [],
};
3 changes: 3 additions & 0 deletions test-tap/fixture/load-config/non-function/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
2 changes: 2 additions & 0 deletions test/config/loader.js
Original file line number Diff line number Diff line change
@@ -117,6 +117,8 @@ test.serial('throws an error if a .js config file has no default export', notOk(

test.serial('throws an error if a config file contains `ava` property', notOk('contains-ava-property'));

test.serial('throws an error if a config file contains a non-function `filterNodeArgumentsForWorkerThreads` property', notOk('non-function'));

test.serial('throws an error if a config file contains a non-object `nonSemVerExperiments` property', notOk('non-object-experiments'));

test.serial('throws an error if a config file enables an unsupported experiment', notOk('unsupported-experiments'));
12 changes: 12 additions & 0 deletions test/config/snapshots/loader.js.md
Original file line number Diff line number Diff line change
@@ -40,6 +40,12 @@ Generated by [AVA](https://avajs.dev).
'Encountered ’ava’ property in ava.config.js; avoid wrapping the configuration'

## throws an error if a config file contains a non-function `filterNodeArgumentsForWorkerThreads` property

> error message
'filterNodeArgumentsForWorkerThreads from ava.config.js must be a function'

## throws an error if a config file contains a non-object `nonSemVerExperiments` property

> error message
@@ -57,3 +63,9 @@ Generated by [AVA](https://avajs.dev).
> error message
'Conflicting configuration in ava.config.js and ava.config.cjs'

## throws an error if a config file contains a non-function `threadArgumentsFilter` property

> error message
'threadArgumentsFilter from ava.config.js must be a function'
Binary file modified test/config/snapshots/loader.js.snap
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import test from 'ava';

test('exec arguments unfiltered', t => {
t.plan(2);
t.truthy(process.execArgv.includes('--throw-deprecation'));
t.truthy(process.execArgv.includes('--allow-natives-syntax'));
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const processOnly = new Set(['--allow-natives-syntax']);

export default {
nodeArguments: [
'--throw-deprecation',
'--allow-natives-syntax',
],
filterNodeArgumentsForWorkerThreads: argument => !processOnly.has(argument),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import test from 'ava';

test('exec arguments filtered', t => {
t.plan(2);
t.truthy(process.execArgv.includes('--throw-deprecation'));
t.falsy(process.execArgv.includes('--allow-natives-syntax'));
});
44 changes: 44 additions & 0 deletions test/node-arguments/snapshots/test.js.md
Original file line number Diff line number Diff line change
@@ -15,6 +15,28 @@ Generated by [AVA](https://avajs.dev).
},
]

## `filterNodeArgumentsForWorkerThreads` configuration filters arguments for worker thread

> tests pass
[
{
file: 'thread.js',
title: 'exec arguments filtered',
},
]

## `filterNodeArgumentsForWorkerThreads` configuration ignored for worker process

> tests pass
[
{
file: 'process.js',
title: 'exec arguments unfiltered',
},
]

## detects incomplete --node-arguments

> fails with message
@@ -31,3 +53,25 @@ Generated by [AVA](https://avajs.dev).
title: 'works',
},
]

## `threadArgumentsFilter` configuration filters arguments for worker thread

> tests pass
[
{
file: 'thread.js',
title: 'exec arguments filtered',
},
]

## `threadArgumentsFilter` configuration ignored for worker process

> tests pass
[
{
file: 'process.js',
title: 'exec arguments unfiltered',
},
]
Binary file modified test/node-arguments/snapshots/test.js.snap
Binary file not shown.
20 changes: 20 additions & 0 deletions test/node-arguments/test.js
Original file line number Diff line number Diff line change
@@ -13,6 +13,26 @@ test('passed node arguments to workers', async t => {
t.snapshot(result.stats.passed, 'tests pass');
});

test('`filterNodeArgumentsForWorkerThreads` configuration filters arguments for worker thread', async t => {
const options = {
cwd: cwd('thread-arguments-filter'),
};

const result = await fixture(['--config=thread-arguments-filter.config.mjs', 'thread.js'], options);

t.snapshot(result.stats.passed, 'tests pass');
});

test('`filterNodeArgumentsForWorkerThreads` configuration ignored for worker process', async t => {
const options = {
cwd: cwd('thread-arguments-filter'),
};

const result = await fixture(['--config=thread-arguments-filter.config.mjs', '--no-worker-threads', 'process.js'], options);

t.snapshot(result.stats.passed, 'tests pass');
});

test('detects incomplete --node-arguments', async t => {
const options = {
cwd: cwd('node-arguments'),

0 comments on commit 86185b4

Please sign in to comment.