From ba8fd7183db7df0a72b2cab2a37ef1e1e6077185 Mon Sep 17 00:00:00 2001 From: Lenvin Gonsalves <41874033+98lenvi@users.noreply.github.com> Date: Mon, 25 Jul 2022 03:11:46 +0530 Subject: [PATCH] feat: add support for boolean values for `concurrency` option PR-URL: https://github.com/nodejs/node/pull/43887 Fixes: https://github.com/nodejs/node/issues/43837 Reviewed-By: Antoine du Hamel Reviewed-By: Jacob Smith (cherry picked from commit dab492f0444b0a6ae8a41dd1d9605e036c363655) --- README.md | 9 +++++-- lib/internal/per_context/primordials.js | 1 + lib/internal/test_runner/test.js | 12 ++++++--- lib/test.d.ts | 2 +- test/parallel/test-runner-concurrency.js | 31 ++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 test/parallel/test-runner-concurrency.js diff --git a/README.md b/README.md index c67c1bd..5dfaf3a 100644 --- a/README.md +++ b/README.md @@ -328,9 +328,14 @@ internally. does not have a name. - `options` {Object} Configuration options for the test. The following properties are supported: - - `concurrency` {number} The number of tests that can be run at the same time. + - `concurrency` {number|boolean} If a number is provided, + then that many tests would run in parallel. + If truthy, it would run (number of cpu cores - 1) + tests in parallel. + For subtests, it will be `Infinity` tests in parallel. + If falsy, it would only run one test at a time. If unspecified, subtests inherit this value from their parent. - **Default:** `1`. + **Default:** `false`. - `only` {boolean} If truthy, and the test context is configured to run `only` tests, then this test will be run. Otherwise, the test is skipped. **Default:** `false`. diff --git a/lib/internal/per_context/primordials.js b/lib/internal/per_context/primordials.js index 60ed3fc..c5d4e05 100644 --- a/lib/internal/per_context/primordials.js +++ b/lib/internal/per_context/primordials.js @@ -17,6 +17,7 @@ exports.Error = Error exports.ErrorCaptureStackTrace = (...args) => Error.captureStackTrace(...args) exports.FunctionPrototype = Function.prototype exports.FunctionPrototypeBind = (fn, obj, ...args) => fn.bind(obj, ...args) +exports.MathMax = (...args) => Math.max(...args) exports.Number = Number exports.ObjectCreate = obj => Object.create(obj) exports.ObjectDefineProperties = (obj, props) => Object.defineProperties(obj, props) diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js index 98d87d1..f6b9df5 100644 --- a/lib/internal/test_runner/test.js +++ b/lib/internal/test_runner/test.js @@ -1,4 +1,4 @@ -// https://github.com/nodejs/node/blob/d83446b4c4694322e12d2b7d22592f2be674e580/lib/internal/test_runner/test.js +// https://github.com/nodejs/node/blob/dab492f0444b0a6ae8a41dd1d9605e036c363655/lib/internal/test_runner/test.js 'use strict' @@ -7,6 +7,7 @@ const { ArrayPrototypeShift, ArrayPrototypeUnshift, FunctionPrototype, + MathMax, Number, PromisePrototypeThen, PromiseResolve, @@ -55,8 +56,7 @@ const noop = FunctionPrototype const isTestRunner = getOptionValue('--test') const testOnlyFlag = !isTestRunner && getOptionValue('--test-only') // TODO(cjihrig): Use uv_available_parallelism() once it lands. -const rootConcurrency = isTestRunner ? cpus().length : 1 - +const rootConcurrency = isTestRunner ? MathMax(cpus().length - 1, 1) : 1 const kShouldAbort = Symbol('kShouldAbort') function stopTest (timeout, signal) { @@ -154,6 +154,12 @@ class Test extends AsyncResource { if (isUint32(concurrency) && concurrency !== 0) { this.concurrency = concurrency + } else if (typeof concurrency === 'boolean') { + if (concurrency) { + this.concurrency = isTestRunner ? MathMax(cpus().length - 1, 1) : Infinity + } else { + this.concurrency = 1 + } } if (timeout != null && timeout !== Infinity) { diff --git a/lib/test.d.ts b/lib/test.d.ts index 8d07336..5a21c5b 100644 --- a/lib/test.d.ts +++ b/lib/test.d.ts @@ -3,7 +3,7 @@ interface TestOptions { * The number of tests that can be run at the same time. If unspecified, subtests inherit this value from their parent. * Default: 1. */ - concurrency?: number + concurrency?: boolean | number /** * If truthy, the test is skipped. If a string is provided, that string is displayed in the test results as the reason for skipping the test. diff --git a/test/parallel/test-runner-concurrency.js b/test/parallel/test-runner-concurrency.js new file mode 100644 index 0000000..7b811a0 --- /dev/null +++ b/test/parallel/test-runner-concurrency.js @@ -0,0 +1,31 @@ +// https://github.com/nodejs/node/blob/dab492f0444b0a6ae8a41dd1d9605e036c363655/test/parallel/test-runner-concurrency.js + +'use strict' +require('../common') +const { describe, it } = require('node:test') +const assert = require('assert') + +describe('Concurrency option (boolean) = true ', { concurrency: true }, () => { + let isFirstTestOver = false + it('should start the first test', () => new Promise((resolve) => { + setImmediate(() => { isFirstTestOver = true; resolve() }) + })) + it('should start before the previous test ends', () => { + // Should work even on single core CPUs + assert.strictEqual(isFirstTestOver, false) + }) +}) + +describe( + 'Concurrency option (boolean) = false ', + { concurrency: false }, + () => { + let isFirstTestOver = false + it('should start the first test', () => new Promise((resolve) => { + setImmediate(() => { isFirstTestOver = true; resolve() }) + })) + it('should start after the previous test ends', () => { + assert.strictEqual(isFirstTestOver, true) + }) + } +)