Author : Soujanya Akella
The main purpose of this document is to outline the testing strategy used for Performance Testing of BOT in one of the customer engagements.
The Application Under Test is a Mobile App that communicates with BOT which consumes services to call the Knowledge Graph APIs. Load testing was performed at the BOT layer.
Following are the detailed steps involved:
For details to implement the mock channel, please refer to published IP.
2. Send Request from Visual Studio Web Test to BOT.
Request1: POST https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token
In the below request, replace MICROSOFT-APP-ID and MICROSOFT-APP-PASSWORD with the App ID and Password of the BOT (obtained during BOT Registration).
POST https://login.microsoftonline.com/botframework.com/oauth2/v2.0/token
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
Request Body:
grant_type=client_credentials&client_id=MICROSOFT-APP-ID&client_secret=MICROSOFT-APP-PASSWORD&scope=MICROSOFT-APP-ID/.default
Successful request returns a JSON payload with access_token.
Request2: POST https://{{BotEndPoint}}/api/messages
Create HTTP POST to BOT’s endpoint URL that includes Authorization header where the access_token retrieved in above step is passed.
Requests sent to BOT Endpoint https://{{BotEndPoint}}/api/messages include:
POST api/messages
Authorization: Bearer
Content-Type: application/json
{ "Type": "message", "Id": "{{ActivityID}}" "ChannelId": "test", "Conversation": { "id": "{{ConversationID}}" }, "From": { "id": "1" }, "Recipient": { "id": "2" }, "ServiceUrl": "https://{{mockchannel}}.azurewebsites.net", "Text": “{Message Sent}"
3. Save the above request body along with request timestamp to the same Storage table account created in Step 1. with ConvID(guid) and ActivityID(guid) as the PartitionKey and RowKey.
Code for design of Storage Table, generation of request body for api/messages and save the request to Storage Table.
public class ActivityTableEntity : TableEntity { public ActivityTableEntity() { } public ActivityTableEntity(string convId) { this.PartitionKey = convId; } public ActivityTableEntity(string convId, string activityId) { this.PartitionKey = convId; this.RowKey = activityId; } public string activityMsg; public string scenarioName { get; set; } public string incomingAcvitityMsg { get; set; } public string botResponseMsg { get; set; } public DateTime requestTimeStamp { get; set; } public string responseTimeStamp { get; set; } }
public class SaveRequest : WebTestPlugin { private static CloudStorageAccount account = default(CloudStorageAccount); private static CloudTableClient tableClient; private static CloudTable botOperationLogTable; public string azureStorageAccount = HelperMethods.GetAppConfigValues("azureStorageAccount"); public string azureStorageSecret = HelperMethods.GetAppConfigValues("azureStorageSecret"); public string TableName = HelperMethods.GetAppConfigValues("tableName"); ActivityTableEntity activityTableEntity; private string postData = string.Empty; private string Text = string.Empty; private string AuthToken = string.Empty; private Guid guid = Guid.NewGuid(); private string Id = string.Empty; public override void PreWebTest(object sender, PreWebTestEventArgs e) { if (!string.IsNullOrEmpty(azureStorageAccount) && !string.IsNullOrEmpty(azureStorageSecret)) { account = new CloudStorageAccount(new StorageCredentials(azureStorageAccount, azureStorageSecret), true); tableClient = account.CreateCloudTableClient(); botOperationLogTable = tableClient.GetTableReference(TableName); botOperationLogTable.CreateIfNotExistsAsync(); } } /* ToDo Include a check for the request to match with api/messages in order to create the request body only for that request */ public override void PreRequestDataBinding(object sender, PreRequestDataBindingEventArgs e) { // Generation of request body Id = e.WebTest.Context["ActivityID"].ToString(); postData = @"{ ""Type"":""message"", ""Id"":""" + Id + @""", ""ChannelId"":""test"", ""Conversation"":{ ""id"":""" + e.WebTest.Context["ConvID"].ToString() + @""" }, ""From"":{ ""id"":""1"" }, ""Recipient"":{ ""id"":""2"" }, ""ServiceUrl"":""" + e.WebTest.Context["BotConnectorBaseUrl"].ToString() + @""", ""Text"" : ""{\""Query\"":\""" + @"\""}"" }"; e.WebTest.Context.Add("postData", postData); activityTableEntity = new ActivityTableEntity(e.WebTest.Context["ConvID"].ToString(),Id); activityTableEntity.incomingAcvitityMsg = postData; activityTableEntity.requestTimeStamp = DateTime.UtcNow; activityTableEntity.scenarioName = "WebTest1"; } /* ToDo Include a check for request to match with api/messages in order to save only for that request */ public override void PostRequest(object sender, PostRequestEventArgs e) { // Save the request details to table storage TableOperation tableOperation = TableOperation.Insert(activityTableEntity); botOperationLogTable.Execute(tableOperation); } }
4. Calculation of response timestamp: Since both request timestamp -requestTimeStamp (from web test) and response timestamp-responseTimeStamp(from mock channel ) are captured in Storage Table, the difference in columns gives the response times.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.