Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b733179
Error handling for UTG
laileni-aws Dec 11, 2024
bc08f99
Error handling for UTG
laileni-aws Dec 11, 2024
9ee9b13
Merge branch 'aws:main' into main
laileni-aws Dec 11, 2024
c04de5e
Minor edits addresing comments
laileni-aws Dec 12, 2024
b22eca6
Lint errors
laileni-aws Dec 12, 2024
10b39bb
Merge branch 'main' into main
laileni-aws Dec 12, 2024
7fc0959
Merge branch 'main' into main
laileni-aws Dec 13, 2024
ee4de19
Merge branch 'main' into main
laileni-aws Dec 13, 2024
95b7f1b
Merge branch 'main' into main
laileni-aws Dec 13, 2024
75a6254
Fixing build failures
laileni-aws Dec 13, 2024
3a87313
Fixing build failures
laileni-aws Dec 13, 2024
4461636
Merge branch 'main' into main
laileni-aws Dec 13, 2024
143c8c7
Removing CodeTestServerException from CodeTestException file
laileni-aws Dec 13, 2024
d893719
Adding Generic error message for CX facing UX
laileni-aws Dec 13, 2024
4698590
Changing status code from 4XX to 5XX for CreateTestJobError
laileni-aws Dec 13, 2024
a0c6fc1
Moving statusCode datatype from string to int
laileni-aws Dec 13, 2024
0bab6b6
Adding perfClientLatency to telemetry event (#4)
laileni-aws Dec 14, 2024
1c89a6e
Addressing comments
laileni-aws Dec 14, 2024
f200c7c
Addressing Comments
laileni-aws Dec 14, 2024
f86d1cb
Merge branch 'main' into main
laileni-aws Dec 14, 2024
d62ae9c
Removing the statusCode from UTG telemetry
laileni-aws Dec 14, 2024
584547b
Minor edits
laileni-aws Dec 14, 2024
6bf2386
Merge branch 'main' into main
ashishrp-aws Jan 13, 2025
cf60095
Merge branch 'main' into main
ashishrp-aws Jan 14, 2025
6a566d3
Merge branch 'main' into main
ashishrp-aws Jan 14, 2025
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 @@ -34,9 +34,6 @@ class CodeWhispererCodeTestSession(val sessionContext: CodeTestSessionContext) {
* Run UTG sessions are follow steps:
* 1. Zipping project
* 2. Creating Upload url & Upload to S3 bucket
* 3. StartTestGeneration API -> Get JobId
* 4. GetTestGeneration API
* 5. ExportResultsArchieve API
*/
suspend fun run(codeTestChatHelper: CodeTestChatHelper, previousIterationContext: PreviousUTGIterationContext?): CodeTestResponseContext {
try {
Expand Down Expand Up @@ -94,7 +91,8 @@ class CodeWhispererCodeTestSession(val sessionContext: CodeTestSessionContext) {
sourceZip,
"SourceCode",
CodeWhispererConstants.UploadTaskType.UTG,
taskName
taskName,
CodeWhispererConstants.FeatureName.TEST_GENERATION
)

sourceZipUploadResponse.uploadId()
Expand All @@ -113,11 +111,10 @@ class CodeWhispererCodeTestSession(val sessionContext: CodeTestSessionContext) {
sourceZipUploadResponse,
testSummaryMessageId
)
// TODO send telemetry for upload duration

return codeTestResponseContext
} catch (e: Exception) {
LOG.debug(e) { "Error when creating tests for the current file" }
LOG.debug(e) { "Error while creating zip and uploading to S3" }
throw e
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import software.amazon.awssdk.services.codewhispererruntime.model.CodeWhispererRuntimeException
import software.amazon.awssdk.core.exception.SdkServiceException
import software.amazon.awssdk.services.codewhispererruntime.model.GetTestGenerationResponse
import software.amazon.awssdk.services.codewhispererruntime.model.Range
import software.amazon.awssdk.services.codewhispererruntime.model.StartTestGenerationResponse
Expand All @@ -38,9 +38,13 @@
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.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
Expand All @@ -67,7 +71,7 @@

private fun throwIfCancelled(session: Session) {
if (!session.isGeneratingTests) {
error(message("testgen.message.cancelled"))
testGenStoppedError()
}
}

Expand Down Expand Up @@ -104,24 +108,38 @@
}

// 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) {
val statusCode = when {
e is SdkServiceException -> e.statusCode()
else -> 400
}
LOG.error(e) { "Unexpected error while creating test generation job" }
val errorMessage = getTelemetryErrorMessage(e, CodeWhispererConstants.FeatureName.TEST_GENERATION)
throw CodeTestException(
"CreateTestJobError: $errorMessage",
"CreateTestJobError",
message("testgen.error.generic_technical_error_message")

Check warning

Code 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()
Expand Down Expand Up @@ -173,7 +191,12 @@
}
// 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 CodeTestException(
"TestGenFailedError: " + message("testgen.message.failed"),
"TestGenFailedError",
message("testgen.error.generic_technical_error_message")

Check warning

Code 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 {
Expand All @@ -183,12 +206,16 @@
if (testGenerationResponse.testGenerationJob().shortAnswer() != null) {
shortAnswer = parseShortAnswerString(testGenerationResponse.testGenerationJob().shortAnswer())
if (shortAnswer.stopIteration == "true") {
throw Exception("${shortAnswer.planSummary}")
throw CodeTestException("TestGenFailedError: ${shortAnswer.planSummary}", "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 CodeTestException(
"TestGenFailedError: " + message("testgen.message.failed"),
"TestGenFailedError",
message("testgen.error.generic_technical_error_message")
)
} else {
// In progress
LOG.debug {
Expand All @@ -200,7 +227,7 @@
if (previousIterationContext == null && testGenerationResponse.testGenerationJob().shortAnswer() != null) {
shortAnswer = parseShortAnswerString(testGenerationResponse.testGenerationJob().shortAnswer())
if (shortAnswer.stopIteration == "true") {
throw Exception("${shortAnswer.planSummary}")
throw CodeTestException("TestGenFailedError: ${shortAnswer.planSummary}", "TestGenFailedError", shortAnswer.planSummary)
}
codeTestChatHelper.updateAnswer(
CodeTestChatMessageContent(
Expand Down Expand Up @@ -232,6 +259,11 @@
},
{ e ->
LOG.error(e) { "ExportResultArchive failed: ${e.message}" }
throw CodeTestException(
"ExportResultsArchiveError: ${e.message}",
"ExportResultsArchiveError",
message("testgen.error.generic_technical_error_message")
)
},
{ startTime ->
LOG.info { "ExportResultArchive latency: ${calculateTotalLatency(startTime, Instant.now())}" }
Expand Down Expand Up @@ -493,16 +525,18 @@
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.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")
else -> message("testgen.error.generic_error_message")

Check warning

Code 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,
type = ChatMessageType.Answer,
canBeVoted = false
Expand All @@ -518,8 +552,8 @@
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",
Copy link
Contributor

Choose a reason for hiding this comment

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

why don't we just let it be null?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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,
perfClientLatency = (Instant.now().toEpochMilli() - session.startTimeOfTestGeneration),
isCodeBlockSelected = session.isCodeBlockSelected,
artifactsUploadDuration = session.artifactUploadDuration,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,6 @@ class CodeTestChatController(
var charDifference = 0
var generatedFileContent = ""
var selectedFileContent = ""
var latencyOfTestGeneration = 0.0

when (message.actionID) {
"utg_view_diff" -> {
Expand Down Expand Up @@ -496,7 +495,7 @@ class CodeTestChatController(

session.linesOfCodeGenerated = lineDifference.coerceAtLeast(0)
session.charsOfCodeGenerated = charDifference.coerceAtLeast(0)
latencyOfTestGeneration = (Instant.now().toEpochMilli() - session.startTimeOfTestGeneration)
session.latencyOfTestGeneration = (Instant.now().toEpochMilli() - session.startTimeOfTestGeneration)
UiTelemetry.click(null as Project?, "unitTestGeneration_viewDiff")

val buttonList = mutableListOf<Button>()
Expand Down Expand Up @@ -611,7 +610,7 @@ class CodeTestChatController(
acceptedCharactersCount = session.charsOfCodeGenerated?.toLong(),
generatedCharactersCount = session.charsOfCodeGenerated?.toLong(),
result = MetricResult.Succeeded,
perfClientLatency = latencyOfTestGeneration,
perfClientLatency = session.latencyOfTestGeneration,
isCodeBlockSelected = session.isCodeBlockSelected,
artifactsUploadDuration = session.artifactUploadDuration,
buildPayloadBytes = session.srcPayloadSize,
Expand Down Expand Up @@ -807,7 +806,7 @@ class CodeTestChatController(
acceptedCharactersCount = 0,
generatedCharactersCount = session.charsOfCodeGenerated?.toLong(),
result = MetricResult.Succeeded,
perfClientLatency = latencyOfTestGeneration,
perfClientLatency = session.latencyOfTestGeneration,
isCodeBlockSelected = session.isCodeBlockSelected,
artifactsUploadDuration = session.artifactUploadDuration,
buildPayloadBytes = session.srcPayloadSize,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ data class Session(val tabId: String) {
var linesOfCodeGenerated: Int? = null
var charsOfCodeGenerated: Int? = null
var startTimeOfTestGeneration: Double = 0.0
var latencyOfTestGeneration: Double = 0.0
var isCodeBlockSelected: Boolean = false
var srcPayloadSize: Long = 0
var srcZipFileSize: Long = 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ class AmazonQCodeFixSession(val project: Project) {
sourceZip,
"SourceCode",
CodeWhispererConstants.UploadTaskType.CODE_FIX,
codeFixName
codeFixName,
CodeWhispererConstants.FeatureName.CODE_REVIEW
)

/**
Expand Down Expand Up @@ -149,7 +150,7 @@ class AmazonQCodeFixSession(val project: Project) {
)
} catch (e: Exception) {
LOG.debug { "Create Upload URL failed: ${e.message}" }
val errorMessage = getTelemetryErrorMessage(e)
val errorMessage = getTelemetryErrorMessage(e, featureUseCase = CodeWhispererConstants.FeatureName.CODE_REVIEW)
throw codeScanServerException("CreateUploadUrlException: $errorMessage")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
sourceZip,
"SourceCode",
taskType,
codeScanName
codeScanName,
CodeWhispererConstants.FeatureName.CODE_REVIEW
)
if (isProjectScope()) {
LOG.debug {
Expand Down Expand Up @@ -272,7 +273,7 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
)
} catch (e: Exception) {
LOG.debug { "Creating code review failed: ${e.message}" }
val errorMessage = getTelemetryErrorMessage(e)
val errorMessage = getTelemetryErrorMessage(e, featureUseCase = CodeWhispererConstants.FeatureName.CODE_REVIEW)
throw codeScanServerException(errorMessage)
}
}
Expand All @@ -285,7 +286,7 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
)
} catch (e: Exception) {
LOG.debug { "Getting code review failed: ${e.message}" }
val errorMessage = getTelemetryErrorMessage(e)
val errorMessage = getTelemetryErrorMessage(e, featureUseCase = CodeWhispererConstants.FeatureName.CODE_REVIEW)
throw codeScanServerException("GetCodeReviewException: $errorMessage")
}

Expand All @@ -299,7 +300,7 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
)
} catch (e: Exception) {
LOG.debug { "Listing code review failed: ${e.message}" }
val errorMessage = getTelemetryErrorMessage(e)
val errorMessage = getTelemetryErrorMessage(e, featureUseCase = CodeWhispererConstants.FeatureName.CODE_REVIEW)
throw codeScanServerException("ListCodeReviewFindingsException: $errorMessage")
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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

View workflow job for this annotation

GitHub Actions / qodana

Usage of redundant or deprecated syntax or deprecated symbols

Remove deprecated symbol import

Check warning

Code scanning / QDJVMC

Usage of redundant or deprecated syntax or deprecated symbols Warning

Remove deprecated symbol import

open class CodeTestException(
override val message: String?,
val code: String? = "DefaultError",
val uiMessage: String? = message(

Check warning on line 11 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codetest/CodeTestException.kt

View workflow job for this annotation

GitHub Actions / qodana

Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

Check warning

Code 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
"testgen.error.generic_error_message"
),
) : RuntimeException()

internal fun noFileOpenError(): Nothing =
throw CodeTestException(message("codewhisperer.codescan.no_file_open"), "ProjectZipError")

Check warning

Code 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 fileTooLarge(): Nothing =
throw CodeTestException(message("codewhisperer.codescan.file_too_large_telemetry"), "ProjectZipError")

Check warning on line 20 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codetest/CodeTestException.kt

View workflow job for this annotation

GitHub Actions / qodana

Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

Check warning

Code 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 cannotFindFile(errorMessage: String, filepath: String): Nothing =
error(message("codewhisperer.codescan.file_not_found", filepath, errorMessage))

Check warning on line 23 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codetest/CodeTestException.kt

View workflow job for this annotation

GitHub Actions / qodana

Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

Check warning

Code 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, "ProjectZipError")

internal fun cannotFindBuildArtifacts(errorMessage: String): Nothing =
throw CodeTestException(errorMessage, "ProjectZipError")

internal fun invalidSourceZipError(): Nothing =
throw CodeTestException(message("codewhisperer.codescan.invalid_source_zip_telemetry"), "InvalidSourceZipError")

Check warning on line 32 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codetest/CodeTestException.kt

View workflow job for this annotation

GitHub Actions / qodana

Usage of redundant or deprecated syntax or deprecated symbols

'message(String, vararg Any): String' is deprecated. Use extension-specific localization bundle instead

Check warning

Code 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

fun testGenStoppedError(): Nothing =
throw CodeTestException(message("testgen.message.cancelled"), "TestGenCancelled", message("testgen.message.cancelled"))

Check warning

Code 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

Check warning

Code 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
Loading
Loading