-
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 15 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", | ||
| "500", | ||
| "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())}" } | ||
|
|
@@ -243,7 +278,7 @@ | |
| // TODO: Modify text according to FnF | ||
| codeTestChatHelper.addAnswer( | ||
| CodeTestChatMessageContent( | ||
| message = message("testgen.message.failed"), | ||
|
Check warning on line 281 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/CodeWhispererUTGChatManager.kt
|
||
| type = ChatMessageType.Answer, | ||
| canBeVoted = true | ||
| ) | ||
|
|
@@ -493,14 +528,16 @@ | |
| 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") == true -> | ||
|
||
| message("testgen.error.maximum_generations_reach") | ||
|
||
|
|
||
| e is CodeTestException -> e.uiMessage | ||
|
||
| e is JsonParseException -> message("testgen.error.generic_technical_error_message") | ||
|
Check warning on line 537 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/CodeWhispererUTGChatManager.kt
|
||
|
||
| else -> message("testgen.error.generic_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
|
||
| } | ||
|
|
||
| if (e is CodeWhispererRuntimeException) { | ||
| errorMessage = message("testgen.error.maximum_generations_reach") | ||
| } | ||
| codeTestChatHelper.addAnswer( | ||
| CodeTestChatMessageContent( | ||
| message = errorMessage, | ||
|
|
@@ -517,8 +554,9 @@ | |
| jobGroup = session.testGenerationJobGroupName, | ||
| jobId = session.testGenerationJob, | ||
| result = if (e.message == message("testgen.message.cancelled")) MetricResult.Cancelled else MetricResult.Failed, | ||
| 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, | ||
|
||
| httpStatusCode = e.statusCode ?: "400", | ||
| perfClientLatency = (Instant.now().toEpochMilli() - session.startTimeOfTestGeneration), | ||
| isCodeBlockSelected = session.isCodeBlockSelected, | ||
| artifactsUploadDuration = session.artifactUploadDuration, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| // Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| package software.aws.toolkits.jetbrains.services.codewhisperer.codetest | ||
|
|
||
| import software.aws.toolkits.resources.message | ||
|
Check warning on line 6 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codetest/CodeTestException.kt
|
||
Check warningCode scanning / QDJVMC Usage of redundant or deprecated syntax or deprecated symbols Warning
Remove deprecated symbol import
|
||
|
|
||
| open class CodeTestException( | ||
| override val message: String?, | ||
| val statusCode: String? = "400", | ||
| val code: String? = "DefaultError", | ||
| val uiMessage: String? = message( | ||
|
||
| "testgen.error.generic_error_message" | ||
| ), | ||
| ) : RuntimeException() | ||
|
|
||
| internal fun noFileOpenError(): Nothing = | ||
| throw CodeTestException(message("codewhisperer.codescan.no_file_open"), "400", "ProjectZipError") | ||
|
Check warning on line 18 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codetest/CodeTestException.kt
|
||
|
||
|
|
||
| internal fun fileTooLarge(): Nothing = | ||
| throw CodeTestException(message("codewhisperer.codescan.file_too_large_telemetry"), "400", "ProjectZipError") | ||
|
Check warning on line 21 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codetest/CodeTestException.kt
|
||
|
||
|
|
||
| internal fun cannotFindFile(errorMessage: String, filepath: String): Nothing = | ||
| error(message("codewhisperer.codescan.file_not_found", filepath, errorMessage)) | ||
|
Check warning on line 24 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codetest/CodeTestException.kt
|
||
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
|
||
|
|
||
| internal fun cannotFindValidFile(errorMessage: String): Nothing = | ||
| throw CodeTestException(errorMessage, "400", "ProjectZipError") | ||
|
|
||
| internal fun cannotFindBuildArtifacts(errorMessage: String): Nothing = | ||
| throw CodeTestException(errorMessage, "400", "ProjectZipError") | ||
|
|
||
| internal fun invalidSourceZipError(): Nothing = | ||
| throw CodeTestException(message("codewhisperer.codescan.invalid_source_zip_telemetry"), "400", "InvalidSourceZipError") | ||
|
Check warning on line 33 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codetest/CodeTestException.kt
|
||
|
||
|
|
||
| fun codeTestServerException( | ||
| errorMessage: String, | ||
| statusCode: String?, | ||
|
||
| code: String? = "DefaultError", | ||
| uiMessage: String? = message( | ||
|
||
| "testgen.error.generic_technical_error_message" | ||
| ), | ||
| ): Nothing = | ||
| throw CodeTestException(errorMessage, statusCode, code, uiMessage) | ||
|
|
||
| fun testGenStoppedError(): Nothing = | ||
| throw CodeTestException(message("testgen.message.cancelled"), "400", "TestGenCancelled", message("testgen.message.cancelled")) | ||
|
||
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.