@@ -442,7 +442,7 @@ describe('Controller', () => {
442442 { name : 'default' , error : new ToolkitError ( 'Default' , { code : 'Default' } ) } ,
443443 ]
444444
445- async function fireChatMessage ( ) {
445+ async function fireChatMessage ( session : Session ) {
446446 const getSessionStub = sinon . stub ( controllerSetup . sessionStorage , 'getSession' ) . resolves ( session )
447447
448448 controllerSetup . emitters . processHumanChatMessage . fire ( {
@@ -458,52 +458,104 @@ describe('Controller', () => {
458458 }
459459
460460 describe ( 'onCodeGeneration' , function ( ) {
461+ let session : any
462+ let sendMetricDataTelemetrySpy : sinon . SinonStub
463+
464+ const errorResultMapping = new Map ( [
465+ [ 'EmptyPatchException' , MetricDataResult . LLMFAILURE ] ,
466+ [ PromptRefusalException . name , MetricDataResult . ERROR ] ,
467+ [ NoChangeRequiredException . name , MetricDataResult . ERROR ] ,
468+ ] )
469+
470+ function getMetricResult ( error : ToolkitError ) : MetricDataResult {
471+ if ( error instanceof FeatureDevServiceError && error . code ) {
472+ return errorResultMapping . get ( error . code ) ?? MetricDataResult . ERROR
473+ }
474+ return errorResultMapping . get ( error . constructor . name ) ?? MetricDataResult . FAULT
475+ }
476+
477+ async function createCodeGenState ( ) {
478+ mockGetCodeGeneration = sinon . stub ( ) . resolves ( { codeGenerationStatus : { status : 'Complete' } } )
479+
480+ const workspaceFolders = [ controllerSetup . workspaceFolder ] as CurrentWsFolders
481+ const testConfig = {
482+ conversationId : conversationID ,
483+ proxyClient : {
484+ createConversation : ( ) => sinon . stub ( ) ,
485+ createUploadUrl : ( ) => sinon . stub ( ) ,
486+ generatePlan : ( ) => sinon . stub ( ) ,
487+ startCodeGeneration : ( ) => sinon . stub ( ) ,
488+ getCodeGeneration : ( ) => mockGetCodeGeneration ( ) ,
489+ exportResultArchive : ( ) => sinon . stub ( ) ,
490+ } as unknown as FeatureDevClient ,
491+ workspaceRoots : [ '' ] ,
492+ uploadId : uploadID ,
493+ workspaceFolders,
494+ }
495+
496+ const codeGenState = new CodeGenState ( testConfig , getFilePaths ( controllerSetup ) , [ ] , [ ] , tabID , 0 , { } )
497+ const newSession = await createSession ( {
498+ messenger : controllerSetup . messenger ,
499+ sessionState : codeGenState ,
500+ conversationID,
501+ tabID,
502+ uploadID,
503+ scheme : featureDevScheme ,
504+ } )
505+ return newSession
506+ }
507+
461508 async function verifyException ( error : ToolkitError ) {
462- sinon . stub ( session , 'preloader' ) . resolves ( )
463509 sinon . stub ( session , 'send' ) . throws ( error )
464- const sendMetricDataTelemetrySpy = sinon . stub ( session , 'sendMetricDataTelemetry' )
465-
466- await fireChatMessage ( )
467510
468- sendMetricDataTelemetrySpy . calledWith (
469- MetricDataOperationName . START_CODE_GENERATION ,
470- MetricDataResult . SUCCESS
511+ await fireChatMessage ( session )
512+ await verifyMetricsCalled ( )
513+ assert . ok (
514+ sendMetricDataTelemetrySpy . calledWith (
515+ MetricDataOperationName . START_CODE_GENERATION ,
516+ MetricDataResult . SUCCESS
517+ )
471518 )
519+ const metricResult = getMetricResult ( error )
520+ assert . ok (
521+ sendMetricDataTelemetrySpy . calledWith ( MetricDataOperationName . END_CODE_GENERATION , metricResult )
522+ )
523+ }
472524
473- switch ( error . constructor . name ) {
474- case FeatureDevServiceError . name :
475- if ( error . code === 'EmptyPatchException' ) {
476- sendMetricDataTelemetrySpy . calledWith (
477- MetricDataOperationName . END_CODE_GENERATION ,
478- MetricDataResult . LLMFAILURE
479- )
480- } else {
481- sendMetricDataTelemetrySpy . calledWith (
482- MetricDataOperationName . END_CODE_GENERATION ,
483- MetricDataResult . ERROR
484- )
485- }
486- break
487- case PromptRefusalException . name :
488- case NoChangeRequiredException . name :
489- sendMetricDataTelemetrySpy . calledWith (
490- MetricDataOperationName . END_CODE_GENERATION ,
491- MetricDataResult . ERROR
492- )
493- break
494- default :
495- sendMetricDataTelemetrySpy . calledWith (
496- MetricDataOperationName . END_CODE_GENERATION ,
497- MetricDataResult . FAULT
498- )
499-
500- break
501- }
525+ async function verifyMetricsCalled ( ) {
526+ await waitUntil ( ( ) => Promise . resolve ( sendMetricDataTelemetrySpy . callCount >= 2 ) , { } )
502527 }
503528
504- runs . forEach ( ( run ) => {
505- it ( `sends operation telemetry on ${ run . name } ` , async function ( ) {
506- await verifyException ( run . error )
529+ beforeEach ( async ( ) => {
530+ session = await createCodeGenState ( )
531+ sinon . stub ( session , 'preloader' ) . resolves ( )
532+ sendMetricDataTelemetrySpy = sinon . stub ( session , 'sendMetricDataTelemetry' )
533+ } )
534+
535+ it ( 'sends success operation telemetry' , async ( ) => {
536+ sinon . stub ( session , 'send' ) . resolves ( )
537+ sinon . stub ( session , 'sendLinesOfCodeGeneratedTelemetry' ) . resolves ( ) // Avoid sending extra telemetry
538+
539+ await fireChatMessage ( session )
540+ await verifyMetricsCalled ( )
541+
542+ assert . ok (
543+ sendMetricDataTelemetrySpy . calledWith (
544+ MetricDataOperationName . START_CODE_GENERATION ,
545+ MetricDataResult . SUCCESS
546+ )
547+ )
548+ assert . ok (
549+ sendMetricDataTelemetrySpy . calledWith (
550+ MetricDataOperationName . END_CODE_GENERATION ,
551+ MetricDataResult . SUCCESS
552+ )
553+ )
554+ } )
555+
556+ runs . forEach ( ( { name, error } ) => {
557+ it ( `sends failure operation telemetry on ${ name } ` , async ( ) => {
558+ await verifyException ( error )
507559 } )
508560 } )
509561 } )
@@ -519,7 +571,7 @@ describe('Controller', () => {
519571 const sendErrorMessageSpy = sinon . stub ( controllerSetup . messenger , 'sendErrorMessage' )
520572 const sendMonthlyLimitErrorSpy = sinon . stub ( controllerSetup . messenger , 'sendMonthlyLimitError' )
521573
522- await fireChatMessage ( )
574+ await fireChatMessage ( session )
523575
524576 switch ( error . constructor . name ) {
525577 case ContentLengthError . name :
0 commit comments