Skip to content

Commit bc08f99

Browse files
committed
Error handling for UTG
1 parent b733179 commit bc08f99

File tree

13 files changed

+168
-77
lines changed

13 files changed

+168
-77
lines changed

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/CodeWhispererCodeTestSession.kt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@ class CodeWhispererCodeTestSession(val sessionContext: CodeTestSessionContext) {
3434
* Run UTG sessions are follow steps:
3535
* 1. Zipping project
3636
* 2. Creating Upload url & Upload to S3 bucket
37-
* 3. StartTestGeneration API -> Get JobId
38-
* 4. GetTestGeneration API
39-
* 5. ExportResultsArchieve API
4037
*/
4138
suspend fun run(codeTestChatHelper: CodeTestChatHelper, previousIterationContext: PreviousUTGIterationContext?): CodeTestResponseContext {
4239
try {
@@ -94,7 +91,8 @@ class CodeWhispererCodeTestSession(val sessionContext: CodeTestSessionContext) {
9491
sourceZip,
9592
"SourceCode",
9693
CodeWhispererConstants.UploadTaskType.UTG,
97-
taskName
94+
taskName,
95+
CodeWhispererConstants.FeatureName.TEST_GENERATION
9896
)
9997

10098
sourceZipUploadResponse.uploadId()
@@ -113,7 +111,6 @@ class CodeWhispererCodeTestSession(val sessionContext: CodeTestSessionContext) {
113111
sourceZipUploadResponse,
114112
testSummaryMessageId
115113
)
116-
// TODO send telemetry for upload duration
117114

118115
return codeTestResponseContext
119116
} catch (e: Exception) {

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/CodeWhispererUTGChatManager.kt

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import kotlinx.coroutines.CoroutineScope
1616
import kotlinx.coroutines.Job
1717
import kotlinx.coroutines.delay
1818
import kotlinx.coroutines.launch
19-
import software.amazon.awssdk.services.codewhispererruntime.model.CodeWhispererRuntimeException
2019
import software.amazon.awssdk.services.codewhispererruntime.model.GetTestGenerationResponse
2120
import software.amazon.awssdk.services.codewhispererruntime.model.Range
2221
import software.amazon.awssdk.services.codewhispererruntime.model.StartTestGenerationResponse
@@ -38,9 +37,14 @@ import software.aws.toolkits.jetbrains.services.amazonqCodeTest.session.BuildAnd
3837
import software.aws.toolkits.jetbrains.services.amazonqCodeTest.session.Session
3938
import software.aws.toolkits.jetbrains.services.amazonqCodeTest.utils.combineBuildAndExecuteLogFiles
4039
import software.aws.toolkits.jetbrains.services.codemodernizer.utils.calculateTotalLatency
40+
import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.CodeTestException
41+
import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.codeTestServerException
4142
import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.sessionconfig.CodeTestSessionConfig
43+
import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.testGenStoppedError
4244
import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererClientAdaptor
45+
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants
4346
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererUtil.promptReAuth
47+
import software.aws.toolkits.jetbrains.services.codewhisperer.util.getTelemetryErrorMessage
4448
import software.aws.toolkits.jetbrains.services.cwc.controller.chat.telemetry.getStartUrl
4549
import software.aws.toolkits.jetbrains.services.cwc.messages.ChatMessageType
4650
import software.aws.toolkits.jetbrains.services.cwc.messages.CodeReference
@@ -67,7 +71,7 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
6771

6872
private fun throwIfCancelled(session: Session) {
6973
if (!session.isGeneratingTests) {
70-
error(message("testgen.message.cancelled"))
74+
throw testGenStoppedError()
7175
}
7276
}
7377

@@ -104,24 +108,37 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
104108
}
105109

106110
// 2nd API call: StartTestGeneration
107-
val startTestGenerationResponse = startTestGeneration(
108-
uploadId = createUploadUrlResponse.uploadId(),
109-
targetCode = listOf(
110-
TargetCode.builder()
111-
.relativeTargetPath(codeTestResponseContext.currentFileRelativePath.toString())
112-
.targetLineRangeList(
113-
if (selectionRange != null) {
114-
listOf(
115-
selectionRange
116-
)
117-
} else {
118-
emptyList()
119-
}
120-
)
121-
.build()
122-
),
123-
userInput = prompt
124-
)
111+
val startTestGenerationResponse = try {
112+
startTestGeneration(
113+
uploadId = createUploadUrlResponse.uploadId(),
114+
targetCode = listOf(
115+
TargetCode.builder()
116+
.relativeTargetPath(codeTestResponseContext.currentFileRelativePath.toString())
117+
.targetLineRangeList(
118+
if (selectionRange != null) {
119+
listOf(
120+
selectionRange
121+
)
122+
} else {
123+
emptyList()
124+
}
125+
)
126+
.build()
127+
),
128+
userInput = prompt
129+
)
130+
} catch (e: Exception) {
131+
LOG.error(e) { "Failed to create test generation job" }
132+
// TODO: Not able to emit e.statusCode directly as statusCode is private property
133+
// Cannot access 'statusCode': it is invisible (private in a supertype) in 'ThrottlingException'
134+
val errorMessage = getTelemetryErrorMessage(e, CodeWhispererConstants.FeatureName.TEST_GENERATION)
135+
throw codeTestServerException(
136+
"CreateTestJobError: $errorMessage",
137+
"400",
138+
"CreateTestJobError",
139+
message("testgen.error.generic_technical_error_message")
140+
)
141+
}
125142

126143
val job = startTestGenerationResponse.testGenerationJob()
127144
session.startTestGenerationRequestId = startTestGenerationResponse.responseMetadata().requestId()
@@ -173,7 +190,13 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
173190
}
174191
// update test summary card
175192
} else {
176-
throw Exception(message("testgen.message.failed"))
193+
// If job status is Completed and has no ShortAnswer then there might be some issue in the backend.
194+
throw codeTestServerException(
195+
"TestGenFailedError: " + message("testgen.message.failed"),
196+
"500",
197+
"TestGenFailedError",
198+
message("testgen.error.generic_technical_error_message")
199+
)
177200
}
178201
} else if (status == TestGenerationJobStatus.FAILED) {
179202
LOG.debug {
@@ -184,11 +207,17 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
184207
shortAnswer = parseShortAnswerString(testGenerationResponse.testGenerationJob().shortAnswer())
185208
if (shortAnswer.stopIteration == "true") {
186209
throw Exception("${shortAnswer.planSummary}")
210+
throw codeTestServerException("TestGenFailedError: ${shortAnswer.planSummary}", "400", "TestGenFailedError", shortAnswer.planSummary)
187211
}
188212
}
189213

190-
// TODO: Modify text according to FnF
191-
throw Exception(message("testgen.message.failed"))
214+
// If job status is Failed and has no ShortAnswer then there might be some issue in the backend.
215+
throw codeTestServerException(
216+
"TestGenFailedError: " + message("testgen.message.failed"),
217+
"500",
218+
"TestGenFailedError",
219+
message("testgen.error.generic_technical_error_message")
220+
)
192221
} else {
193222
// In progress
194223
LOG.debug {
@@ -200,7 +229,7 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
200229
if (previousIterationContext == null && testGenerationResponse.testGenerationJob().shortAnswer() != null) {
201230
shortAnswer = parseShortAnswerString(testGenerationResponse.testGenerationJob().shortAnswer())
202231
if (shortAnswer.stopIteration == "true") {
203-
throw Exception("${shortAnswer.planSummary}")
232+
throw codeTestServerException("TestGenFailedError: ${shortAnswer.planSummary}", "400", "TestGenFailedError", shortAnswer.planSummary)
204233
}
205234
codeTestChatHelper.updateAnswer(
206235
CodeTestChatMessageContent(
@@ -232,6 +261,12 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
232261
},
233262
{ e ->
234263
LOG.error(e) { "ExportResultArchive failed: ${e.message}" }
264+
throw codeTestServerException(
265+
"ExportResultsArchiveError: ${e.message}",
266+
"500",
267+
"ExportResultsArchiveError",
268+
message("testgen.error.generic_technical_error_message")
269+
)
235270
},
236271
{ startTime ->
237272
LOG.info { "ExportResultArchive latency: ${calculateTotalLatency(startTime, Instant.now())}" }
@@ -495,10 +530,18 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
495530
// Add an answer for displaying error message
496531
var errorMessage = e.message
497532
if (e is JsonParseException) {
498-
errorMessage = message("testgen.error.generic_error_message")
533+
errorMessage = message("testgen.error.generic_technical_error_message")
534+
}
535+
if (e is CodeTestException) {
536+
errorMessage = e.uiMessage
499537
}
500538

501-
if (e is CodeWhispererRuntimeException) {
539+
if (e is CodeTestException && e.statusCode == "400" &&
540+
e.message?.startsWith(
541+
"CreateTestJobError: Maximum com.amazon.aws.codewhisperer.runtime.StartTestGeneration " +
542+
"reached for this month."
543+
) != false
544+
) {
502545
errorMessage = message("testgen.error.maximum_generations_reach")
503546
}
504547
codeTestChatHelper.addAnswer(
@@ -517,8 +560,9 @@ class CodeWhispererUTGChatManager(val project: Project, private val cs: Coroutin
517560
jobGroup = session.testGenerationJobGroupName,
518561
jobId = session.testGenerationJob,
519562
result = if (e.message == message("testgen.message.cancelled")) MetricResult.Cancelled else MetricResult.Failed,
520-
reason = e.javaClass.name,
521-
reasonDesc = e.message,
563+
reason = (e as CodeTestException).code ?: "DefaultError",
564+
reasonDesc = if (e.message == message("testgen.message.cancelled")) "${e.code}: ${e.message}" else e.message,
565+
httpStatusCode = e.statusCode ?: "400",
522566
perfClientLatency = (Instant.now().toEpochMilli() - session.startTimeOfTestGeneration),
523567
isCodeBlockSelected = session.isCodeBlockSelected,
524568
artifactsUploadDuration = session.artifactUploadDuration,

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqCodeTest/controller/CodeTestChatController.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@ class CodeTestChatController(
291291
credentialStartUrl = getStartUrl(project),
292292
result = MetricResult.Succeeded,
293293
perfClientLatency = (Instant.now().toEpochMilli() - session.startTimeOfTestGeneration),
294-
requestId = id
294+
requestId = id,
295+
httpStatusCode = "200"
295296
)
296297
}
297298
session.isGeneratingTests = false

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/AmazonQCodeFixSession.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ class AmazonQCodeFixSession(val project: Project) {
7272
sourceZip,
7373
"SourceCode",
7474
CodeWhispererConstants.UploadTaskType.CODE_FIX,
75-
codeFixName
75+
codeFixName,
76+
CodeWhispererConstants.FeatureName.CODE_REVIEW
7677
)
7778

7879
/**
@@ -149,7 +150,7 @@ class AmazonQCodeFixSession(val project: Project) {
149150
)
150151
} catch (e: Exception) {
151152
LOG.debug { "Create Upload URL failed: ${e.message}" }
152-
val errorMessage = getTelemetryErrorMessage(e)
153+
val errorMessage = getTelemetryErrorMessage(e, featureUseCase = CodeWhispererConstants.FeatureName.CODE_REVIEW)
153154
throw codeScanServerException("CreateUploadUrlException: $errorMessage")
154155
}
155156

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codescan/CodeWhispererCodeScanSession.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
117117
sourceZip,
118118
"SourceCode",
119119
taskType,
120-
codeScanName
120+
codeScanName,
121+
CodeWhispererConstants.FeatureName.CODE_REVIEW
121122
)
122123
if (isProjectScope()) {
123124
LOG.debug {
@@ -272,7 +273,7 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
272273
)
273274
} catch (e: Exception) {
274275
LOG.debug { "Creating code review failed: ${e.message}" }
275-
val errorMessage = getTelemetryErrorMessage(e)
276+
val errorMessage = getTelemetryErrorMessage(e, featureUseCase = CodeWhispererConstants.FeatureName.CODE_REVIEW)
276277
throw codeScanServerException(errorMessage)
277278
}
278279
}
@@ -285,7 +286,7 @@ class CodeWhispererCodeScanSession(val sessionContext: CodeScanSessionContext) {
285286
)
286287
} catch (e: Exception) {
287288
LOG.debug { "Getting code review failed: ${e.message}" }
288-
val errorMessage = getTelemetryErrorMessage(e)
289+
val errorMessage = getTelemetryErrorMessage(e, featureUseCase = CodeWhispererConstants.FeatureName.CODE_REVIEW)
289290
throw codeScanServerException("GetCodeReviewException: $errorMessage")
290291
}
291292

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

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codetest/sessionconfig/CodeTestException.kt

Lines changed: 0 additions & 2 deletions
This file was deleted.

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/codetest/sessionconfig/CodeTestSessionConfig.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ import software.aws.toolkits.core.utils.debug
1919
import software.aws.toolkits.core.utils.getLogger
2020
import software.aws.toolkits.core.utils.putNextEntry
2121
import software.aws.toolkits.jetbrains.services.amazonq.FeatureDevSessionContext
22-
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.cannotFindBuildArtifacts
23-
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.cannotFindFile
24-
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.fileTooLarge
25-
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.noFileOpenError
2622
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.sessionconfig.Payload
2723
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.sessionconfig.PayloadContext
2824
import software.aws.toolkits.jetbrains.services.codewhisperer.codescan.sessionconfig.PayloadMetadata
25+
import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.cannotFindBuildArtifacts
26+
import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.cannotFindFile
27+
import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.fileTooLarge
28+
import software.aws.toolkits.jetbrains.services.codewhisperer.codetest.noFileOpenError
2929
import software.aws.toolkits.jetbrains.services.codewhisperer.language.CodeWhispererProgrammingLanguage
3030
import software.aws.toolkits.jetbrains.services.codewhisperer.language.languages.CodeWhispererUnknownLanguage
3131
import software.aws.toolkits.jetbrains.services.codewhisperer.language.programmingLanguage
@@ -94,7 +94,7 @@ class CodeTestSessionConfig(
9494
else -> e.message
9595
}
9696
LOG.debug { "Error creating payload metadata: $errorMessage" }
97-
throw cannotFindBuildArtifacts(errorMessage ?: message("codewhisperer.codescan.run_scan_error_telemetry"))
97+
throw cannotFindBuildArtifacts(errorMessage ?: message("testgen.message.failed"))
9898
}
9999

100100
// Copy all the included source files to the source zip

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/util/CodeWhispererConstants.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ object CodeWhispererConstants {
127127
PROJECT("PROJECT"),
128128
}
129129

130+
enum class FeatureName(val value: String) {
131+
TEST_GENERATION("TEST_GENERATION"),
132+
CODE_REVIEW("CODE_REVIEW"),
133+
}
134+
130135
enum class UploadTaskType(val value: String) {
131136
SCAN_FILE("SCAN_FILE"),
132137
SCAN_PROJECT("SCAN_PROJECT"),

0 commit comments

Comments
 (0)