From 0c6cc039d8908c5b3ef420b2b31df7d5f41f263b Mon Sep 17 00:00:00 2001 From: Sung Ye In <66503450+syi0808@users.noreply.github.com> Date: Thu, 27 Jun 2024 15:40:14 +0900 Subject: [PATCH 1/8] docs: Update maxworkers description --- docs/guide/cli-table.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guide/cli-table.md b/docs/guide/cli-table.md index e36b70452893..10d7a3ed855c 100644 --- a/docs/guide/cli-table.md +++ b/docs/guide/cli-table.md @@ -80,8 +80,8 @@ | `--poolOptions.vmForks.minForks ` | Minimum number of processes to run tests in | | `--poolOptions.vmForks.memoryLimit ` | Memory limit for VM forks pool. If you see memory leaks, try to tinker this value. | | `--fileParallelism` | Should all test files run in parallel. Use `--no-file-parallelism` to disable (default: `true`) | -| `--maxWorkers ` | Maximum number of workers to run tests in | -| `--minWorkers ` | Minimum number of workers to run tests in | +| `--maxWorkers ` | Maximum number or percentage of workers to run tests in | +| `--minWorkers ` | Minimum number or percentage of workers to run tests in | | `--environment ` | Specify runner environment, if not running in the browser (default: `node`) | | `--passWithNoTests` | Pass when no tests are found | | `--logHeapUsage` | Show the size of heap for each test when running in node | From f643a52757a9c2c5708b88423a6a8e792a44ed46 Mon Sep 17 00:00:00 2001 From: syi0808 Date: Fri, 28 Jun 2024 00:29:48 +0900 Subject: [PATCH 2/8] feat(config): allow percentage value for workers option --- packages/vitest/rollup.config.js | 1 + packages/vitest/src/node/config.ts | 15 +++++++-- packages/vitest/src/types/config.ts | 11 ++++--- packages/vitest/src/utils/workers.ts | 8 +++++ .../fixtures/workers-option/example.test.ts | 5 +++ .../fixtures/workers-option/vitest.config.js | 1 + test/config/test/workers-option.test.ts | 33 +++++++++++++++++++ 7 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 packages/vitest/src/utils/workers.ts create mode 100644 test/config/fixtures/workers-option/example.test.ts create mode 100644 test/config/fixtures/workers-option/vitest.config.js create mode 100644 test/config/test/workers-option.test.ts diff --git a/packages/vitest/rollup.config.js b/packages/vitest/rollup.config.js index 9b0693000521..133ec7fdab5e 100644 --- a/packages/vitest/rollup.config.js +++ b/packages/vitest/rollup.config.js @@ -67,6 +67,7 @@ const external = [ 'worker_threads', 'node:worker_threads', 'node:fs', + 'node:os', 'node:stream', 'node:vm', 'inspector', diff --git a/packages/vitest/src/node/config.ts b/packages/vitest/src/node/config.ts index b009e7294d7b..cd563e43b4c0 100644 --- a/packages/vitest/src/node/config.ts +++ b/packages/vitest/src/node/config.ts @@ -17,6 +17,7 @@ import { import { benchmarkConfigDefaults, configDefaults } from '../defaults' import { isCI, stdProvider, toArray } from '../utils' import type { BuiltinPool } from '../types/pool-options' +import { getWorkersCountByPercentage } from '../utils/workers' import { VitestCache } from './cache' import { BaseSequencer } from './sequencers/BaseSequencer' import { RandomSequencer } from './sequencers/RandomSequencer' @@ -176,11 +177,21 @@ export function resolveConfig( } if (resolved.maxWorkers) { - resolved.maxWorkers = Number(resolved.maxWorkers) + if (typeof options.maxWorkers === 'string' && options.maxWorkers.trim().endsWith('%')) { + resolved.maxWorkers = getWorkersCountByPercentage(options.maxWorkers) + } + else { + resolved.maxWorkers = Number(resolved.maxWorkers) + } } if (resolved.minWorkers) { - resolved.minWorkers = Number(resolved.minWorkers) + if (typeof options.minWorkers === 'string' && options.minWorkers.trim().endsWith('%')) { + resolved.minWorkers = getWorkersCountByPercentage(options.minWorkers) + } + else { + resolved.minWorkers = Number(resolved.minWorkers) + } } resolved.browser ??= {} as any diff --git a/packages/vitest/src/types/config.ts b/packages/vitest/src/types/config.ts index b77748a87fb2..6c0ead31f2f7 100644 --- a/packages/vitest/src/types/config.ts +++ b/packages/vitest/src/types/config.ts @@ -343,13 +343,13 @@ export interface InlineConfig { poolOptions?: PoolOptions /** - * Maximum number of workers to run tests in. `poolOptions.{threads,vmThreads}.maxThreads`/`poolOptions.forks.maxForks` has higher priority. + * Maximum number or percentage of workers to run tests in. `poolOptions.{threads,vmThreads}.maxThreads`/`poolOptions.forks.maxForks` has higher priority. */ - maxWorkers?: number + maxWorkers?: number | string /** - * Minimum number of workers to run tests in. `poolOptions.{threads,vmThreads}.minThreads`/`poolOptions.forks.minForks` has higher priority. + * Minimum number or percentage of workers to run tests in. `poolOptions.{threads,vmThreads}.minThreads`/`poolOptions.forks.minForks` has higher priority. */ - minWorkers?: number + minWorkers?: number | string /** * Should all test files run in parallel. Doesn't affect tests running in the same file. @@ -1009,6 +1009,9 @@ export interface ResolvedConfig enabled: boolean } runner?: string + + maxWorkers: number + minWorkers: number } export type ProjectConfig = Omit< diff --git a/packages/vitest/src/utils/workers.ts b/packages/vitest/src/utils/workers.ts new file mode 100644 index 000000000000..289498e0ea2e --- /dev/null +++ b/packages/vitest/src/utils/workers.ts @@ -0,0 +1,8 @@ +import { cpus } from 'node:os' + +export function getWorkersCountByPercentage(percent: string) { + const maxWorkersCount = cpus().length + const workersCountByPercentage = Math.round((Number.parseInt(percent) / 100) * maxWorkersCount) + + return Math.max(1, Math.min(maxWorkersCount, workersCountByPercentage)) +} diff --git a/test/config/fixtures/workers-option/example.test.ts b/test/config/fixtures/workers-option/example.test.ts new file mode 100644 index 000000000000..5a275a3fb95f --- /dev/null +++ b/test/config/fixtures/workers-option/example.test.ts @@ -0,0 +1,5 @@ +import { expect, test } from 'vitest' + +test('it works', () => { + expect(true).toBe(true) +}) diff --git a/test/config/fixtures/workers-option/vitest.config.js b/test/config/fixtures/workers-option/vitest.config.js new file mode 100644 index 000000000000..56004c9f9e06 --- /dev/null +++ b/test/config/fixtures/workers-option/vitest.config.js @@ -0,0 +1 @@ +export default {} \ No newline at end of file diff --git a/test/config/test/workers-option.test.ts b/test/config/test/workers-option.test.ts new file mode 100644 index 000000000000..3ad5a3163ace --- /dev/null +++ b/test/config/test/workers-option.test.ts @@ -0,0 +1,33 @@ +import { type UserConfig, describe, expect, test, vi } from 'vitest' + +import { getWorkersCountByPercentage } from 'vitest/src/utils/workers.js' +import * as testUtils from '../../test-utils' + +function runVitest(config: UserConfig) { + return testUtils.runVitest({ ...config, root: './fixtures/workers-option' }) +} + +test('workers percent argument should not throw error', async () => { + const { stderr } = await runVitest({ maxWorkers: '100%', minWorkers: '10%' }) + + expect(stderr).toBe('') +}) + +describe('workers util', () => { + vi.mock('node:os', async importOriginal => ({ + ...(await importOriginal() as Record), + cpus: () => Array.from({ length: 10 }), + })) + + test('percent=50% should return 5', () => { + expect(getWorkersCountByPercentage('50%')).toBe(5) + }) + + test('percent=-10% should return 1', () => { + expect(getWorkersCountByPercentage('-10%')).toBe(1) + }) + + test('percent=110% should return 10', () => { + expect(getWorkersCountByPercentage('110%')).toBe(10) + }) +}) From 94d1a399e06795ca61f200beb8c6564c69087e18 Mon Sep 17 00:00:00 2001 From: syi0808 Date: Sun, 30 Jun 2024 23:28:06 +0900 Subject: [PATCH 3/8] test: hoist mock function and remove type assertion --- test/config/test/workers-option.test.ts | 28 ++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/config/test/workers-option.test.ts b/test/config/test/workers-option.test.ts index 3ad5a3163ace..d3d952f82404 100644 --- a/test/config/test/workers-option.test.ts +++ b/test/config/test/workers-option.test.ts @@ -3,22 +3,12 @@ import { type UserConfig, describe, expect, test, vi } from 'vitest' import { getWorkersCountByPercentage } from 'vitest/src/utils/workers.js' import * as testUtils from '../../test-utils' -function runVitest(config: UserConfig) { - return testUtils.runVitest({ ...config, root: './fixtures/workers-option' }) -} - -test('workers percent argument should not throw error', async () => { - const { stderr } = await runVitest({ maxWorkers: '100%', minWorkers: '10%' }) - - expect(stderr).toBe('') -}) +vi.mock(import('node:os'), async importOriginal => ({ + ...await importOriginal(), + cpus: () => Array.from({ length: 10 }), +})) describe('workers util', () => { - vi.mock('node:os', async importOriginal => ({ - ...(await importOriginal() as Record), - cpus: () => Array.from({ length: 10 }), - })) - test('percent=50% should return 5', () => { expect(getWorkersCountByPercentage('50%')).toBe(5) }) @@ -31,3 +21,13 @@ describe('workers util', () => { expect(getWorkersCountByPercentage('110%')).toBe(10) }) }) + +function runVitest(config: UserConfig) { + return testUtils.runVitest({ ...config, root: './fixtures/workers-option' }) +} + +test('workers percent argument should not throw error', async () => { + const { stderr } = await runVitest({ maxWorkers: '100%', minWorkers: '10%' }) + + expect(stderr).toBe('') +}) From 4663f92df4c62cb557fd6e65320eaf51b26de861 Mon Sep 17 00:00:00 2001 From: syi0808 Date: Mon, 1 Jul 2024 01:40:40 +0900 Subject: [PATCH 4/8] docs: update docs for workers options --- docs/config/index.md | 40 ++++++++++++++++++++-------------------- docs/guide/cli-table.md | 16 ++++++++-------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/config/index.md b/docs/config/index.md index eb9ccb714fca..63d1c9658e94 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -654,17 +654,17 @@ export default defineConfig({ ##### poolOptions.threads.maxThreads -- **Type:** `number` +- **Type:** `number | string` - **Default:** _available CPUs_ -Maximum number of threads. You can also use `VITEST_MAX_THREADS` environment variable. +Maximum number or percentage of threads. You can also use `VITEST_MAX_THREADS` environment variable. ##### poolOptions.threads.minThreads -- **Type:** `number` +- **Type:** `number | string` - **Default:** _available CPUs_ -Minimum number of threads. You can also use `VITEST_MIN_THREADS` environment variable. +Minimum number or percentage of threads. You can also use `VITEST_MIN_THREADS` environment variable. ##### poolOptions.threads.singleThread @@ -726,17 +726,17 @@ export default defineConfig({ ##### poolOptions.forks.maxForks -- **Type:** `number` +- **Type:** `number | string` - **Default:** _available CPUs_ -Maximum number of forks. +Maximum number or percentage of forks. ##### poolOptions.forks.minForks -- **Type:** `number` +- **Type:** `number | string` - **Default:** _available CPUs_ -Minimum number of forks. +Minimum number or percentage of forks. ##### poolOptions.forks.isolate @@ -789,17 +789,17 @@ export default defineConfig({ ##### poolOptions.vmThreads.maxThreads -- **Type:** `number` +- **Type:** `number | string` - **Default:** _available CPUs_ -Maximum number of threads. You can also use `VITEST_MAX_THREADS` environment variable. +Maximum number or percentage of threads. You can also use `VITEST_MAX_THREADS` environment variable. ##### poolOptions.vmThreads.minThreads -- **Type:** `number` +- **Type:** `number | string` - **Default:** _available CPUs_ -Minimum number of threads. You can also use `VITEST_MIN_THREADS` environment variable. +Minimum number or percentage of threads. You can also use `VITEST_MIN_THREADS` environment variable. ##### poolOptions.vmThreads.memoryLimit @@ -870,17 +870,17 @@ export default defineConfig({ ##### poolOptions.vmForks.maxForks -- **Type:** `number` +- **Type:** `number | string` - **Default:** _available CPUs_ -Maximum number of threads. You can also use `VITEST_MAX_FORKS` environment variable. +Maximum number or percentage of threads. You can also use `VITEST_MAX_FORKS` environment variable. ##### poolOptions.vmForks.minForks -- **Type:** `number` +- **Type:** `number | string` - **Default:** _available CPUs_ -Minimum number of threads. You can also use `VITEST_MIN_FORKS` environment variable. +Minimum number or percentage of threads. You can also use `VITEST_MIN_FORKS` environment variable. ##### poolOptions.vmForks.memoryLimit @@ -914,15 +914,15 @@ This option doesn't affect tests running in the same file. If you want to run th ### maxWorkers {#maxworkers} -- **Type:** `number` +- **Type:** `number | string` -Maximum number of workers to run tests in. `poolOptions.{threads,vmThreads}.maxThreads`/`poolOptions.forks.maxForks` has higher priority. +Maximum number or percentage of workers to run tests in. `poolOptions.{threads,vmThreads}.maxThreads`/`poolOptions.forks.maxForks` has higher priority. ### minWorkers {#minworkers} -- **Type:** `number` +- **Type:** `number | string` -Minimum number of workers to run tests in. `poolOptions.{threads,vmThreads}.minThreads`/`poolOptions.forks.minForks` has higher priority. +Minimum number or percentage of workers to run tests in. `poolOptions.{threads,vmThreads}.minThreads`/`poolOptions.forks.minForks` has higher priority. ### testTimeout diff --git a/docs/guide/cli-table.md b/docs/guide/cli-table.md index 10d7a3ed855c..c343c3bb6250 100644 --- a/docs/guide/cli-table.md +++ b/docs/guide/cli-table.md @@ -61,23 +61,23 @@ | `--pool ` | Specify pool, if not running in the browser (default: `threads`) | | `--poolOptions.threads.isolate` | Isolate tests in threads pool (default: `true`) | | `--poolOptions.threads.singleThread` | Run tests inside a single thread (default: `false`) | -| `--poolOptions.threads.maxThreads ` | Maximum number of threads to run tests in | -| `--poolOptions.threads.minThreads ` | Minimum number of threads to run tests in | +| `--poolOptions.threads.maxThreads ` | Maximum number or percentage of threads to run tests in | +| `--poolOptions.threads.minThreads ` | Minimum number or percentage of threads to run tests in | | `--poolOptions.threads.useAtomics` | Use Atomics to synchronize threads. This can improve performance in some cases, but might cause segfault in older Node versions (default: `false`) | | `--poolOptions.vmThreads.isolate` | Isolate tests in threads pool (default: `true`) | | `--poolOptions.vmThreads.singleThread` | Run tests inside a single thread (default: `false`) | -| `--poolOptions.vmThreads.maxThreads ` | Maximum number of threads to run tests in | -| `--poolOptions.vmThreads.minThreads ` | Minimum number of threads to run tests in | +| `--poolOptions.vmThreads.maxThreads ` | Maximum number or percentage of threads to run tests in | +| `--poolOptions.vmThreads.minThreads ` | Minimum number or percentage of threads to run tests in | | `--poolOptions.vmThreads.useAtomics` | Use Atomics to synchronize threads. This can improve performance in some cases, but might cause segfault in older Node versions (default: `false`) | | `--poolOptions.vmThreads.memoryLimit ` | Memory limit for VM threads pool. If you see memory leaks, try to tinker this value. | | `--poolOptions.forks.isolate` | Isolate tests in forks pool (default: `true`) | | `--poolOptions.forks.singleFork` | Run tests inside a single child_process (default: `false`) | -| `--poolOptions.forks.maxForks ` | Maximum number of processes to run tests in | -| `--poolOptions.forks.minForks ` | Minimum number of processes to run tests in | +| `--poolOptions.forks.maxForks ` | Maximum number or percentage of processes to run tests in | +| `--poolOptions.forks.minForks ` | Minimum number or percentage of processes to run tests in | | `--poolOptions.vmForks.isolate` | Isolate tests in forks pool (default: `true`) | | `--poolOptions.vmForks.singleFork` | Run tests inside a single child_process (default: `false`) | -| `--poolOptions.vmForks.maxForks ` | Maximum number of processes to run tests in | -| `--poolOptions.vmForks.minForks ` | Minimum number of processes to run tests in | +| `--poolOptions.vmForks.maxForks ` | Maximum number or percentage of processes to run tests in | +| `--poolOptions.vmForks.minForks ` | Minimum number or percentage of processes to run tests in | | `--poolOptions.vmForks.memoryLimit ` | Memory limit for VM forks pool. If you see memory leaks, try to tinker this value. | | `--fileParallelism` | Should all test files run in parallel. Use `--no-file-parallelism` to disable (default: `true`) | | `--maxWorkers ` | Maximum number or percentage of workers to run tests in | From 20223408e36bd0fb1351cb802999a25a0ceb30e8 Mon Sep 17 00:00:00 2001 From: syi0808 Date: Mon, 1 Jul 2024 01:41:19 +0900 Subject: [PATCH 5/8] feat: update description for worker options on cli config --- packages/vitest/src/node/cli/cli-config.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/vitest/src/node/cli/cli-config.ts b/packages/vitest/src/node/cli/cli-config.ts index 50293f2e9277..f8fa04c5dbd9 100644 --- a/packages/vitest/src/node/cli/cli-config.ts +++ b/packages/vitest/src/node/cli/cli-config.ts @@ -62,11 +62,11 @@ const poolThreadsCommands: CLIOptions = { description: 'Run tests inside a single thread (default: `false`)', }, maxThreads: { - description: 'Maximum number of threads to run tests in', + description: 'Maximum number or percentage of threads to run tests in', argument: '', }, minThreads: { - description: 'Minimum number of threads to run tests in', + description: 'Minimum number or percentage of threads to run tests in', argument: '', }, useAtomics: { @@ -84,11 +84,11 @@ const poolForksCommands: CLIOptions = { description: 'Run tests inside a single child_process (default: `false`)', }, maxForks: { - description: 'Maximum number of processes to run tests in', + description: 'Maximum number or percentage of processes to run tests in', argument: '', }, minForks: { - description: 'Minimum number of processes to run tests in', + description: 'Minimum number or percentage of processes to run tests in', argument: '', }, execArgv: null, From 1615b5691b715361a237ccaea534b0008fcb0dcf Mon Sep 17 00:00:00 2001 From: syi0808 Date: Mon, 1 Jul 2024 02:27:01 +0900 Subject: [PATCH 6/8] feat: allow percent value in poolOptions too --- packages/vitest/src/node/config.ts | 67 ++++++++++++++++++----- packages/vitest/src/types/config.ts | 4 +- packages/vitest/src/types/pool-options.ts | 25 +++++++-- test/config/test/workers-option.test.ts | 21 +++++++ 4 files changed, 98 insertions(+), 19 deletions(-) diff --git a/packages/vitest/src/node/config.ts b/packages/vitest/src/node/config.ts index 6e69a8931b3a..38b01bfb36c9 100644 --- a/packages/vitest/src/node/config.ts +++ b/packages/vitest/src/node/config.ts @@ -16,7 +16,7 @@ import { } from '../constants' import { benchmarkConfigDefaults, configDefaults } from '../defaults' import { isCI, stdProvider, toArray } from '../utils' -import type { BuiltinPool } from '../types/pool-options' +import type { BuiltinPool, ForksOptions, PoolOptions, ThreadsOptions } from '../types/pool-options' import { getWorkersCountByPercentage } from '../utils/workers' import { VitestCache } from './cache' import { BaseSequencer } from './sequencers/BaseSequencer' @@ -98,6 +98,15 @@ export function resolveApiServerConfig( return api } +function resolveInlineWorkerOption(value: string | number): number { + if (typeof value === 'string' && value.trim().endsWith('%')) { + return getWorkersCountByPercentage(value) + } + else { + return Number(value) + } +} + export function resolveConfig( mode: VitestRunMode, options: UserConfig, @@ -177,21 +186,11 @@ export function resolveConfig( } if (resolved.maxWorkers) { - if (typeof options.maxWorkers === 'string' && options.maxWorkers.trim().endsWith('%')) { - resolved.maxWorkers = getWorkersCountByPercentage(options.maxWorkers) - } - else { - resolved.maxWorkers = Number(resolved.maxWorkers) - } + resolved.maxWorkers = resolveInlineWorkerOption(resolved.maxWorkers) } if (resolved.minWorkers) { - if (typeof options.minWorkers === 'string' && options.minWorkers.trim().endsWith('%')) { - resolved.minWorkers = getWorkersCountByPercentage(options.minWorkers) - } - else { - resolved.minWorkers = Number(resolved.minWorkers) - } + resolved.minWorkers = resolveInlineWorkerOption(resolved.minWorkers) } resolved.browser ??= {} as any @@ -447,6 +446,48 @@ export function resolveConfig( } } + const poolThreadsOptions = [ + ['threads', 'minThreads'], + ['threads', 'maxThreads'], + ['vmThreads', 'minThreads'], + ['vmThreads', 'maxThreads'], + ] as const satisfies [keyof PoolOptions, keyof ThreadsOptions][] + + for (const [poolOptionKey, workerOptionKey] of poolThreadsOptions) { + const workerInlineOption = resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey] + + if (workerInlineOption) { + resolved.poolOptions = { + ...resolved.poolOptions, + [poolOptionKey]: { + ...resolved.poolOptions?.[poolOptionKey], + [workerOptionKey]: resolveInlineWorkerOption(workerInlineOption), + }, + } + } + } + + const poolForksOptions = [ + ['forks', 'minForks'], + ['forks', 'maxForks'], + ['vmForks', 'minForks'], + ['vmForks', 'maxForks'], + ] as const satisfies [keyof PoolOptions, keyof ForksOptions][] + + for (const [poolOptionKey, workerOptionKey] of poolForksOptions) { + const workerInlineOption = resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey] + + if (workerInlineOption) { + resolved.poolOptions = { + ...resolved.poolOptions, + [poolOptionKey]: { + ...resolved.poolOptions?.[poolOptionKey], + [workerOptionKey]: resolveInlineWorkerOption(workerInlineOption), + }, + } + } + } + if (resolved.workspace) { // if passed down from the CLI and it's relative, resolve relative to CWD resolved.workspace diff --git a/packages/vitest/src/types/config.ts b/packages/vitest/src/types/config.ts index 6c0ead31f2f7..6b230a80c18e 100644 --- a/packages/vitest/src/types/config.ts +++ b/packages/vitest/src/types/config.ts @@ -17,7 +17,7 @@ import type { SnapshotStateOptions } from './snapshot' import type { Arrayable, ParsedStack } from './general' import type { BenchmarkUserOptions } from './benchmark' import type { BrowserConfigOptions, ResolvedBrowserOptions } from './browser' -import type { Pool, PoolOptions } from './pool-options' +import type { Pool, PoolOptions, ResolvedPoolOptions } from './pool-options' export type { BrowserScript, BrowserConfigOptions } from './browser' export type { SequenceHooks, SequenceSetupFiles } from '@vitest/runner' @@ -969,7 +969,7 @@ export interface ResolvedConfig browser: ResolvedBrowserOptions pool: Pool - poolOptions?: PoolOptions + poolOptions?: ResolvedPoolOptions reporters: (InlineReporter | ReporterWithOptions)[] diff --git a/packages/vitest/src/types/pool-options.ts b/packages/vitest/src/types/pool-options.ts index 25e26c1d8cea..a3fbf8a20d0a 100644 --- a/packages/vitest/src/types/pool-options.ts +++ b/packages/vitest/src/types/pool-options.ts @@ -42,12 +42,19 @@ export interface PoolOptions extends Record { vmForks?: ForksOptions & VmOptions } +export interface ResolvedPoolOptions extends PoolOptions { + threads?: ResolvedThreadsOptions & WorkerContextOptions + forks?: ResolvedForksOptions & WorkerContextOptions + vmThreads?: ResolvedThreadsOptions & VmOptions + vmForks?: ResolvedForksOptions & VmOptions +} + export interface ThreadsOptions { /** Minimum amount of threads to use */ - minThreads?: number + minThreads?: number | string /** Maximum amount of threads to use */ - maxThreads?: number + maxThreads?: number | string /** * Run tests inside a single thread. @@ -66,12 +73,17 @@ export interface ThreadsOptions { useAtomics?: boolean } +export interface ResolvedThreadsOptions extends ThreadsOptions { + minThreads?: number + maxThreads?: number +} + export interface ForksOptions { /** Minimum amount of child processes to use */ - minForks?: number + minForks?: number | string /** Maximum amount of child processes to use */ - maxForks?: number + maxForks?: number | string /** * Run tests inside a single fork. @@ -81,6 +93,11 @@ export interface ForksOptions { singleFork?: boolean } +export interface ResolvedForksOptions extends ForksOptions { + minForks?: number + maxForks?: number +} + export interface WorkerContextOptions { /** * Isolate test environment by recycling `worker_threads` or `child_process` after each test diff --git a/test/config/test/workers-option.test.ts b/test/config/test/workers-option.test.ts index d3d952f82404..2b3a3168506c 100644 --- a/test/config/test/workers-option.test.ts +++ b/test/config/test/workers-option.test.ts @@ -31,3 +31,24 @@ test('workers percent argument should not throw error', async () => { expect(stderr).toBe('') }) + +test.each([ + { poolOption: 'threads' }, + { poolOption: 'vmThreads' }, + { poolOption: 'forks' }, + { poolOption: 'vmForks' }, +] as const)('workers percent argument in $poolOption should not throw error', async ({ poolOption }) => { + let workerOptions = {} + + if (poolOption.toLowerCase().includes('threads')) { + workerOptions = { maxThreads: '100%', minThreads: '10%' } + } + + if (poolOption.toLowerCase().includes('forks')) { + workerOptions = { maxForks: '100%', minForks: '10%' } + } + + const { stderr } = await runVitest({ poolOptions: { [poolOption]: workerOptions } }) + + expect(stderr).toBe('') +}) From aa4706ff22d3e505c0e30d82c5bbe2ee90572657 Mon Sep 17 00:00:00 2001 From: syi0808 Date: Mon, 1 Jul 2024 16:51:49 +0900 Subject: [PATCH 7/8] feat: use availableParallelism instead of cpus.length --- packages/vitest/src/utils/workers.ts | 4 ++-- test/config/test/workers-option.test.ts | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/vitest/src/utils/workers.ts b/packages/vitest/src/utils/workers.ts index 289498e0ea2e..f702219d7578 100644 --- a/packages/vitest/src/utils/workers.ts +++ b/packages/vitest/src/utils/workers.ts @@ -1,7 +1,7 @@ -import { cpus } from 'node:os' +import os from 'node:os' export function getWorkersCountByPercentage(percent: string) { - const maxWorkersCount = cpus().length + const maxWorkersCount = os.availableParallelism?.() ?? os.cpus().length const workersCountByPercentage = Math.round((Number.parseInt(percent) / 100) * maxWorkersCount) return Math.max(1, Math.min(maxWorkersCount, workersCountByPercentage)) diff --git a/test/config/test/workers-option.test.ts b/test/config/test/workers-option.test.ts index 2b3a3168506c..a31fa95f46bf 100644 --- a/test/config/test/workers-option.test.ts +++ b/test/config/test/workers-option.test.ts @@ -4,8 +4,10 @@ import { getWorkersCountByPercentage } from 'vitest/src/utils/workers.js' import * as testUtils from '../../test-utils' vi.mock(import('node:os'), async importOriginal => ({ - ...await importOriginal(), - cpus: () => Array.from({ length: 10 }), + default: { + ...(await importOriginal()).default, + availableParallelism: () => 10, + }, })) describe('workers util', () => { From 786f8f11e10eb53b24ed55154c87565184d14bf8 Mon Sep 17 00:00:00 2001 From: syi0808 Date: Mon, 1 Jul 2024 17:11:47 +0900 Subject: [PATCH 8/8] refactor: add non-null assertion instead of object spread --- packages/vitest/src/node/config.ts | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/packages/vitest/src/node/config.ts b/packages/vitest/src/node/config.ts index 38b01bfb36c9..85359cc02fc5 100644 --- a/packages/vitest/src/node/config.ts +++ b/packages/vitest/src/node/config.ts @@ -454,16 +454,8 @@ export function resolveConfig( ] as const satisfies [keyof PoolOptions, keyof ThreadsOptions][] for (const [poolOptionKey, workerOptionKey] of poolThreadsOptions) { - const workerInlineOption = resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey] - - if (workerInlineOption) { - resolved.poolOptions = { - ...resolved.poolOptions, - [poolOptionKey]: { - ...resolved.poolOptions?.[poolOptionKey], - [workerOptionKey]: resolveInlineWorkerOption(workerInlineOption), - }, - } + if (resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey]) { + resolved.poolOptions[poolOptionKey]![workerOptionKey] = resolveInlineWorkerOption(resolved.poolOptions[poolOptionKey]![workerOptionKey]!) } } @@ -475,16 +467,8 @@ export function resolveConfig( ] as const satisfies [keyof PoolOptions, keyof ForksOptions][] for (const [poolOptionKey, workerOptionKey] of poolForksOptions) { - const workerInlineOption = resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey] - - if (workerInlineOption) { - resolved.poolOptions = { - ...resolved.poolOptions, - [poolOptionKey]: { - ...resolved.poolOptions?.[poolOptionKey], - [workerOptionKey]: resolveInlineWorkerOption(workerInlineOption), - }, - } + if (resolved.poolOptions?.[poolOptionKey]?.[workerOptionKey]) { + resolved.poolOptions[poolOptionKey]![workerOptionKey] = resolveInlineWorkerOption(resolved.poolOptions[poolOptionKey]![workerOptionKey]!) } }