Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion packages/core/src/amazonqTest/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function init(appContext: AmazonQAppInitContext) {
authClicked: new vscode.EventEmitter<any>(),
startTestGen: new vscode.EventEmitter<any>(),
processHumanChatMessage: new vscode.EventEmitter<any>(),
updateShortAnswer: new vscode.EventEmitter<any>(),
updateTargetFileInfo: new vscode.EventEmitter<any>(),
showCodeGenerationResults: new vscode.EventEmitter<any>(),
openDiff: new vscode.EventEmitter<any>(),
formActionClicked: new vscode.EventEmitter<any>(),
Expand Down
22 changes: 11 additions & 11 deletions packages/core/src/amazonqTest/chat/controller/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import { randomUUID } from '../../../shared/crypto'
import { tempDirPath, testGenerationLogsDir } from '../../../shared/filesystemUtilities'
import { CodeReference } from '../../../codewhispererChat/view/connector/connector'
import { TelemetryHelper } from '../../../codewhisperer/util/telemetryHelper'
import { ShortAnswer, ShortAnswerReference, testGenState } from '../../../codewhisperer/models/model'
import { Reference, testGenState } from '../../../codewhisperer/models/model'
import {
referenceLogText,
TestGenerationBuildStep,
Expand All @@ -63,14 +63,15 @@ import {
} from '../../../codewhisperer/models/constants'
import { UserWrittenCodeTracker } from '../../../codewhisperer/tracker/userWrittenCodeTracker'
import { ReferenceLogViewProvider } from '../../../codewhisperer/service/referenceLogViewProvider'
import { TargetFileInfo } from '../../../codewhisperer/client/codewhispereruserclient'

export interface TestChatControllerEventEmitters {
readonly tabOpened: vscode.EventEmitter<any>
readonly tabClosed: vscode.EventEmitter<any>
readonly authClicked: vscode.EventEmitter<any>
readonly startTestGen: vscode.EventEmitter<any>
readonly processHumanChatMessage: vscode.EventEmitter<any>
readonly updateShortAnswer: vscode.EventEmitter<any>
readonly updateTargetFileInfo: vscode.EventEmitter<any>
readonly showCodeGenerationResults: vscode.EventEmitter<any>
readonly openDiff: vscode.EventEmitter<any>
readonly formActionClicked: vscode.EventEmitter<any>
Expand Down Expand Up @@ -131,8 +132,8 @@ export class TestController {
return this.handleFormActionClicked(data)
})

this.chatControllerMessageListeners.updateShortAnswer.event((data) => {
return this.updateShortAnswer(data)
this.chatControllerMessageListeners.updateTargetFileInfo.event((data) => {
return this.updateTargetFileInfo(data)
})

this.chatControllerMessageListeners.showCodeGenerationResults.event((data) => {
Expand Down Expand Up @@ -586,10 +587,9 @@ export class TestController {
}
}

private async updateShortAnswer(message: {
private async updateTargetFileInfo(message: {
tabID: string
status: string
shortAnswer?: ShortAnswer
targetFileInfo?: TargetFileInfo
testGenerationJobGroupName: string
testGenerationJobId: string
type: ChatItemType
Expand All @@ -599,11 +599,11 @@ export class TestController {
type: 'answer',
tabID: message.tabID,
message: testGenSummaryMessage(
path.basename(message.shortAnswer?.sourceFilePath ?? message.filePath),
message.shortAnswer?.planSummary?.replaceAll('```', '')
path.basename(message.targetFileInfo?.filePath ?? message.filePath),
message.targetFileInfo?.filePlan?.replaceAll('```', '')
),
canBeVoted: true,
filePath: message.shortAnswer?.testFilePath,
filePath: message.targetFileInfo?.testFilePath,
})
}

Expand Down Expand Up @@ -663,7 +663,7 @@ export class TestController {
filePaths: [data.filePath],
},
codeReference: session.references.map(
(ref: ShortAnswerReference) =>
(ref: Reference) =>
({
...ref,
information: `${ref.licenseName} - <a href="${ref.url}">${ref.repository}</a>`,
Expand Down
7 changes: 4 additions & 3 deletions packages/core/src/amazonqTest/chat/session/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { ShortAnswer, ShortAnswerReference } from '../../../codewhisperer/models/model'
import { TestGenerationJob } from '../../../codewhisperer/client/codewhispereruserclient'
import { ShortAnswer, Reference } from '../../../codewhisperer/models/model'
import { TargetFileInfo, TestGenerationJob } from '../../../codewhisperer/client/codewhispereruserclient'

export enum ConversationState {
IDLE,
Expand Down Expand Up @@ -42,6 +42,7 @@ export class Session {
public projectRootPath: string = ''
public fileLanguage: string | undefined = 'plaintext'
public stopIteration: boolean = false
public targetFileInfo: TargetFileInfo | undefined

// Telemetry
public testGenerationStartTime: number = 0
Expand All @@ -64,7 +65,7 @@ export class Session {
public testCoveragePercentage: number = 90
public isInProgress: boolean = false
public acceptedJobId = ''
public references: ShortAnswerReference[] = []
public references: Reference[] = []

constructor() {}

Expand Down
90 changes: 89 additions & 1 deletion packages/core/src/codewhisperer/client/user-service-2.json
Original file line number Diff line number Diff line change
Expand Up @@ -1760,6 +1760,39 @@
"type": "string",
"enum": ["OPTIN", "OPTOUT"]
},
"PackageInfo": {
"type": "structure",
"members": {
"executionCommand": { "shape": "SensitiveString" },
"buildCommand": { "shape": "SensitiveString" },
"buildOrder": { "shape": "PackageInfoBuildOrderInteger" },
"testFramework": { "shape": "String" },
"packageSummary": { "shape": "PackageInfoPackageSummaryString" },
"packagePlan": { "shape": "PackageInfoPackagePlanString" },
"targetFileInfoList": { "shape": "TargetFileInfoList" }
}
},
"PackageInfoBuildOrderInteger": {
"type": "integer",
"box": true,
"min": 0
},
"PackageInfoList": {
"type": "list",
"member": { "shape": "PackageInfo" }
},
"PackageInfoPackagePlanString": {
"type": "string",
"max": 30720,
"min": 0,
"sensitive": true
},
"PackageInfoPackageSummaryString": {
"type": "string",
"max": 30720,
"min": 0,
"sensitive": true
},
"PaginationToken": {
"type": "string",
"max": 2048,
Expand Down Expand Up @@ -2418,6 +2451,45 @@
"min": 1,
"sensitive": true
},
"TargetFileInfo": {
"type": "structure",
"members": {
"filePath": { "shape": "SensitiveString" },
"testFilePath": { "shape": "SensitiveString" },
"testCoverage": { "shape": "TargetFileInfoTestCoverageInteger" },
"fileSummary": { "shape": "TargetFileInfoFileSummaryString" },
"filePlan": { "shape": "TargetFileInfoFilePlanString" },
"codeReferences": { "shape": "References" },
"numberOfTestMethods": { "shape": "TargetFileInfoNumberOfTestMethodsInteger" }
}
},
"TargetFileInfoFilePlanString": {
"type": "string",
"max": 30720,
"min": 0,
"sensitive": true
},
"TargetFileInfoFileSummaryString": {
"type": "string",
"max": 30720,
"min": 0,
"sensitive": true
},
"TargetFileInfoList": {
"type": "list",
"member": { "shape": "TargetFileInfo" }
},
"TargetFileInfoNumberOfTestMethodsInteger": {
"type": "integer",
"box": true,
"min": 0
},
"TargetFileInfoTestCoverageInteger": {
"type": "integer",
"box": true,
"max": 100,
"min": 0
},
"TaskAssistPlan": {
"type": "list",
"member": { "shape": "TaskAssistPlanStep" },
Expand Down Expand Up @@ -2556,7 +2628,11 @@
"status": { "shape": "TestGenerationJobStatus" },
"shortAnswer": { "shape": "SensitiveString" },
"creationTime": { "shape": "Timestamp" },
"progressRate": { "shape": "TestGenerationJobProgressRateInteger" }
"progressRate": { "shape": "TestGenerationJobProgressRateInteger" },
"jobStatusReason": { "shape": "String" },
"jobSummary": { "shape": "TestGenerationJobJobSummaryString" },
"jobPlan": { "shape": "TestGenerationJobJobPlanString" },
"packageInfoList": { "shape": "PackageInfoList" }
},
"documentation": "<p>Represents a test generation job</p>"
},
Expand All @@ -2567,6 +2643,18 @@
"min": 1,
"pattern": "[a-zA-Z0-9-_]+"
},
"TestGenerationJobJobPlanString": {
"type": "string",
"max": 30720,
"min": 0,
"sensitive": true
},
"TestGenerationJobJobSummaryString": {
"type": "string",
"max": 30720,
"min": 0,
"sensitive": true
},
"TestGenerationJobProgressRateInteger": {
"type": "integer",
"box": true,
Expand Down
5 changes: 3 additions & 2 deletions packages/core/src/codewhisperer/models/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1165,7 +1165,7 @@ export interface FolderInfo {
name: string
}

export interface ShortAnswerReference {
export interface Reference {
licenseName?: string
repository?: string
url?: string
Expand All @@ -1175,6 +1175,7 @@ export interface ShortAnswerReference {
}
}

// TODO: remove ShortAnswer because it will be deprecated
export interface ShortAnswer {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this ShortAnswer being used any where in the project apart from build and execute in public master branch?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not being used anywhere else. I will eventually delete this after I do the shortAnswer refactoring for build exec

testFilePath: string
buildCommands: string[]
Expand All @@ -1185,6 +1186,6 @@ export interface ShortAnswer {
testCoverage?: number
stopIteration?: string
errorMessage?: string
codeReferences?: ShortAnswerReference[]
codeReferences?: References
numberOfTestMethods?: number
}
44 changes: 20 additions & 24 deletions packages/core/src/codewhisperer/service/testGenHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@ import {
CreateUploadUrlError,
ExportResultsArchiveError,
InvalidSourceZipError,
TestGenFailedError,
TestGenStoppedError,
TestGenTimedOutError,
} from '../../amazonqTest/error'
import { getMd5, uploadArtifactToS3 } from './securityScanHandler'
import { ShortAnswer, testGenState } from '../models/model'
import { testGenState, Reference } from '../models/model'
import { ChatSessionManager } from '../../amazonqTest/chat/storages/chatSession'
import { createCodeWhispererChatStreamingClient } from '../../shared/clients/codewhispererChatClient'
import { downloadExportResultArchive } from '../../shared/utilities/download'
Expand Down Expand Up @@ -156,44 +155,41 @@ export async function pollTestJobStatus(
status: 'InProgress',
progressRate,
})
const shortAnswerString = resp.testGenerationJob?.shortAnswer
if (shortAnswerString) {
const parsedShortAnswer = JSON.parse(shortAnswerString)
const shortAnswer: ShortAnswer = JSON.parse(parsedShortAnswer)
// Stop the Unit test generation workflow if IDE receive stopIteration = true
if (shortAnswer.stopIteration === 'true') {
session.stopIteration = true
throw new TestGenFailedError(shortAnswer.planSummary)
}
if (shortAnswer.numberOfTestMethods) {
session.numberOfTestsGenerated = Number(shortAnswer.numberOfTestMethods)
const packageInfoList = resp.testGenerationJob?.packageInfoList ?? []
const packageInfo = packageInfoList[0]
const targetFileInfo = packageInfo?.targetFileInfoList?.[0]

if (packageInfo) {
// TODO: will need some fields from packageInfo such as buildCommand, packagePlan, packageSummary
}
if (targetFileInfo) {
if (targetFileInfo.numberOfTestMethods) {
session.numberOfTestsGenerated = Number(targetFileInfo.numberOfTestMethods)
}
if (shortAnswer.codeReferences) {
session.references = shortAnswer.codeReferences
if (targetFileInfo.codeReferences) {
session.references = targetFileInfo.codeReferences as Reference[]
}
if (initialExecution) {
session.generatedFilePath = shortAnswer?.testFilePath ?? ''
const currentPlanSummary = session.shortAnswer?.planSummary
const newPlanSummary = shortAnswer?.planSummary
const status = shortAnswer.stopIteration
session.generatedFilePath = targetFileInfo.testFilePath ?? ''
const currentPlanSummary = session.targetFileInfo?.filePlan
const newPlanSummary = targetFileInfo?.filePlan

if (currentPlanSummary !== newPlanSummary && newPlanSummary) {
const chatControllers = testGenState.getChatControllers()
if (chatControllers) {
const currentSession = ChatSessionManager.Instance.getSession()
chatControllers.updateShortAnswer.fire({
chatControllers.updateTargetFileInfo.fire({
tabID: currentSession.tabID,
status,
shortAnswer,
targetFileInfo,
testGenerationJobGroupName: resp.testGenerationJob?.testGenerationJobGroupName,
testGenerationJobId: resp.testGenerationJob?.testGenerationJobId,
filePath,
})
}
}
}
ChatSessionManager.Instance.getSession().shortAnswer = shortAnswer
}
ChatSessionManager.Instance.getSession().targetFileInfo = targetFileInfo
if (resp.testGenerationJob?.status !== CodeWhispererConstants.TestGenerationJobStatus.IN_PROGRESS) {
// This can be FAILED or COMPLETED
status = resp.testGenerationJob?.status as CodeWhispererConstants.TestGenerationJobStatus
Expand Down Expand Up @@ -243,7 +239,7 @@ export async function exportResultsArchive(
const zip = new AdmZip(pathToArchive)
zip.extractAllTo(pathToArchiveDir, true)

const testFilePathFromResponse = session?.shortAnswer?.testFilePath
const testFilePathFromResponse = session?.targetFileInfo?.testFilePath
const testFilePath = testFilePathFromResponse
? testFilePathFromResponse.split('/').slice(1).join('/') // remove the project name
: await getTestFilePathFromZip(pathToArchiveDir)
Expand Down