Skip to content

Commit

Permalink
feat(vitest): expose execArgv to the different pools (#4383)
Browse files Browse the repository at this point in the history
  • Loading branch information
adriencaccia committed Oct 31, 2023
1 parent 0db386d commit 9021e8b
Show file tree
Hide file tree
Showing 16 changed files with 215 additions and 3 deletions.
33 changes: 33 additions & 0 deletions docs/config/index.md
Expand Up @@ -723,6 +723,17 @@ This can improve performance in some cases, but might cause segfault in older No

Isolate environment for each test file.

##### poolOptions.threads.execArgv<NonProjectOption />

- **Type:** `string[]`
- **Default:** `[]`

Pass additional arguments to `node` in the threads. See [Command-line API | Node.js](https://nodejs.org/docs/latest/api/cli.html) for more information.

:::warning
Be careful when using, it as some options may crash worker, e.g. --prof, --title. See https://github.com/nodejs/node/issues/41103.
:::

#### poolOptions.forks<NonProjectOption />

Options for `forks` pool.
Expand Down Expand Up @@ -776,6 +787,17 @@ Even though this option will force tests to run one after another, this option i
This might cause all sorts of issues, if you are relying on global state (frontend frameworks usually do) or your code relies on environment to be defined separately for each test. But can be a speed boost for your tests (up to 3 times faster), that don't necessarily rely on global state or can easily bypass that.
:::

##### poolOptions.forks.execArgv<NonProjectOption />

- **Type:** `string[]`
- **Default:** `[]`

Pass additional arguments to `node` process in the child processes. See [Command-line API | Node.js](https://nodejs.org/docs/latest/api/cli.html) for more information.

:::warning
Be careful when using, it as some options may crash worker, e.g. --prof, --title. See https://github.com/nodejs/node/issues/41103.
:::

#### poolOptions.vmThreads<NonProjectOption />

Options for `vmThreads` pool.
Expand Down Expand Up @@ -846,6 +868,17 @@ Use Atomics to synchronize threads.

This can improve performance in some cases, but might cause segfault in older Node versions.

##### poolOptions.vmThreads.execArgv<NonProjectOption />

- **Type:** `string[]`
- **Default:** `[]`

Pass additional arguments to `node` process in the VM context. See [Command-line API | Node.js](https://nodejs.org/docs/latest/api/cli.html) for more information.

:::warning
Be careful when using, it as some options may crash worker, e.g. --prof, --title. See https://github.com/nodejs/node/issues/41103.
:::

### testTimeout

- **Type:** `number`
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/node/pool.ts
Expand Up @@ -63,7 +63,7 @@ export function createPool(ctx: Vitest): ProcessPool {
// Instead of passing whole process.execArgv to the workers, pick allowed options.
// Some options may crash worker, e.g. --prof, --title. nodejs/node#41103
const execArgv = process.execArgv.filter(execArg =>
execArg.startsWith('--cpu-prof') || execArg.startsWith('--heap-prof'),
execArg.startsWith('--cpu-prof') || execArg.startsWith('--heap-prof') || execArg.startsWith('--diagnostic-dir'),
)

const options: PoolProcessOptions = {
Expand Down
5 changes: 4 additions & 1 deletion packages/vitest/src/node/pools/child.ts
Expand Up @@ -69,7 +69,10 @@ export function createChildProcessPool(ctx: Vitest, { execArgv, env, forksPath }
minThreads,

env,
execArgv,
execArgv: [
...ctx.config.poolOptions?.forks?.execArgv ?? [],
...execArgv,
],

terminateTimeout: ctx.config.teardownTimeout,
}
Expand Down
5 changes: 4 additions & 1 deletion packages/vitest/src/node/pools/threads.ts
Expand Up @@ -56,7 +56,10 @@ export function createThreadsPool(ctx: Vitest, { execArgv, env, workerPath }: Po
minThreads,

env,
execArgv,
execArgv: [
...ctx.config.poolOptions?.threads?.execArgv ?? [],
...execArgv,
],

terminateTimeout: ctx.config.teardownTimeout,
}
Expand Down
1 change: 1 addition & 0 deletions packages/vitest/src/node/pools/vm-threads.ts
Expand Up @@ -66,6 +66,7 @@ export function createVmThreadsPool(ctx: Vitest, { execArgv, env, vmPath }: Pool
'--experimental-vm-modules',
'--require',
suppressWarningsPath,
...ctx.config.poolOptions?.vmThreads?.execArgv ?? [],
...execArgv,
],

Expand Down
26 changes: 26 additions & 0 deletions packages/vitest/src/types/pool-options.ts
Expand Up @@ -81,6 +81,19 @@ interface WorkerContextOptions {
* @default true
*/
isolate?: boolean

/**
* Pass additional arguments to `node` process when spawning `worker_threads` or `child_process`.
*
* See [Command-line API | Node.js](https://nodejs.org/docs/latest/api/cli.html) for more information.
*
* Set to `process.execArgv` to pass all arguments of the current process.
*
* Be careful when using, it as some options may crash worker, e.g. --prof, --title. See https://github.com/nodejs/node/issues/41103
*
* @default [] // no execution arguments are passed
*/
execArgv?: string[]
}

interface VmOptions {
Expand All @@ -92,4 +105,17 @@ interface VmOptions {

/** Isolation is always enabled */
isolate?: true

/**
* Pass additional arguments to `node` process when spawning `worker_threads` or `child_process`.
*
* See [Command-line API | Node.js](https://nodejs.org/docs/latest/api/cli.html) for more information.
*
* Set to `process.execArgv` to pass all arguments of the current process.
*
* Be careful when using, it as some options may crash worker, e.g. --prof, --title. See https://github.com/nodejs/node/issues/41103
*
* @default [] // no execution arguments are passed
*/
execArgv?: string[]
}
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions test/run/allowed-exec-args-fixtures/allowed-exec-argv.test.ts
@@ -0,0 +1,16 @@
import { describe, expect, it } from 'vitest'

describe('exec-args', async () => {
it('should have the correct flags', () => {
// flags that should go through
expect(process.execArgv).toContain('--cpu-prof')
expect(process.execArgv).toContain('--cpu-prof-name=cpu.prof')
expect(process.execArgv).toContain('--heap-prof')
expect(process.execArgv).toContain('--heap-prof-name=heap.prof')
expect(process.execArgv).toContain('--diagnostic-dir=/tmp/vitest-diagnostics')

// added via vitest
expect(process.execArgv).toContain('--conditions')
expect(process.execArgv).toContain('node')
})
})
3 changes: 3 additions & 0 deletions test/run/allowed-exec-args-fixtures/vitest.config.ts
@@ -0,0 +1,3 @@
import { defineConfig } from 'vitest/config'

export default defineConfig({})
13 changes: 13 additions & 0 deletions test/run/exec-args-fixtures/forks.test.ts
@@ -0,0 +1,13 @@
import { describe, expect, it } from 'vitest'

describe('exec-args', async () => {
it('should have the correct flags', () => {
expect(process.execArgv).toContain('--hash-seed=1')
expect(process.execArgv).toContain('--random-seed=1')
expect(process.execArgv).toContain('--no-opt')

// added via vitest
expect(process.execArgv).toContain('--conditions')
expect(process.execArgv).toContain('node')
})
})
11 changes: 11 additions & 0 deletions test/run/exec-args-fixtures/threads.test.ts
@@ -0,0 +1,11 @@
import { describe, expect, it } from 'vitest'

describe('exec-args', async () => {
it('should have the correct flags', () => {
expect(process.execArgv).toContain('--inspect-brk')

// added via vitest
expect(process.execArgv).toContain('--conditions')
expect(process.execArgv).toContain('node')
})
})
15 changes: 15 additions & 0 deletions test/run/exec-args-fixtures/vmThreads.test.ts
@@ -0,0 +1,15 @@
import { describe, expect, it } from 'vitest'

describe('exec-args', async () => {
it('should have the correct flags', () => {
expect(process.execArgv).toContain('--inspect-brk')

// added via vitest
expect(process.execArgv).toContain('--experimental-import-meta-resolve')
expect(process.execArgv).toContain('--experimental-vm-modules')
expect(process.execArgv).toContain('--require')
expect(process.execArgv).toContainEqual(expect.stringContaining('/packages/vitest/suppress-warnings.cjs'))
expect(process.execArgv).toContain('--conditions')
expect(process.execArgv).toContain('node')
})
})
12 changes: 12 additions & 0 deletions test/run/no-exec-args-fixtures/no-exec-argv.test.ts
@@ -0,0 +1,12 @@
import { describe, expect, it } from 'vitest'

describe('exec-args', async () => {
it('should have the correct flags', () => {
// flags should not be passed
expect(process.execArgv).not.toContain('--title')

// added via vitest
expect(process.execArgv).toContain('--conditions')
expect(process.execArgv).toContain('node')
})
})
3 changes: 3 additions & 0 deletions test/run/no-exec-args-fixtures/vitest.config.ts
@@ -0,0 +1,3 @@
import { defineConfig } from 'vitest/config'

export default defineConfig({})
1 change: 1 addition & 0 deletions test/run/package.json
Expand Up @@ -5,6 +5,7 @@
"test": "vitest"
},
"devDependencies": {
"execa": "^7.1.1",
"vite": "latest",
"vitest": "workspace:*"
}
Expand Down
69 changes: 69 additions & 0 deletions test/run/test/exec-args.test.ts
@@ -0,0 +1,69 @@
import { afterAll, beforeAll, expect, test } from 'vitest'
import { execa } from 'execa'
import { runVitest } from '../../test-utils'

// VITEST_SEGFAULT_RETRY messes with the node flags, as can be seen in packages/vitest/src/node/cli-wrapper.ts
// so here we remove it to make sure the tests are not affected by it
const ORIGIN_VITEST_SEGFAULT_RETRY = process.env.VITEST_SEGFAULT_RETRY
beforeAll(() => {
delete process.env.VITEST_SEGFAULT_RETRY
})
afterAll(() => {
process.env.VITEST_SEGFAULT_RETRY = ORIGIN_VITEST_SEGFAULT_RETRY
})

test.each([
{ pool: 'forks', execArgv: ['--hash-seed=1', '--random-seed=1', '--no-opt'] },
{ pool: 'threads', execArgv: ['--inspect-brk'] },
{ pool: 'vmThreads', execArgv: ['--inspect-brk'] },
] as const)('should pass execArgv to { pool: $pool } ', async ({ pool, execArgv }) => {
const fileToTest = `exec-args-fixtures/${pool}.test.ts`

const vitest = await runVitest({
include: [fileToTest],
pool,
poolOptions: {
[pool]: {
execArgv,
},
},
})

expect(vitest.stdout).toContain(`✓ ${fileToTest}`)
})

test('should not pass execArgv to workers when not specified in the config', async () => {
const { stdout, stderr } = await execa('node', [
'--title', 'this-works-only-on-main-thread',
'../node_modules/vitest/vitest.mjs', '--run',
], {
cwd: `${process.cwd()}/no-exec-args-fixtures`,
reject: false,
env: {
VITE_NODE_DEPS_MODULE_DIRECTORIES: '/node_modules/,/packages/',
NO_COLOR: '1',
},
})

expect(stderr).not.toContain('Error: Initiated Worker with invalid execArgv flags: --title')
expect(stderr).not.toContain('ERR_WORKER_INVALID_EXEC_ARGV')
expect(stdout).toContain('✓ no-exec-argv.test.ts')
})

test('should let allowed args pass to workers', async () => {
const { stdout, stderr } = await execa('node', [
'--cpu-prof', '--heap-prof', '--diagnostic-dir=/tmp/vitest-diagnostics',
'--cpu-prof-name=cpu.prof', '--heap-prof-name=heap.prof',
'../node_modules/vitest/vitest.mjs', '--run',
], {
cwd: `${process.cwd()}/allowed-exec-args-fixtures`,
reject: false,
env: {
VITE_NODE_DEPS_MODULE_DIRECTORIES: '/node_modules/,/packages/',
NO_COLOR: '1',
},
})

expect(stderr).toBe('')
expect(stdout).toContain('✓ allowed-exec-argv.test.ts')
})

0 comments on commit 9021e8b

Please sign in to comment.