in packages/core/src/amazonqTest/chat/controller/controller.ts [458:612]
private async startTestGen(message: any, regenerateTests: boolean) {
const session: Session = this.sessionStorage.getSession()
// Perform session cleanup before start of unit test generation workflow unless there is an existing job in progress.
if (!ChatSessionManager.Instance.getIsInProgress()) {
await this.sessionCleanUp()
}
const tabID = this.sessionStorage.setActiveTab(message.tabID)
getLogger().debug('startTestGen message: %O', message)
getLogger().debug('startTestGen tabId: %O', message.tabID)
let fileName = ''
let filePath = ''
let userFacingMessage = ''
let userPrompt = ''
session.testGenerationStartTime = performance.now()
try {
if (ChatSessionManager.Instance.getIsInProgress()) {
void vscode.window.showInformationMessage(
"There is already a test generation job in progress. Cancel current job or wait until it's finished to try again."
)
return
}
if (testGenState.isCancelling()) {
void vscode.window.showInformationMessage(
'There is a test generation job being cancelled. Please wait for cancellation to finish.'
)
return
}
// Truncating the user prompt if the prompt is more than 4096.
userPrompt = message.prompt.slice(0, maxUserPromptLength)
// check that the session is authenticated
const authState = await AuthUtil.instance.getChatAuthState()
if (authState.amazonQ !== 'connected') {
void this.messenger.sendAuthNeededExceptionMessage(authState, tabID)
session.isAuthenticating = true
return
}
// check that a project/workspace is open
const workspaceFolders = vscode.workspace.workspaceFolders
if (workspaceFolders === undefined || workspaceFolders.length === 0) {
this.messenger.sendUnrecoverableErrorResponse('no-project-found', tabID)
return
}
// check if IDE has active file open.
const activeEditor = vscode.window.activeTextEditor
// also check all open editors and allow this to proceed if only one is open (even if not main focus)
const allVisibleEditors = vscode.window.visibleTextEditors
const openFileEditors = allVisibleEditors.filter((editor) => editor.document.uri.scheme === 'file')
const hasOnlyOneOpenFileSplitView = openFileEditors.length === 1
getLogger().debug(`hasOnlyOneOpenSplitView: ${hasOnlyOneOpenFileSplitView}`)
// is not a file if the currently highlighted window is not a file, and there is either more than one or no file windows open
const isNotFile = activeEditor?.document.uri.scheme !== 'file' && !hasOnlyOneOpenFileSplitView
getLogger().debug(`activeEditor: ${activeEditor}, isNotFile: ${isNotFile}`)
if (!activeEditor || isNotFile) {
this.messenger.sendUnrecoverableErrorResponse(
isNotFile ? 'invalid-file-type' : 'no-open-file-found',
tabID
)
this.messenger.sendUpdatePlaceholder(
tabID,
'Please open and highlight a source code file in order to generate tests.'
)
this.messenger.sendChatInputEnabled(tabID, true)
this.sessionStorage.getSession().conversationState = ConversationState.WAITING_FOR_INPUT
return
}
const fileEditorToTest = hasOnlyOneOpenFileSplitView ? openFileEditors[0] : activeEditor
getLogger().debug(`File path: ${fileEditorToTest.document.uri.fsPath}`)
filePath = fileEditorToTest.document.uri.fsPath
fileName = path.basename(filePath)
userFacingMessage = userPrompt
? regenerateTests
? `${userPrompt}`
: `/test ${userPrompt}`
: `/test Generate unit tests for \`${fileName}\``
session.hasUserPromptSupplied = userPrompt.length > 0
// displaying user message prompt in Test tab
this.messenger.sendMessage(userFacingMessage, tabID, 'prompt')
this.messenger.sendChatInputEnabled(tabID, false)
this.sessionStorage.getSession().conversationState = ConversationState.IN_PROGRESS
this.messenger.sendUpdatePromptProgress(message.tabID, testGenProgressField)
const language = await this.getLanguageForFilePath(filePath)
session.fileLanguage = language
const workspaceFolder = vscode.workspace.getWorkspaceFolder(fileEditorToTest.document.uri)
/*
For Re:Invent 2024 we are supporting only java and python for unit test generation, rest of the languages shows the similar experience as CWC
*/
if (!['java', 'python'].includes(language) || workspaceFolder === undefined) {
if (!workspaceFolder) {
// File is outside of workspace
const unsupportedMessage = `<span style="color: #EE9D28;">⚠<b>I can't generate tests for ${fileName}</b> because the file is outside of workspace scope.<br></span> I can still provide examples, instructions and code suggestions.`
this.messenger.sendMessage(unsupportedMessage, tabID, 'answer')
}
// Keeping this metric as is. TODO - Change to true once we support through other feature
session.isSupportedLanguage = false
await this.onCodeGeneration(
session,
userPrompt,
tabID,
fileName,
filePath,
workspaceFolder !== undefined
)
} else {
this.messenger.sendCapabilityCard({ tabID })
this.messenger.sendMessage(testGenSummaryMessage(fileName), message.tabID, 'answer-part')
// Grab the selection from the fileEditorToTest and get the vscode Range
const selection = fileEditorToTest.selection
let selectionRange = undefined
if (
selection.start.line !== selection.end.line ||
selection.start.character !== selection.end.character
) {
selectionRange = new vscode.Range(
selection.start.line,
selection.start.character,
selection.end.line,
selection.end.character
)
}
session.isCodeBlockSelected = selectionRange !== undefined
session.isSupportedLanguage = true
/**
* Zip the project
* Create pre-signed URL and upload artifact to S3
* send API request to startTestGeneration API
* Poll from getTestGeneration API
* Get Diff from exportResultArchive API
*/
ChatSessionManager.Instance.setIsInProgress(true)
await startTestGenerationProcess(filePath, message.prompt, tabID, true, selectionRange)
}
} catch (err: any) {
// TODO: refactor error handling to be more robust
ChatSessionManager.Instance.setIsInProgress(false)
getLogger().error('startTestGen failed: %O', err)
this.messenger.sendUpdatePromptProgress(message.tabID, cancellingProgressField)
this.sendErrorMessage({ tabID, error: err })
this.messenger.sendChatInputEnabled(tabID, true)
this.sessionStorage.getSession().conversationState = ConversationState.WAITING_FOR_INPUT
await sleep(2000)
// eslint-disable-next-line unicorn/no-null
this.messenger.sendUpdatePromptProgress(message.tabID, null)
}
}