Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,130 +7,28 @@ import assert from 'assert'
import * as vscode from 'vscode'
import * as sinon from 'sinon'
import * as semver from 'semver'
import { DefaultCodeWhispererClient } from '../../../codewhisperer/client/codewhisperer'
import * as startSecurityScan from '../../../codewhisperer/commands/startSecurityScan'
import { SecurityPanelViewProvider } from '../../../codewhisperer/views/securityPanelViewProvider'
import { FakeExtensionContext } from '../../fakeExtensionContext'
import * as diagnosticsProvider from '../../../codewhisperer/service/diagnosticsProvider'
import { getTestWorkspaceFolder } from '../../../testInteg/integrationTestsUtilities'
import * as startSecurityScan from '../../codewhisperer/commands/startSecurityScan'
import { SecurityPanelViewProvider } from '../../codewhisperer/views/securityPanelViewProvider'
import { FakeExtensionContext } from '../fakeExtensionContext'
import * as diagnosticsProvider from '../../codewhisperer/service/diagnosticsProvider'
import { getTestWorkspaceFolder } from '../../testInteg/integrationTestsUtilities'
import { join } from 'path'
import {
assertTelemetry,
closeAllEditors,
createTestWorkspaceFolder,
getFetchStubWithResponse,
toFile,
} from '../../testUtil'
import { stub } from '../../utilities/stubber'
import { AWSError, HttpResponse } from 'aws-sdk'
import { getTestWindow } from '../../shared/vscode/window'
import { SeverityLevel } from '../../shared/vscode/message'
import { cancel } from '../../../shared/localizedText'
import { assertTelemetry, closeAllEditors, getFetchStubWithResponse } from '../testUtil'
import { AWSError } from 'aws-sdk'
import { getTestWindow } from '../shared/vscode/window'
import { SeverityLevel } from '../shared/vscode/message'
import { cancel } from '../../shared/localizedText'
import {
showScannedFilesMessage,
stopScanMessage,
CodeAnalysisScope,
projectScansLimitReached,
} from '../../../codewhisperer/models/constants'
import * as model from '../../../codewhisperer/models/model'
import { CodewhispererSecurityScan } from '../../../shared/telemetry/telemetry.gen'
import * as errors from '../../../shared/errors'
import * as timeoutUtils from '../../../shared/utilities/timeoutUtils'
import { performanceTest } from '../../../shared/performance/performance'

const mockCreateCodeScanResponse = {
$response: {
data: {
jobId: 'jobId',
status: 'Pending',
},
requestId: 'requestId',
hasNextPage: () => false,
error: undefined,
nextPage: () => undefined,
redirectCount: 0,
retryCount: 0,
httpResponse: new HttpResponse(),
},
jobId: 'jobId',
status: 'Pending',
}

const mockCreateUploadUrlResponse = {
$response: {
data: {
uploadId: 'uploadId',
uploadUrl: 'uploadUrl',
},
requestId: 'requestId',
hasNextPage: () => false,
error: undefined,
nextPage: () => undefined,
redirectCount: 0,
retryCount: 0,
httpResponse: new HttpResponse(),
},
uploadId: 'uploadId',
uploadUrl: 'https://test.com',
}

const mockGetCodeScanResponse = {
$response: {
data: {
status: 'Completed',
},
requestId: 'requestId',
hasNextPage: () => false,
error: undefined,
nextPage: () => undefined,
redirectCount: 0,
retryCount: 0,
httpResponse: new HttpResponse(),
},
status: 'Completed',
}

const mockCodeScanFindings = JSON.stringify([
{
filePath: 'workspaceFolder/python3.7-plain-sam-app/hello_world/app.py',
startLine: 1,
endLine: 1,
title: 'title',
description: {
text: 'text',
markdown: 'markdown',
},
detectorId: 'detectorId',
detectorName: 'detectorName',
findingId: 'findingId',
relatedVulnerabilities: [],
severity: 'High',
remediation: {
recommendation: {
text: 'text',
url: 'url',
},
suggestedFixes: [],
},
codeSnippet: [],
} satisfies model.RawCodeScanIssue,
])

