@@ -2,7 +2,7 @@ import cp from 'node:child_process';
22import { randomUUID } from 'node:crypto' ;
33import fs from 'node:fs' ;
44import fsPromises from 'node:fs/promises' ;
5- import { tmpdir } from 'node:os' ;
5+ import { cpus , tmpdir } from 'node:os' ;
66import path from 'node:path' ;
77import { debuglog , parseArgs , promisify } from 'node:util' ;
88
@@ -16,6 +16,44 @@ const exec = async (command: string, options: cp.ExecOptionsWithStringEncoding)
1616 process . platform === 'win32' ? { ...options , shell : 'pwsh.exe' } : options ,
1717 ) ;
1818
19+ /**
20+ * Run tasks with limited concurrency based on CPU count.
21+ * @param tasks Array of task functions to execute
22+ * @param maxConcurrency Maximum number of concurrent tasks (defaults to CPU count)
23+ */
24+ async function runWithConcurrencyLimit (
25+ tasks : ( ( ) => Promise < void > ) [ ] ,
26+ maxConcurrency = cpus ( ) . length ,
27+ ) : Promise < void > {
28+ const executing : Promise < void > [ ] = [ ] ;
29+ const errors : Error [ ] = [ ] ;
30+
31+ for ( const task of tasks ) {
32+ const promise = task ( )
33+ . catch ( ( error ) => {
34+ errors . push ( error ) ;
35+ console . error ( 'Task failed:' , error ) ;
36+ } )
37+ . finally ( ( ) => {
38+ executing . splice ( executing . indexOf ( promise ) , 1 ) ;
39+ } ) ;
40+
41+ executing . push ( promise ) ;
42+
43+ if ( executing . length >= maxConcurrency ) {
44+ await Promise . race ( executing ) ;
45+ }
46+ }
47+
48+ await Promise . all ( executing ) ;
49+
50+ if ( errors . length > 0 ) {
51+ throw new Error (
52+ `${ errors . length } test case(s) failed. First error: ${ errors [ 0 ] . message } ` ,
53+ ) ;
54+ }
55+ }
56+
1957export async function snapTest ( ) {
2058 const { positionals } = parseArgs ( {
2159 allowPositionals : true ,
@@ -41,16 +79,22 @@ export async function snapTest() {
4179
4280 const casesDir = path . resolve ( 'snap-tests' ) ;
4381
44- const tasks : Promise < void > [ ] = [ ] ;
82+ const taskFunctions : ( ( ) => Promise < void > ) [ ] = [ ] ;
4583 for ( const caseName of fs . readdirSync ( casesDir ) ) {
4684 if ( caseName . startsWith ( '.' ) ) continue ; // Skip hidden files like .DS_Store
4785 if ( caseName . includes ( filter ) ) {
48- tasks . push ( runTestCase ( caseName , tempTmpDir , casesDir ) ) ;
86+ taskFunctions . push ( ( ) => runTestCase ( caseName , tempTmpDir , casesDir ) ) ;
4987 }
5088 }
5189
52- if ( tasks . length > 0 ) {
53- await Promise . all ( tasks ) ;
90+ if ( taskFunctions . length > 0 ) {
91+ const cpuCount = cpus ( ) . length ;
92+ console . log (
93+ 'Running %d test cases with concurrency limit of %d (CPU count)' ,
94+ taskFunctions . length ,
95+ cpuCount ,
96+ ) ;
97+ await runWithConcurrencyLimit ( taskFunctions , cpuCount ) ;
5498 }
5599}
56100
0 commit comments