@@ -8,7 +8,13 @@ import * as os from 'os'
88import * as path from 'path'
99import * as sinon from 'sinon'
1010import { makeTemporaryToolkitFolder , tryRemoveFolder } from '../../../shared/filesystemUtilities'
11- import { ChildProcess , ChildProcessTracker , eof , ProcessStats } from '../../../shared/utilities/processUtils'
11+ import {
12+ ChildProcess ,
13+ ChildProcessResult ,
14+ ChildProcessTracker ,
15+ eof ,
16+ ProcessStats ,
17+ } from '../../../shared/utilities/processUtils'
1218import { sleep } from '../../../shared/utilities/timeoutUtils'
1319import { Timeout , waitUntil } from '../../../shared/utilities/timeoutUtils'
1420import { fs } from '../../../shared'
@@ -356,21 +362,24 @@ describe('ChildProcess', async function () {
356362 }
357363} )
358364
365+ interface RunningProcess {
366+ childProcess : ChildProcess
367+ result : Promise < ChildProcessResult >
368+ }
369+
359370function getSleepCmd ( ) {
360371 return isWin ( ) ? 'timeout' : 'sleep'
361372}
362373
363- // ChildProcess.stop is non-async and doesn't wait for the process to be stopped.
364- async function stopAndWait ( cp : ChildProcess , clock : FakeTimers . InstalledClock ) {
365- cp . stop ( true )
366- await clock . tickAsync ( ChildProcess . stopTimeout * 2 )
367- assert . ok ( cp . stopped , `Failed to stop process with id: ${ cp . pid ( ) } ` )
374+ async function stopAndWait ( runningProcess : RunningProcess ) : Promise < void > {
375+ runningProcess . childProcess . stop ( true )
376+ await runningProcess . result
368377}
369378
370- function startSleepProcess ( timeout : number = 90 ) {
379+ function startSleepProcess ( timeout : number = 90 ) : RunningProcess {
371380 const childProcess = new ChildProcess ( getSleepCmd ( ) , [ timeout . toString ( ) ] )
372- childProcess . run ( ) . catch ( ( ) => assert . fail ( 'sleep command threw an error' ) )
373- return childProcess
381+ const result = childProcess . run ( ) . catch ( ( ) => assert . fail ( 'sleep command threw an error' ) )
382+ return { childProcess, result }
374383}
375384
376385describe ( 'ChildProcessTracker' , function ( ) {
@@ -395,41 +404,51 @@ describe('ChildProcessTracker', function () {
395404
396405 it ( `removes stopped processes every ${ ChildProcessTracker . pollingInterval / 1000 } seconds` , async function ( ) {
397406 // Start a 'sleep' command, check it only removes after we stop it.
398- const childProcess = startSleepProcess ( )
399- tracker . add ( childProcess )
400- assert . strictEqual ( tracker . has ( childProcess ) , true , 'failed to add sleep command' )
407+ const runningProcess = startSleepProcess ( )
408+ tracker . add ( runningProcess . childProcess )
409+ assert . strictEqual ( tracker . has ( runningProcess . childProcess ) , true , 'failed to add sleep command' )
401410
402411 await clock . tickAsync ( ChildProcessTracker . pollingInterval )
403- assert . strictEqual ( tracker . has ( childProcess ) , true , 'process was mistakenly removed' )
404- await stopAndWait ( childProcess , clock )
412+ assert . strictEqual ( tracker . has ( runningProcess . childProcess ) , true , 'process was mistakenly removed' )
413+ await stopAndWait ( runningProcess )
405414
406415 await clock . tickAsync ( ChildProcessTracker . pollingInterval )
407- assert . strictEqual ( tracker . has ( childProcess ) , false , 'process was not removed after stopping' )
416+ assert . strictEqual ( tracker . has ( runningProcess . childProcess ) , false , 'process was not removed after stopping' )
408417 } )
409418 for ( const _ of Array . from ( { length : 1000 } ) ) {
410419 it ( 'multiple processes from same command are tracked seperately' , async function ( ) {
411- const childProcess1 = startSleepProcess ( )
412- const childProcess2 = startSleepProcess ( )
413- tracker . add ( childProcess1 )
414- tracker . add ( childProcess2 )
420+ const runningProcess1 = startSleepProcess ( )
421+ const runningProcess2 = startSleepProcess ( )
422+ tracker . add ( runningProcess1 . childProcess )
423+ tracker . add ( runningProcess2 . childProcess )
415424
416- assert . strictEqual ( tracker . has ( childProcess1 ) , true , 'Missing first process' )
417- assert . strictEqual ( tracker . has ( childProcess2 ) , true , 'Missing second process' )
425+ assert . strictEqual ( tracker . has ( runningProcess1 . childProcess ) , true , 'Missing first process' )
426+ assert . strictEqual ( tracker . has ( runningProcess2 . childProcess ) , true , 'Missing second process' )
418427
419- await stopAndWait ( childProcess1 , clock )
428+ await stopAndWait ( runningProcess1 )
420429 await clock . tickAsync ( ChildProcessTracker . pollingInterval )
421- if ( tracker . has ( childProcess1 ) ) {
422- console . log ( 'process: %O' , childProcess1 )
423- console . log ( 'tracker: %O' , tracker )
424- }
425- assert . strictEqual ( tracker . has ( childProcess2 ) , true , 'second process was mistakenly removed' )
426- assert . strictEqual ( tracker . has ( childProcess1 ) , false , 'first process was not removed after stopping it' )
430+ assert . strictEqual ( tracker . has ( runningProcess2 . childProcess ) , true , 'second process was mistakenly removed' )
431+ assert . strictEqual (
432+ tracker . has ( runningProcess1 . childProcess ) ,
433+ false ,
434+ 'first process was not removed after stopping it'
435+ )
436+
437+ await stopAndWait ( runningProcess2 )
438+ await clock . tickAsync ( ChildProcessTracker . pollingInterval )
439+ assert . strictEqual (
440+ tracker . has ( runningProcess2 . childProcess ) ,
441+ false ,
442+ 'second process was not removed after stopping it'
443+ )
444+
445+ assert . strictEqual ( tracker . size ( ) , 0 , 'expected tracker to be empty' )
427446 } )
428447 }
429448
430449 it ( 'logs a warning message when system usage exceeds threshold' , async function ( ) {
431- const childProcess = startSleepProcess ( )
432- tracker . add ( childProcess )
450+ const runningProcess = startSleepProcess ( )
451+ tracker . add ( runningProcess . childProcess )
433452
434453 const highCpu : ProcessStats = {
435454 cpu : ChildProcessTracker . thresholds . cpu + 1 ,
@@ -448,24 +467,27 @@ describe('ChildProcessTracker', function () {
448467 usageMock . resolves ( highMemory )
449468 await clock . tickAsync ( ChildProcessTracker . pollingInterval )
450469 assertLogsContain ( 'exceeded memory threshold' , false , 'warn' )
470+
471+ await stopAndWait ( runningProcess )
451472 } )
452473
453474 it ( 'includes pid in logs' , async function ( ) {
454- const childProcess = startSleepProcess ( )
455- tracker . add ( childProcess )
475+ const runningProcess = startSleepProcess ( )
476+ tracker . add ( runningProcess . childProcess )
456477
457478 usageMock . resolves ( {
458479 cpu : ChildProcessTracker . thresholds . cpu + 1 ,
459480 memory : 0 ,
460481 } )
461482
462483 await clock . tickAsync ( ChildProcessTracker . pollingInterval )
463- assertLogsContain ( childProcess . pid ( ) . toString ( ) , false , 'warn' )
484+ assertLogsContain ( runningProcess . childProcess . pid ( ) . toString ( ) , false , 'warn' )
485+
486+ await stopAndWait ( runningProcess )
464487 } )
465488
466489 it ( 'does not log for processes within threshold' , async function ( ) {
467- const childProcess = new ChildProcess ( getSleepCmd ( ) , [ '90' ] )
468- childProcess . run ( ) . catch ( ( ) => assert . fail ( 'sleep command threw an error' ) )
490+ const runningProcess = startSleepProcess ( )
469491
470492 usageMock . resolves ( {
471493 cpu : ChildProcessTracker . thresholds . cpu - 1 ,
@@ -474,6 +496,8 @@ describe('ChildProcessTracker', function () {
474496
475497 await clock . tickAsync ( ChildProcessTracker . pollingInterval )
476498
477- assert . throws ( ( ) => assertLogsContain ( childProcess . pid ( ) . toString ( ) , false , 'warn' ) )
499+ assert . throws ( ( ) => assertLogsContain ( runningProcess . childProcess . pid ( ) . toString ( ) , false , 'warn' ) )
500+
501+ await stopAndWait ( runningProcess )
478502 } )
479503} )
0 commit comments