const mockListCodeScanFindingsResponse = {
$response: {
data: {
codeScanFindings: mockCodeScanFindings,
},
requestId: 'requestId',
hasNextPage: () => false,
error: undefined,
nextPage: () => undefined,
redirectCount: 0,
retryCount: 0,
httpResponse: new HttpResponse(),
},
codeScanFindings: mockCodeScanFindings,
}
} from '../../codewhisperer/models/constants'
import * as model from '../../codewhisperer/models/model'
import { CodewhispererSecurityScan } from '../../shared/telemetry/telemetry.gen'
import * as errors from '../../shared/errors'
import * as timeoutUtils from '../../shared/utilities/timeoutUtils'
import { createClient, mockGetCodeScanResponse } from './testUtil'

let extensionContext: FakeExtensionContext
let mockSecurityPanelViewProvider: SecurityPanelViewProvider
Expand All @@ -155,15 +53,6 @@ describe('startSecurityScan', function () {
after(async function () {
await closeAllEditors()
})
const createClient = () => {
const mockClient = stub(DefaultCodeWhispererClient)

mockClient.createCodeScan.resolves(mockCreateCodeScanResponse)
mockClient.createUploadUrl.resolves(mockCreateUploadUrlResponse)
mockClient.getCodeScan.resolves(mockGetCodeScanResponse)
mockClient.listCodeScanFindings.resolves(mockListCodeScanFindingsResponse)
return mockClient
}

const openTestFile = async (filePath: string) => {
const doc = await vscode.workspace.openTextDocument(filePath)
Expand Down Expand Up @@ -454,78 +343,3 @@ describe('startSecurityScan', function () {
} as unknown as CodewhispererSecurityScan)
})
})

describe('startSecurityScanPerformanceTest', function () {
beforeEach(async function () {
extensionContext = await FakeExtensionContext.create()
mockSecurityPanelViewProvider = new SecurityPanelViewProvider(extensionContext)
const folder = await createTestWorkspaceFolder()
const mockFilePath = join(folder.uri.fsPath, 'app.py')
await toFile('hello_world', mockFilePath)
appCodePath = mockFilePath
editor = await openTestFile(appCodePath)
await model.CodeScansState.instance.setScansEnabled(false)
sinon.stub(timeoutUtils, 'sleep')
})

afterEach(function () {
sinon.restore()
})

after(async function () {
await closeAllEditors()
})

const createClient = () => {
const mockClient = stub(DefaultCodeWhispererClient)
mockClient.createCodeScan.resolves(mockCreateCodeScanResponse)
mockClient.createUploadUrl.resolves(mockCreateUploadUrlResponse)
mockClient.getCodeScan.resolves(mockGetCodeScanResponse)
mockClient.listCodeScanFindings.resolves(mockListCodeScanFindingsResponse)
return mockClient
}

const openTestFile = async (filePath: string) => {
const doc = await vscode.workspace.openTextDocument(filePath)
return await vscode.window.showTextDocument(doc, {
selection: new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 1)),
})
}

performanceTest({}, 'Should calculate cpu and memory usage for file scans', function () {
return {
setup: async () => {
getFetchStubWithResponse({ status: 200, statusText: 'testing stub' })
const commandSpy = sinon.spy(vscode.commands, 'executeCommand')
const securityScanRenderSpy = sinon.spy(diagnosticsProvider, 'initSecurityScanRender')
await model.CodeScansState.instance.setScansEnabled(true)
return { commandSpy, securityScanRenderSpy }
},
execute: async () => {
await startSecurityScan.startSecurityScan(
mockSecurityPanelViewProvider,
editor,
createClient(),
extensionContext,
CodeAnalysisScope.FILE
)
},
verify: ({
commandSpy,
securityScanRenderSpy,
}: {
commandSpy: sinon.SinonSpy
securityScanRenderSpy: sinon.SinonSpy
}) => {
assert.ok(commandSpy.neverCalledWith('workbench.action.problems.focus'))
assert.ok(securityScanRenderSpy.calledOnce)
const warnings = getTestWindow().shownMessages.filter((m) => m.severity === SeverityLevel.Warning)
assert.strictEqual(warnings.length, 0)
assertTelemetry('codewhisperer_securityScan', {
codewhispererCodeScanScope: 'FILE',
passive: true,
})
},
}
})
})
107 changes: 106 additions & 1 deletion packages/core/src/test/codewhisperer/testUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ import globals from '../../shared/extensionGlobals'
import { session } from '../../codewhisperer/util/codeWhispererSession'
import { DefaultAWSClientBuilder, ServiceOptions } from '../../shared/awsClientBuilder'
import { FakeAwsContext } from '../utilities/fakeAwsContext'
import { Service } from 'aws-sdk'
import { HttpResponse, Service } from 'aws-sdk'
import userApiConfig = require('./../../codewhisperer/client/user-service-2.json')
import CodeWhispererUserClient = require('../../codewhisperer/client/codewhispereruserclient')
import { codeWhispererClient } from '../../codewhisperer/client/codewhisperer'
import { RecommendationHandler } from '../../codewhisperer/service/recommendationHandler'
import * as model from '../../codewhisperer/models/model'
import { stub } from '../utilities/stubber'
import { Dirent } from 'fs' // eslint-disable-line no-restricted-imports

