@@ -8,7 +8,13 @@ import * as os from 'os'
8
8
import * as path from 'path'
9
9
import * as sinon from 'sinon'
10
10
import { 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'
12
18
import { sleep } from '../../../shared/utilities/timeoutUtils'
13
19
import { Timeout , waitUntil } from '../../../shared/utilities/timeoutUtils'
14
20
import { fs } from '../../../shared'
@@ -356,21 +362,24 @@ describe('ChildProcess', async function () {
356
362
}
357
363
} )
358
364
365
+ interface RunningProcess {
366
+ childProcess : ChildProcess
367
+ result : Promise < ChildProcessResult >
368
+ }
369
+
359
370
function getSleepCmd ( ) {
360
371
return isWin ( ) ? 'timeout' : 'sleep'
361
372
}
362
373
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
368
377
}
369
378
370
- function startSleepProcess ( timeout : number = 90 ) {
379
+ function startSleepProcess ( timeout : number = 90 ) : RunningProcess {
371
380
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 }
374
383
}
375
384
376
385
describe ( 'ChildProcessTracker' , function ( ) {
@@ -395,41 +404,51 @@ describe('ChildProcessTracker', function () {
395
404
396
405
it ( `removes stopped processes every ${ ChildProcessTracker . pollingInterval / 1000 } seconds` , async function ( ) {
397
406
// 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' )
401
410
402
411
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 )
405
414
406
415
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' )
408
417
} )
409
418
for ( const _ of Array . from ( { length : 1000 } ) ) {
410
419
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 )
415
424
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' )
418
427
419
- await stopAndWait ( childProcess1 , clock )
428
+ await stopAndWait ( runningProcess1 )
420
429
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' )
427
446
} )
428
447
}
429
448
430
449
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 )
433
452
434
453
const highCpu : ProcessStats = {
435
454
cpu : ChildProcessTracker . thresholds . cpu + 1 ,
@@ -448,24 +467,27 @@ describe('ChildProcessTracker', function () {
448
467
usageMock . resolves ( highMemory )
449
468
await clock . tickAsync ( ChildProcessTracker . pollingInterval )
450
469
assertLogsContain ( 'exceeded memory threshold' , false , 'warn' )
470
+
471
+ await stopAndWait ( runningProcess )
451
472
} )
452
473
453
474
it ( 'includes pid in logs' , async function ( ) {
454
- const childProcess = startSleepProcess ( )
455
- tracker . add ( childProcess )
475
+ const runningProcess = startSleepProcess ( )
476
+ tracker . add ( runningProcess . childProcess )
456
477
457
478
usageMock . resolves ( {
458
479
cpu : ChildProcessTracker . thresholds . cpu + 1 ,
459
480
memory : 0 ,
460
481
} )
461
482
462
483
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 )
464
487
} )
465
488
466
489
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 ( )
469
491
470
492
usageMock . resolves ( {
471
493
cpu : ChildProcessTracker . thresholds . cpu - 1 ,
@@ -474,6 +496,8 @@ describe('ChildProcessTracker', function () {
474
496
475
497
await clock . tickAsync ( ChildProcessTracker . pollingInterval )
476
498
477
- assert . throws ( ( ) => assertLogsContain ( childProcess . pid ( ) . toString ( ) , false , 'warn' ) )
499
+ assert . throws ( ( ) => assertLogsContain ( runningProcess . childProcess . pid ( ) . toString ( ) , false , 'warn' ) )
500
+
501
+ await stopAndWait ( runningProcess )
478
502
} )
479
503
} )
0 commit comments