Path: blob/main/extensions/copilot/src/extension/conversation/vscode-node/test/interactiveSessionProvider.telemetry.test.ts
13405 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import assert from 'assert';6import * as vscode from 'vscode';7import { ICopilotTokenManager } from '../../../../platform/authentication/common/copilotTokenManager';8import { SimulationTestCopilotTokenManager } from '../../../../platform/authentication/test/node/simulationTestCopilotTokenManager';9import { allEvents, withTelemetryCapture } from '../../../../platform/test/node/telemetry';10import { SpyChatResponseStream } from '../../../../util/common/test/mockChatResponseStream';11import { SyncDescriptor } from '../../../../util/vs/platform/instantiation/common/descriptors';12import { IInstantiationService } from '../../../../util/vs/platform/instantiation/common/instantiation';13import { ChatParticipantRequestHandler } from '../../../prompt/node/chatParticipantRequestHandler';14import { TestChatRequest } from '../../../test/node/testHelpers';15import { createExtensionTestingServices } from '../../../test/vscode-node/services';161718suite('Conversation telemetry tests - Integration tests', function () {19this.timeout(10000);2021test.skip('Telemetry for user message', async function () {22const testingServiceCollection = createExtensionTestingServices();23testingServiceCollection.define(ICopilotTokenManager, new SyncDescriptor(SimulationTestCopilotTokenManager));24const messageText = 'Write me a function that returns the square root of a number.';2526const [messages] = await withTelemetryCapture(testingServiceCollection, async (accessor) => {27const token = new vscode.CancellationTokenSource().token;28const request: vscode.ChatRequest = new TestChatRequest(messageText);29const stream = new SpyChatResponseStream();30const instantiationService = accessor.get(IInstantiationService);31const session = instantiationService.createInstance(ChatParticipantRequestHandler,32[],33request,34stream,35token,36{ agentName: '', agentId: '' },37() => false,38undefined);39await session.getResult(); // and throw away the result40});41assert.ok(allEvents(messages));42const names = messages43.map(message => message.data.baseData.name.split('/')[1])44// in case we need a new Copilot token, we don't care about the messages that triggers45.filter(name => !['auth.new_login', 'auth.new_token'].includes(name));4647// Check client telemetry events48orderMatches(49[50'conversation.message',51'conversation.messageText',52'request.sent',53'request.response',54'engine.messages',55'engine.messages.length',56'model.request.added',57'model.message.added',58'model.modelCall.input',59'model.request.options.added',60'request.shownWarning',61].sort(),62names.filter(name => name !== 'log').sort()63);6465// Check there exists a conversation.message event for the user with the correct properties and measurements66const userMessage = messages.find(67message =>68message.data.baseData.name.split('/')[1] === 'conversation.message' &&69message.data.baseData.properties.source === 'user'70);71const userMessageId = userMessage?.data.baseData.properties.messageId;72// conversation.message event exists73assert.ok(userMessage, 'conversation.message event for user message does not exist');74// Turn index is 0 because this is the first message in the conversation75assert.ok(76userMessage.data.baseData.properties.turnIndex === '0',77'conversation.message event for user message has turn index != 0'78);79// Message length equals the length of the message text80assert.ok(81userMessage.data.baseData.measurements.messageCharLen === messageText.length,82'conversation.message event for user message has incorrect message length'83);84// Check there exists a conversation.messageText event for the user with the correct properties and measurements85const userMessageText = messages.find(86message =>87message.data.baseData.name.split('/')[1] === 'conversation.messageText' &&88message.data.baseData.properties.messageId === userMessageId89);90// conversation.messageText event exists with matching messageId91assert.ok(userMessageText, 'conversation.messageText event for user message does not exist');92assert.ok(93userMessageText.data.baseData.properties.messageText === messageText,94'conversation.messageText event for user message has incorrect message text'95);9697// Check there exists a request.sent event with matching messageId98const userMessageRequest = messages.find(99message =>100message.data.baseData.name.split('/')[1] === 'request.sent' &&101message.data.baseData.properties.messageId === userMessageId102);103// request.sent event exists with matching messageId104assert.ok(userMessageRequest, 'request.sent event for user message does not exist');105106// Check there exists a request.response event with matching messageId107const userMessageResponse = messages.find(108message =>109message.data.baseData.name.split('/')[1] === 'request.response' &&110message.data.baseData.properties.messageId === userMessageId111);112// request.sent event exists with matching messageId113assert.ok(userMessageResponse, 'request.response event for user message does not exist');114115// Check there exists a engine.messages event with matching messageId116const userMessageEngine = messages.find(117message =>118message.data.baseData.name.split('/')[1] === 'engine.messages' &&119message.data.baseData.properties.messageId === userMessageId120);121// engine.messages event exists with matching messageId122assert.ok(userMessageEngine, 'engine.messages event for user message does not exist');123// Check that the engine.messages event has a messagesJson property with length greater than or equal to message124assert.ok(125userMessageEngine.data.baseData.properties.messagesJson.length >= messageText.length,126'engine.messages event for user message has messagesJson property with length < message length'127);128129// Check there exists a engine.messages.length event with matching messageId130const userMessageEngineLength = messages.find(131message =>132message.data.baseData.name.split('/')[1] === 'engine.messages.length' &&133message.data.baseData.properties.messageId === userMessageId134);135assert.ok(userMessageEngineLength, 'engine.messages.length event for user message does not exist');136137// Check there exists a model.request.added event with matching headerRequestId138const modelRequestAdded = messages.find(139message =>140message.data.baseData.name.split('/')[1] === 'model.request.added' &&141message.data.baseData.properties.headerRequestId142);143assert.ok(modelRequestAdded, 'model.request.added event for user message does not exist');144145// Check there exists a model.message.added event with messageUuid146const modelMessageAdded = messages.find(147message =>148message.data.baseData.name.split('/')[1] === 'model.message.added' &&149message.data.baseData.properties.messageUuid150);151assert.ok(modelMessageAdded, 'model.message.added event for user message does not exist');152153// Check there exists a model.modelCall.input event with modelCallId154const modelCallInput = messages.find(155message =>156message.data.baseData.name.split('/')[1] === 'model.modelCall.input' &&157message.data.baseData.properties.modelCallId158);159assert.ok(modelCallInput, 'model.modelCall.input event for user message does not exist');160161// Check there exists a model.request.options.added event with requestOptionsId162const modelRequestOptionsAdded = messages.find(163message =>164message.data.baseData.name.split('/')[1] === 'model.request.options.added' &&165message.data.baseData.properties.requestOptionsId166);167assert.ok(modelRequestOptionsAdded, 'model.request.options.added event for user message does not exist');168});169});170171function orderMatches(list1: string[], list2: string[]) {172const filteredList2 = list2.filter(el => list1.includes(el));173const result = list1.every((el, index) => el === filteredList2[index]);174assert.ok(result, `Expected members\n[${list2.join(', ')}]\nto be in order\n[${list1.join(', ')}].`);175}176177178