export async function resetCodeWhispererGlobalVariables() {
Expand Down Expand Up @@ -208,6 +210,109 @@ export function createMockDirentFile(fileName: string): Dirent {
return dirent
}

export const mockGetCodeScanResponse = {
$response: {
data: {
status: 'Completed',
},
requestId: 'requestId',
hasNextPage: () => false,
error: undefined,
nextPage: () => undefined,
redirectCount: 0,
retryCount: 0,
httpResponse: new HttpResponse(),
},
status: 'Completed',
}

export function createClient() {
const mockClient = stub(codewhispererClient.DefaultCodeWhispererClient)

const mockCreateCodeScanResponse = {
$response: {
data: {
jobId: 'jobId',
status: 'Pending',
},
requestId: 'requestId',
hasNextPage: () => false,
error: undefined,
nextPage: () => undefined,
redirectCount: 0,
retryCount: 0,
httpResponse: new HttpResponse(),
},
jobId: 'jobId',
status: 'Pending',
}
const mockCreateUploadUrlResponse = {
$response: {
data: {
uploadId: 'uploadId',
uploadUrl: 'uploadUrl',
},
requestId: 'requestId',
hasNextPage: () => false,
error: undefined,
nextPage: () => undefined,
redirectCount: 0,
retryCount: 0,
httpResponse: new HttpResponse(),
},
uploadId: 'uploadId',
uploadUrl: 'https://test.com',
}

const mockCodeScanFindings = JSON.stringify([
{
filePath: 'workspaceFolder/python3.7-plain-sam-app/hello_world/app.py',
startLine: 1,
endLine: 1,
title: 'title',
description: {
text: 'text',
markdown: 'markdown',
},
detectorId: 'detectorId',
detectorName: 'detectorName',
findingId: 'findingId',
relatedVulnerabilities: [],
severity: 'High',
remediation: {
recommendation: {
text: 'text',
url: 'url',
},
suggestedFixes: [],
},
codeSnippet: [],
} satisfies model.RawCodeScanIssue,
])

const mockListCodeScanFindingsResponse = {
$response: {
data: {
codeScanFindings: mockCodeScanFindings,
},
requestId: 'requestId',
hasNextPage: () => false,
error: undefined,
nextPage: () => undefined,
redirectCount: 0,
retryCount: 0,
httpResponse: new HttpResponse(),
},
codeScanFindings: mockCodeScanFindings,
}

mockClient.createCodeScan.resolves(mockCreateCodeScanResponse)
mockClient.createUploadUrl.resolves(mockCreateUploadUrlResponse)
mockClient.getCodeScan.resolves(mockGetCodeScanResponse)
mockClient.listCodeScanFindings.resolves(mockListCodeScanFindingsResponse)
return mockClient
}

export function aStringWithLineCount(lineCount: number, start: number = 0): string {
let s = ''
for (let i = start; i < start + lineCount; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { performanceTest } from '../shared/performance/performance'
import { performanceTest } from '../../shared/performance/performance'
import * as sinon from 'sinon'
import * as vscode from 'vscode'
import assert from 'assert'
import { LspClient, LspController } from '../amazonq'
import { LspClient, LspController } from '../../amazonq'
import { LanguageClient, ServerOptions } from 'vscode-languageclient'
import { createTestWorkspace } from '../test/testUtil'
import { GetUsageRequestType, IndexRequestType } from '../amazonq/lsp/types'
import { getRandomString } from '../shared'
import { createTestWorkspace } from '../../test/testUtil'
import { GetUsageRequestType, IndexRequestType } from '../../amazonq/lsp/types'
import { getRandomString } from '../../shared'

interface SetupResult {
clientReqStub: sinon.SinonStub
Expand Down
Loading
Loading