@@ -7,14 +7,15 @@ import assert from 'assert'
7
7
import * as vscode from 'vscode'
8
8
import * as sinon from 'sinon'
9
9
import * as semver from 'semver'
10
+ import * as process from 'process'
10
11
import { DefaultCodeWhispererClient } from '../../../codewhisperer/client/codewhisperer'
11
12
import * as startSecurityScan from '../../../codewhisperer/commands/startSecurityScan'
12
13
import { SecurityPanelViewProvider } from '../../../codewhisperer/views/securityPanelViewProvider'
13
14
import { FakeExtensionContext } from '../../fakeExtensionContext'
14
15
import * as diagnosticsProvider from '../../../codewhisperer/service/diagnosticsProvider'
15
16
import { getTestWorkspaceFolder } from '../../../testInteg/integrationTestsUtilities'
16
17
import { join } from 'path'
17
- import { assertTelemetry , closeAllEditors } from '../../testUtil'
18
+ import { assertTelemetry , closeAllEditors , createTestWorkspaceFolder , toFile } from '../../testUtil'
18
19
import { stub } from '../../utilities/stubber'
19
20
import { AWSError , HttpResponse } from 'aws-sdk'
20
21
import { getTestWindow } from '../../shared/vscode/window'
@@ -134,7 +135,6 @@ let editor: vscode.TextEditor
134
135
135
136
describe ( 'startSecurityScan' , function ( ) {
136
137
const workspaceFolder = getTestWorkspaceFolder ( )
137
-
138
138
beforeEach ( async function ( ) {
139
139
extensionContext = await FakeExtensionContext . create ( )
140
140
mockSecurityPanelViewProvider = new SecurityPanelViewProvider ( extensionContext )
@@ -449,3 +449,92 @@ describe('startSecurityScan', function () {
449
449
} as unknown as CodewhispererSecurityScan )
450
450
} )
451
451
} )
452
+
453
+ describe ( 'startSecurityScanPerformanceTest' , function ( ) {
454
+ beforeEach ( async function ( ) {
455
+ extensionContext = await FakeExtensionContext . create ( )
456
+ mockSecurityPanelViewProvider = new SecurityPanelViewProvider ( extensionContext )
457
+ const folder = await createTestWorkspaceFolder ( )
458
+ const mockFilePath = join ( folder . uri . fsPath , 'app.py' )
459
+ await toFile ( 'hello_world' , mockFilePath )
460
+ appCodePath = mockFilePath
461
+ editor = await openTestFile ( appCodePath )
462
+ await model . CodeScansState . instance . setScansEnabled ( false )
463
+ sinon . stub ( timeoutUtils , 'sleep' )
464
+ } )
465
+
466
+ afterEach ( function ( ) {
467
+ sinon . restore ( )
468
+ } )
469
+
470
+ after ( async function ( ) {
471
+ await closeAllEditors ( )
472
+ } )
473
+
474
+ const createClient = ( ) => {
475
+ const mockClient = stub ( DefaultCodeWhispererClient )
476
+ mockClient . createCodeScan . resolves ( mockCreateCodeScanResponse )
477
+ mockClient . createUploadUrl . resolves ( mockCreateUploadUrlResponse )
478
+ mockClient . getCodeScan . resolves ( mockGetCodeScanResponse )
479
+ mockClient . listCodeScanFindings . resolves ( mockListCodeScanFindingsResponse )
480
+ return mockClient
481
+ }
482
+
483
+ const openTestFile = async ( filePath : string ) => {
484
+ const doc = await vscode . workspace . openTextDocument ( filePath )
485
+ return await vscode . window . showTextDocument ( doc , {
486
+ selection : new vscode . Range ( new vscode . Position ( 0 , 0 ) , new vscode . Position ( 0 , 1 ) ) ,
487
+ } )
488
+ }
489
+
490
+ it ( 'Should calculate cpu and memory usage for file scans' , async function ( ) {
491
+ getFetchStubWithResponse ( { status : 200 , statusText : 'testing stub' } )
492
+ const commandSpy = sinon . spy ( vscode . commands , 'executeCommand' )
493
+ const securityScanRenderSpy = sinon . spy ( diagnosticsProvider , 'initSecurityScanRender' )
494
+
495
+ await model . CodeScansState . instance . setScansEnabled ( true )
496
+ const startTime = process . hrtime ( )
497
+ const startScanCpuUsage = process . cpuUsage ( )
498
+
499
+ await startSecurityScan . startSecurityScan (
500
+ mockSecurityPanelViewProvider ,
501
+ editor ,
502
+ createClient ( ) ,
503
+ extensionContext ,
504
+ CodeAnalysisScope . FILE
505
+ )
506
+
507
+ // EndScanCpuUsage is the difference of CPU Usage from start of a scan to end of a scan.
508
+ const EndScanCpuUsage = process . cpuUsage ( startScanCpuUsage )
509
+ const elapsedTime = process . hrtime ( startTime )
510
+ const elapsedSeconds = elapsedTime [ 0 ] + elapsedTime [ 1 ] / 1e9
511
+
512
+ const EndScanCpuUsageByUser = EndScanCpuUsage . user / 1000000 // Convert microseconds to seconds
513
+ const EndScanCpuUsageBySystem = EndScanCpuUsage . system / 1000000
514
+
515
+ const EndScanMemoryUsage = process . memoryUsage ( ) . heapTotal
516
+ const EndScanMemoryUsageInMB = EndScanMemoryUsage / ( 1024 * 1024 ) // Converting bytes to MB
517
+
518
+ const cpuUsagePercentage = ( ( EndScanCpuUsageByUser + EndScanCpuUsageBySystem ) / elapsedSeconds ) * 100
519
+
520
+ // These limits are considered after some observations but may vary with machine, OS etc factors.
521
+ assert (
522
+ cpuUsagePercentage < 50 ,
523
+ `Expected CPU usage should be less than 50% of total CPU%, actual CPU usage is ${ cpuUsagePercentage } `
524
+ )
525
+
526
+ assert (
527
+ EndScanMemoryUsageInMB < 400 ,
528
+ 'System memory usage for performing a file scan should not be greater than 400 MB'
529
+ )
530
+
531
+ assert . ok ( commandSpy . neverCalledWith ( 'workbench.action.problems.focus' ) )
532
+ assert . ok ( securityScanRenderSpy . calledOnce )
533
+ const warnings = getTestWindow ( ) . shownMessages . filter ( ( m ) => m . severity === SeverityLevel . Warning )
534
+ assert . strictEqual ( warnings . length , 0 )
535
+ assertTelemetry ( 'codewhisperer_securityScan' , {
536
+ codewhispererCodeScanScope : 'FILE' ,
537
+ passive : true ,
538
+ } )
539
+ } )
540
+ } )
0 commit comments