-
Notifications
You must be signed in to change notification settings - Fork 274
fix(amazonq): Error handling and telemetry for Unit test generation. #5192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
b733179
bc08f99
9ee9b13
c04de5e
b22eca6
10b39bb
7fc0959
ee4de19
95b7f1b
75a6254
3a87313
4461636
143c8c7
d893719
4698590
a0c6fc1
0bab6b6
1c89a6e
f200c7c
f86d1cb
d62ae9c
584547b
6bf2386
cf60095
6a566d3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,6 @@ | |
| import kotlinx.coroutines.Job | ||
| import kotlinx.coroutines.delay | ||
| import kotlinx.coroutines.launch | ||
| import software.amazon.awssdk.services.codewhispererruntime.model.CodeWhispererRuntimeException | ||
| import software.amazon.awssdk.services.codewhispererruntime.model.GetTestGenerationResponse | ||
| import software.amazon.awssdk.services.codewhispererruntime.model.Range | ||
| import software.amazon.awssdk.services.codewhispererruntime.model.StartTestGenerationResponse | ||
|
|
@@ -38,9 +37,14 @@ | |
| import software.aws.toolkits.jetbrains.services.amazonqCodeTest.session.Session | ||
| import software.aws.toolkits.jetbrains.services.amazonqCodeTest.utils.combineBuildAndExecuteLogFiles | ||
| import software.aws.toolkits.jetbrains.services.codemodernizer.utils.calculateTotalLatency | ||
| import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.CodeTestException | ||
| import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.codeTestServerException | ||
| import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.sessionconfig.CodeTestSessionConfig | ||
| import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.testGenStoppedError | ||
| import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor | ||
| import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants | ||
| import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererUtil.promptReAuth | ||
| import software.aws.toolkits.jetbrains.services.codewhisperer.util.getTelemetryErrorMessage | ||
| import software.aws.toolkits.jetbrains.services.cwc.controller.chat.telemetry.getStartUrl | ||
| import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType | ||
| import software.aws.toolkits.jetbrains.services.cwc.messages.CodeReference | ||
|
|
@@ -67,7 +71,7 @@ | |
|
|
||
| private fun throwIfCancelled(session: Session) { | ||
| if (!session.isGeneratingTests) { | ||
| error(message("testgen.message.cancelled")) | ||
| throw testGenStoppedError() | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -104,24 +108,37 @@ | |
| } | ||
|
|
||
| // 2nd API call: StartTestGeneration | ||
| val startTestGenerationResponse = startTestGeneration( | ||
| uploadId = createUploadUrlResponse.uploadId(), | ||
| targetCode = listOf( | ||
| TargetCode.builder() | ||
| .relativeTargetPath(codeTestResponseContext.currentFileRelativePath.toString()) | ||
| .targetLineRangeList( | ||
| if (selectionRange != null) { | ||
| listOf( | ||
| selectionRange | ||
| ) | ||
| } else { | ||
| emptyList() | ||
| } | ||
| ) | ||
| .build() | ||
| ), | ||
| userInput = prompt | ||
| ) | ||
| val startTestGenerationResponse = try { | ||
| startTestGeneration( | ||
| uploadId = createUploadUrlResponse.uploadId(), | ||
| targetCode = listOf( | ||
| TargetCode.builder() | ||
| .relativeTargetPath(codeTestResponseContext.currentFileRelativePath.toString()) | ||
| .targetLineRangeList( | ||
| if (selectionRange != null) { | ||
| listOf( | ||
| selectionRange | ||
| ) | ||
| } else { | ||
| emptyList() | ||
| } | ||
| ) | ||
| .build() | ||
| ), | ||
| userInput = prompt | ||
| ) | ||
| } catch (e: Exception) { | ||
| LOG.error(e) { "Failed to create test generation job" } | ||
| // TODO: Not able to emit e.statusCode directly as statusCode is private property | ||
| // Cannot access 'statusCode': it is invisible (private in a supertype) in 'ThrottlingException' | ||
| val errorMessage = getTelemetryErrorMessage(e, CodeWhispererConstants.FeatureName.TEST_GENERATION) | ||
| throw codeTestServerException( | ||
| "CreateTestJobError: $errorMessage", | ||
| "400", | ||
|
||
| "CreateTestJobError", | ||
| message("testgen.error.generic_technical_error_message") | ||
Check warningCode scanning / QDJVMC Usage of redundant or deprecated syntax or deprecated symbols Warning
'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead
|
||
| ) | ||
| } | ||
|
|
||
| val job = startTestGenerationResponse.testGenerationJob() | ||
| session.startTestGenerationRequestId = startTestGenerationResponse.responseMetadata().requestId() | ||
|
|
@@ -173,7 +190,13 @@ | |
| } | ||
| // update test summary card | ||
| } else { | ||
| throw Exception(message("testgen.message.failed")) | ||
| // If job status is Completed and has no ShortAnswer then there might be some issue in the backend. | ||
| throw codeTestServerException( | ||
|
||
| "TestGenFailedError: " + message("testgen.message.failed"), | ||
| "500", | ||
| "TestGenFailedError", | ||
| message("testgen.error.generic_technical_error_message") | ||
Check warningCode scanning / QDJVMC Usage of redundant or deprecated syntax or deprecated symbols Warning
'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead
|
||
| ) | ||
| } | ||
| } else if (status == TestGenerationJobStatus.FAILED) { | ||
| LOG.debug { | ||
|
|
@@ -184,11 +207,17 @@ | |
| shortAnswer = parseShortAnswerString(testGenerationResponse.testGenerationJob().shortAnswer()) | ||
| if (shortAnswer.stopIteration == "true") { | ||
| throw Exception("${shortAnswer.planSummary}") | ||
| throw codeTestServerException("TestGenFailedError: ${shortAnswer.planSummary}", "400", "TestGenFailedError", shortAnswer.planSummary) | ||
| } | ||
| } | ||
|
|
||
| // TODO: Modify text according to FnF | ||
| throw Exception(message("testgen.message.failed")) | ||
| // If job status is Failed and has no ShortAnswer then there might be some issue in the backend. | ||
| throw codeTestServerException( | ||
| "TestGenFailedError: " + message("testgen.message.failed"), | ||
|
||
| "500", | ||
| "TestGenFailedError", | ||
| message("testgen.error.generic_technical_error_message") | ||
|
||
| ) | ||
| } else { | ||
| // In progress | ||
| LOG.debug { | ||
|
|
@@ -200,7 +229,7 @@ | |
| if (previousIterationContext == null && testGenerationResponse.testGenerationJob().shortAnswer() != null) { | ||
| shortAnswer = parseShortAnswerString(testGenerationResponse.testGenerationJob().shortAnswer()) | ||
| if (shortAnswer.stopIteration == "true") { | ||
| throw Exception("${shortAnswer.planSummary}") | ||
| throw codeTestServerException("TestGenFailedError: ${shortAnswer.planSummary}", "400", "TestGenFailedError", shortAnswer.planSummary) | ||
| } | ||
| codeTestChatHelper.updateAnswer( | ||
| CodeTestChatMessageContent( | ||
|
|
@@ -232,6 +261,12 @@ | |
| }, | ||
| { e -> | ||
| LOG.error(e) { "ExportResultArchive failed: ${e.message}" } | ||
| throw codeTestServerException( | ||
| "ExportResultsArchiveError: ${e.message}", | ||
| "500", | ||
| "ExportResultsArchiveError", | ||
| message("testgen.error.generic_technical_error_message") | ||
|
||
| ) | ||
| }, | ||
| { startTime -> | ||
| LOG.info { "ExportResultArchive latency: ${calculateTotalLatency(startTime, Instant.now())}" } | ||
|
|
@@ -493,14 +528,19 @@ | |
| launchTestGenFlow(prompt, codeTestChatHelper, previousIterationContext, selectionRange) | ||
| } catch (e: Exception) { | ||
| // Add an answer for displaying error message | ||
| var errorMessage = e.message | ||
| if (e is JsonParseException) { | ||
| errorMessage = message("testgen.error.generic_error_message") | ||
| val errorMessage = when { | ||
| e is CodeTestException && e.statusCode == "400" && | ||
|
||
| e.message?.startsWith( | ||
| "CreateTestJobError: " + | ||
| "Maximum com.amazon.aws.codewhisperer.runtime.StartTestGeneration reached for this month." | ||
| ) == true -> | ||
| message("testgen.error.maximum_generations_reach") | ||
|
Check warning on line 537 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/CodeWhispererUTGChatManager.kt
|
||
|
||
|
|
||
| e is CodeTestException -> e.uiMessage | ||
|
||
| e is JsonParseException -> message("testgen.error.generic_technical_error_message") | ||
|
||
| else -> e.message | ||
| } | ||
|
|
||
| if (e is CodeWhispererRuntimeException) { | ||
| errorMessage = message("testgen.error.maximum_generations_reach") | ||
| } | ||
| codeTestChatHelper.addAnswer( | ||
| CodeTestChatMessageContent( | ||
| message = errorMessage, | ||
|
|
@@ -516,11 +556,12 @@ | |
| credentialStartUrl = getStartUrl(project), | ||
| jobGroup = session.testGenerationJobGroupName, | ||
| jobId = session.testGenerationJob, | ||
| result = if (e.message == message("testgen.message.cancelled")) MetricResult.Cancelled else MetricResult.Failed, | ||
|
Check warning on line 559 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/CodeWhispererUTGChatManager.kt
|
||
| reason = e.javaClass.name, | ||
| reasonDesc = e.message, | ||
| reason = (e as CodeTestException).code ?: "DefaultError", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why don't we just let it be null?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It can be but placing this under the bucket of DefaultError to be consistent in Kibana. |
||
| reasonDesc = if (e.message == message("testgen.message.cancelled")) "${e.code}: ${e.message}" else e.message, | ||
|
Check warning on line 561 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/CodeWhispererUTGChatManager.kt
|
||
|
||
| httpStatusCode = e.statusCode ?: "400", | ||
| perfClientLatency = (Instant.now().toEpochMilli() - session.startTimeOfTestGeneration), | ||
| isCodeBlockSelected = session.isCodeBlockSelected, | ||
| artifactsUploadDuration = session.artifactUploadDuration, | ||
| buildPayloadBytes = session.srcPayloadSize, | ||
| buildZipFileBytes = session.srcZipFileSize, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try
statusCode()There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I tried statusCode(), no luck.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.