@@ -7,12 +7,15 @@ import assert from 'assert'
7
7
import * as os from 'os'
8
8
import * as path from 'path'
9
9
import { makeTemporaryToolkitFolder , tryRemoveFolder } from '../../../shared/filesystemUtilities'
10
- import { ChildProcess , ChildProcessTracker , eof } from '../../../shared/utilities/processUtils'
10
+ import { ChildProcess , ChildProcessTracker , eof , ProcessStats } from '../../../shared/utilities/processUtils'
11
11
import { sleep } from '../../../shared/utilities/timeoutUtils'
12
12
import { Timeout , waitUntil } from '../../../shared/utilities/timeoutUtils'
13
13
import { fs } from '../../../shared'
14
14
import * as FakeTimers from '@sinonjs/fake-timers'
15
15
import { installFakeClock } from '../../testUtil'
16
+ import { isWin } from '../../../shared/vscode/env'
17
+ import Sinon from 'sinon'
18
+ import { assertLogsContain } from '../../globalSetup.test'
16
19
17
20
describe ( 'ChildProcess' , async function ( ) {
18
21
let tempFolder : string
@@ -353,6 +356,10 @@ describe('ChildProcess', async function () {
353
356
}
354
357
} )
355
358
359
+ function getSleepCmd ( ) {
360
+ return isWin ( ) ? 'timeout' : 'sleep'
361
+ }
362
+
356
363
describe ( 'ChildProcessTracker' , function ( ) {
357
364
let tracker : ChildProcessTracker
358
365
let clock : FakeTimers . InstalledClock
@@ -361,13 +368,80 @@ describe('ChildProcessTracker', function () {
361
368
tracker = new ChildProcessTracker ( )
362
369
} )
363
370
364
- it ( 'removes stopped processes every X seconds' , async function ( ) {
365
- const childProcess = new ChildProcess ( 'echo' , [ 'hi' ] )
366
- await childProcess . run ( )
371
+ it ( `removes stopped processes every ${ ChildProcessTracker . pollingInterval / 1000 } seconds` , async function ( ) {
372
+ // Start a 'sleep' command, check it only removes after we stop it.
373
+ const childProcess = new ChildProcess ( getSleepCmd ( ) , [ '90' ] )
374
+ childProcess . run ( ) . catch ( ( ) => assert . fail ( 'sleep command threw an error' ) )
375
+ tracker . add ( childProcess )
376
+ assert . strictEqual ( tracker . has ( childProcess ) , true , 'failed to add sleep command' )
377
+
378
+ await clock . tickAsync ( ChildProcessTracker . pollingInterval )
379
+ assert . strictEqual ( tracker . has ( childProcess ) , true , 'process was mistakenly removed' )
380
+ childProcess . stop ( true )
381
+
382
+ await clock . tickAsync ( ChildProcessTracker . pollingInterval )
383
+ assert . strictEqual ( tracker . has ( childProcess ) , false , 'process was not removed after stopping' )
384
+ } )
385
+
386
+ it ( 'multiple processes from same command are tracked seperately' , async function ( ) {
387
+ const childProcess1 = new ChildProcess ( getSleepCmd ( ) , [ '90' ] )
388
+ const childProcess2 = new ChildProcess ( getSleepCmd ( ) , [ '90' ] )
389
+ childProcess1 . run ( ) . catch ( ( ) => assert . fail ( 'sleep command threw an error' ) )
390
+ childProcess2 . run ( ) . catch ( ( ) => assert . fail ( 'sleep command threw an error' ) )
391
+
392
+ tracker . add ( childProcess1 )
393
+ tracker . add ( childProcess2 )
394
+
395
+ assert . strictEqual ( tracker . has ( childProcess1 ) , true , 'Missing first process' )
396
+ assert . strictEqual ( tracker . has ( childProcess2 ) , true , 'Missing second process' )
397
+ assert . strictEqual ( tracker . size ( ) , 2 )
398
+
399
+ childProcess1 . stop ( )
400
+ await clock . tickAsync ( ChildProcessTracker . pollingInterval + 1 )
401
+ assert . strictEqual ( tracker . has ( childProcess2 ) , true , 'first process was not removed after stopping it' )
402
+ assert . strictEqual ( tracker . size ( ) , 1 )
403
+
404
+ childProcess2 . stop ( )
405
+ await clock . tickAsync ( ChildProcessTracker . pollingInterval + 1 )
406
+ assert . strictEqual ( tracker . size ( ) , 0 , 'second process was not removed after stopping it' )
407
+ } )
408
+
409
+ it ( 'logs a warning message when system usage exceeds threshold' , async function ( ) {
410
+ const childProcess = new ChildProcess ( getSleepCmd ( ) , [ '90' ] )
411
+ childProcess . run ( ) . catch ( ( ) => assert . fail ( 'sleep command threw an error' ) )
367
412
tracker . add ( childProcess )
368
- childProcess . stop ( )
369
- assert . strictEqual ( tracker . has ( childProcess ) , true )
413
+
414
+ const usageMock = Sinon . stub ( ChildProcessTracker . prototype , 'getUsage' )
415
+ const highCpu : ProcessStats = {
416
+ cpu : ChildProcessTracker . thresholds . cpu + 1 ,
417
+ memory : 0 ,
418
+ elapsed : 0 ,
419
+ }
420
+ const highMemory : ProcessStats = {
421
+ cpu : 0 ,
422
+ memory : ChildProcessTracker . thresholds . memory + 1 ,
423
+ elapsed : 0 ,
424
+ }
425
+
426
+ const highTime : ProcessStats = {
427
+ cpu : 0 ,
428
+ memory : 0 ,
429
+ elapsed : ChildProcessTracker . thresholds . elapsed + 1 ,
430
+ }
431
+
432
+ usageMock . resolves ( highCpu )
433
+
434
+ await clock . tickAsync ( ChildProcessTracker . pollingInterval )
435
+ assertLogsContain ( 'exceeded cpu threshold' , false , 'warn' )
436
+
437
+ usageMock . resolves ( highMemory )
370
438
await clock . tickAsync ( ChildProcessTracker . pollingInterval )
371
- assert . strictEqual ( tracker . has ( childProcess ) , false )
439
+ assertLogsContain ( 'exceeded memory threshold' , false , 'warn' )
440
+
441
+ usageMock . resolves ( highTime )
442
+ await clock . tickAsync ( ChildProcessTracker . pollingInterval )
443
+ assertLogsContain ( 'exceeded time threshold' , false , 'warn' )
444
+
445
+ usageMock . restore ( )
372
446
} )
373
447
} )
0 commit comments